Skip to content

Commit 77ba378

Browse files
committed
docs: add docs for swift
1 parent 440164d commit 77ba378

File tree

3 files changed

+198
-0
lines changed

3 files changed

+198
-0
lines changed

docs/pages/create.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,5 @@ Once the project is created, you can follow the official React Native docs to le
9393
- [Native UI Components for iOS](https://reactnative.dev/docs/legacy/native-components-ios)
9494
- [Turbo Modules](https://reactnative.dev/docs/turbo-native-modules-introduction)
9595
- [Fabric Components](https://reactnative.dev/docs/fabric-native-components-introduction)
96+
97+
Turbo Modules and Fabric components don't have native support for Swift. If you want to write the iOS implementation in Swift for a Turbo Module or Fabric View, see [Swift with Turbo Modules and Fabric](./swift-new-architecture.md).
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
---
2+
title: Swift with Turbo Modules and Fabric
3+
---
4+
5+
For Turbo Modules and Fabric views, React Native expects the iOS entry point to stay in Objective-C. If you want to use Swift, you need to create a separate Swift class for the implementation and update our Objective-C code to act as a thin wrapper that forwards calls to the Swift implementation.
6+
7+
## Calling Swift from Objective-C
8+
9+
Swift can be called from Objective-C as long as the API is Objective-C compatible:
10+
11+
- Mark the class or exposed methods with `@objc`
12+
- Inherit from `NSObject` or `UIView`
13+
- Use types that Objective-C can bridge, such as `String`, `NSNumber`, `NSArray`, `NSDictionary`, and `UIColor`
14+
15+
The Objective-C wrapper also needs to import the generated Swift compatibility header, which is usually named `"<YourProjectName>-Swift.h"`:
16+
17+
```objc
18+
#if __has_include("<YourProjectName>/<YourProjectName>-Swift.h")
19+
#import "<YourProjectName>/<YourProjectName>-Swift.h"
20+
#else
21+
#import "<YourProjectName>-Swift.h"
22+
#endif
23+
```
24+
25+
The `#if __has_include` check is necessary to make the code work with `use_frameworks!` in the `Podfile`, which changes the import path for the generated header.
26+
27+
## Turbo Modules
28+
29+
To use Swift for a Turbo Module, you can create a Swift class (e.g. `<YourProjectName>Impl`) that contains the actual implementation of your module's methods. Then, update the Objective-C code (`<YourProjectName>.mm`) to use that Swift class.
30+
31+
Example Swift implementation for a simple Turbo Module that multiplies two numbers:
32+
33+
```swift
34+
import Foundation
35+
@objc(<YourProjectName>Impl)
36+
final class <YourProjectName>Impl: NSObject {
37+
@objc
38+
func multiply(_ a: Double, b: Double) -> NSNumber {
39+
NSNumber(value: a * b)
40+
}
41+
}
42+
```
43+
44+
Then call this implementation from the Objective-C wrapper:
45+
46+
```objc
47+
#import "<YourProjectName>.h"
48+
49+
// Add the import for the generated Swift header
50+
// [!code highlight:5]
51+
#if __has_include("<YourProjectName>/<YourProjectName>-Swift.h")
52+
#import "<YourProjectName>/<YourProjectName>-Swift.h"
53+
#else
54+
#import "<YourProjectName>-Swift.h"
55+
#endif
56+
57+
// Declare a private property for the Swift implementation
58+
// [!code highlight:3]
59+
@implementation <YourProjectName> {
60+
<YourProjectName>Impl *_impl;
61+
}
62+
63+
// Initialize the Swift class on module creation
64+
// [!code highlight:8]
65+
- (instancetype)init
66+
{
67+
if (self = [super init]) {
68+
_impl = [<YourProjectName>Impl new];
69+
}
70+
return self;
71+
}
72+
73+
// Call the Swift implementation for the actual implementation
74+
// [!code highlight:4]
75+
- (NSNumber *)multiply:(double)a b:(double)b
76+
{
77+
return [_impl multiply:a b:b];
78+
}
79+
80+
// Keep rest of the boilerplate for module registration
81+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
82+
(const facebook::react::ObjCTurboModule::InitParams &)params
83+
{
84+
return std::make_shared<facebook::react::Native<YourProjectName>SpecJSI>(params);
85+
}
86+
87+
+ (NSString *)moduleName
88+
{
89+
return @"<YourProjectName>";
90+
}
91+
92+
@end
93+
```
94+
95+
## Fabric Views
96+
97+
To use Swift for a Fabric view, you can create a Swift `UIView` subclass (e.g. `<YourProjectName>ViewImpl`) that contains the actual implementation of your view. Then, update the generated Objective-C code (`<YourProjectName>View.mm`) to use that Swift view.
98+
99+
Example Swift implementation for a simple Fabric view that applies the default `color` prop:
100+
101+
```swift
102+
import UIKit
103+
104+
@objc(<YourProjectName>ViewImpl)
105+
final class <YourProjectName>ViewImpl: UIView {
106+
@objc
107+
func setColor(_ color: UIColor?) {
108+
backgroundColor = color
109+
}
110+
}
111+
```
112+
113+
Then call this implementation from the generated Objective-C++ wrapper:
114+
115+
```objc
116+
#import "<YourProjectName>View.h"
117+
118+
// Add the import for the generated Swift header
119+
// [!code highlight:5]
120+
#if __has_include("<YourProjectName>/<YourProjectName>-Swift.h")
121+
#import "<YourProjectName>/<YourProjectName>-Swift.h"
122+
#else
123+
#import "<YourProjectName>-Swift.h"
124+
#endif
125+
126+
#import <React/RCTConversions.h>
127+
128+
#import <react/renderer/components/<YourProjectName>ViewSpec/ComponentDescriptors.h>
129+
#import <react/renderer/components/<YourProjectName>ViewSpec/Props.h>
130+
#import <react/renderer/components/<YourProjectName>ViewSpec/RCTComponentViewHelpers.h>
131+
132+
#import "RCTFabricComponentsPlugins.h"
133+
134+
using namespace facebook::react;
135+
136+
// Declare a private property for the Swift view
137+
// [!code highlight:3]
138+
@implementation <YourProjectName>View {
139+
<YourProjectName>ViewImpl *_view;
140+
}
141+
142+
// Keep the boilerplate for Fabric registration
143+
// [!code highlight:4]
144+
+ (ComponentDescriptorProvider)componentDescriptorProvider
145+
{
146+
return concreteComponentDescriptorProvider<<YourProjectName>ViewComponentDescriptor>();
147+
}
148+
149+
- (instancetype)initWithFrame:(CGRect)frame
150+
{
151+
if (self = [super initWithFrame:frame]) {
152+
static const auto defaultProps =
153+
std::make_shared<const <YourProjectName>ViewProps>();
154+
_props = defaultProps;
155+
156+
// Initialize the Swift view when the Fabric view is created
157+
_view = [<YourProjectName>ViewImpl new]; // [!code highlight]
158+
159+
self.contentView = _view;
160+
}
161+
162+
return self;
163+
}
164+
165+
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
166+
{
167+
const auto &oldViewProps =
168+
*std::static_pointer_cast<<YourProjectName>ViewProps const>(_props);
169+
const auto &newViewProps =
170+
*std::static_pointer_cast<<YourProjectName>ViewProps const>(props);
171+
172+
if (oldViewProps.color != newViewProps.color) {
173+
// Call methods on the Swift view when props are updated
174+
// It may be necessary to convert some types before passing them to Swift
175+
[_view setColor:RCTUIColorFromSharedColor(newViewProps.color)]; // [!code highlight]
176+
}
177+
178+
[super updateProps:props oldProps:oldProps];
179+
}
180+
181+
@end
182+
```
183+
184+
## Notes
185+
186+
If Xcode does not pick up a new Swift file immediately, rerun `pod install` in `example/ios` and restart Xcode.

docs/rspress.config.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { defineConfig } from '@rspress/core';
22
import { withCallstackPreset } from '@callstack/rspress-preset';
3+
import { transformerNotationHighlight } from '@shikijs/transformers';
34

45
export default withCallstackPreset(
56
{
@@ -28,10 +29,19 @@ export default withCallstackPreset(
2829
{ text: 'Scaffold a library', link: '/create' },
2930
{ text: 'Build a library', link: '/build' },
3031
{ text: 'ESM support', link: '/esm' },
32+
{
33+
text: 'Swift with Turbo Modules and Fabric',
34+
link: '/swift-new-architecture',
35+
},
3136
{ text: 'FAQ', link: '/faq' },
3237
],
3338
},
3439
},
40+
markdown: {
41+
shiki: {
42+
transformers: [transformerNotationHighlight()],
43+
},
44+
},
3545
base: '/react-native-builder-bob/',
3646
})
3747
);

0 commit comments

Comments
 (0)