RNNewArchitectureApp
RNNewArchitectureApp copied to clipboard
How to use view created in swift inside an objective-c++ file?
I am trying to use react-native's
new architecture and I have enabled fabric
for the same. I am able to use a view
created in objective-c++
inside my typescript
code. But I want to use a view created in swift
with UIKit
in my objective-c++
file
The documentation on react-native's
website is still for the old architecture of using bridge so it does not directly apply in my case. There are pretty significant changes in the new architecture.
Below is the working code for objective-c++
file
#import <Foundation/Foundation.h>
#import "RNThubView.h"
#import <react/renderer/components/RNThubViewSpec/ComponentDescriptors.h>
#import <react/renderer/components/RNThubViewSpec/EventEmitters.h>
#import <react/renderer/components/RNThubViewSpec/Props.h>
#import <react/renderer/components/RNThubViewSpec/RCTComponentViewHelpers.h>
#import "RCTFabric/React-RCTFabric-umbrella.h"
using namespace facebook::react;
@interface RNThubView () <RCTThubViewViewProtocol>
@end
@implementation RNThubView {
UIView *_view;
UILabel *_label;
}
+ (ComponentDescriptorProvider)componentDescriptorProvider
{
return concreteComponentDescriptorProvider<ThubViewComponentDescriptor>();
}
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
static const auto defaultProps = std::make_shared<const ThubViewProps>();
_props = defaultProps;
_rnThubView = [[RNThubView alloc] init];
_view = [[UIView alloc] init];
_label = [[UILabel alloc] init];
_label.text = @"Initial value";
[_view addSubview:_label];
_label.translatesAutoresizingMaskIntoConstraints = false;
[NSLayoutConstraint activateConstraints:@[
[_label.leadingAnchor constraintEqualToAnchor:_view.leadingAnchor],
[_label.topAnchor constraintEqualToAnchor:_view.topAnchor],
[_label.trailingAnchor constraintEqualToAnchor:_view.trailingAnchor],
[_label.bottomAnchor constraintEqualToAnchor:_view.bottomAnchor],
]];
_label.textAlignment = NSTextAlignmentCenter;
self.contentView = _view;
}
return self;
}
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
{
const auto &oldViewProps = *std::static_pointer_cast<ThubViewProps const>(_props);
const auto &newViewProps = *std::static_pointer_cast<ThubViewProps const>(props);
if (oldViewProps.color != newViewProps.color) {
// NSString * colorToConvert = [[NSString alloc] initWithUTF8String: newViewProps.color.c_str()];
// [_view setBackgroundColor:[self hexStringToColor:colorToConvert]];
// _view.backgroundColor = [UIColor redColor];
}
[super updateProps:props oldProps:oldProps];
}
Class<RCTComponentViewProtocol> ThubViewCls(void)
{
return RNThubView.class;
}
- hexStringToColor:(NSString *)stringToConvert
{
NSString *noHashString = [stringToConvert stringByReplacingOccurrencesOfString:@"#" withString:@""];
NSScanner *stringScanner = [NSScanner scannerWithString:noHashString];
unsigned hex;
if (![stringScanner scanHexInt:&hex]) return nil;
int r = (hex >> 16) & 0xFF;
int g = (hex >> 8) & 0xFF;
int b = (hex) & 0xFF;
return [UIColor colorWithRed:r / 255.0f green:g / 255.0f blue:b / 255.0f alpha:1.0f];
}
@end
Now to use a view which is created in swift inside my objective-c++ file, I use the following approach
Created a swift file called RNThubView. Following is the code for the same
@objcMembers class RNThubView: UIView {
let btnLogin:UIButton = {
let btn = UIButton(type:.system)
btn.backgroundColor = .blue
btn.setTitle("Login", for: .normal)
btn.tintColor = .white
btn.layer.cornerRadius = 5
btn.clipsToBounds = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(btnLogin)
addConstraintsToButtonLogin()
}
func addConstraintsToButtonLogin(){
btnLogin.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
btnLogin.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
btnLogin.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
btnLogin.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
}
}
And I updated my objective-c++ file code to the following
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
static const auto defaultProps = std::make_shared<const ThubViewProps>();
_props = defaultProps;
_rnThubView = [[RNThubView alloc] init];
self.contentView = _rnThubView
.....
......
Rest of the code remains mostly the same in objective-c++ file.
Now when I run via cli
, the app crashes with no logs on cli
. When I run via Xcode
, I get following logs with a white screen on the simulator
flipper: FlipperClient::addPlugin Inspector
flipper: FlipperClient::addPlugin Preferences
flipper: FlipperClient::addPlugin React
flipper: FlipperClient::addPlugin Network
2022-07-04 19:16:34.262238+0530 FabricSwift[51914:596543] [connection] nw_socket_handle_socket_event [C1.1:1] Socket SO_ERROR [61: Connection refused]
2022-07-04 19:16:34.290263+0530 FabricSwift[51914:596543] [connection] nw_socket_handle_socket_event [C1.2:1] Socket SO_ERROR [61: Connection refused]
2022-07-04 19:16:34.293022+0530 FabricSwift[51914:596537] [connection] nw_connection_get_connected_socket [C1] Client called nw_connection_get_connected_socket on unconnected nw_connection
2022-07-04 19:16:34.296327+0530 FabricSwift[51914:596537] TCP Conn 0x600001130370 Failed : error 0:61 [61]
2022-07-04 19:16:36.557475+0530 FabricSwift[51914:596543] [connection] nw_socket_handle_socket_event [C5.1:1] Socket SO_ERROR [61: Connection refused]
2022-07-04 19:16:36.558768+0530 FabricSwift[51914:596543] [connection] nw_socket_handle_socket_event [C5.2:1] Socket SO_ERROR [61: Connection refused]
2022-07-04 19:16:36.559075+0530 FabricSwift[51914:596538] [connection] nw_connection_get_connected_socket [C5] Client called nw_connection_get_connected_socket on unconnected nw_connection
2022-07-04 19:16:36.559146+0530 FabricSwift[51914:596538] TCP Conn 0x600001104840 Failed : error 0:61 [61]
2022-07-04 19:16:36.728528+0530 FabricSwift[51914:596578] [javascript] Running "FabricSwift" with {"fabric":true,"initialProps":{"concurrentRoot":true},"rootTag":1}
2022-07-04 19:16:37.065773+0530 FabricSwift[51914:596539] [connection] nw_socket_handle_socket_event [C9.1:1] Socket SO_ERROR [61: Connection refused]
2022-07-04 19:16:37.066881+0530 FabricSwift[51914:596539] [connection] nw_socket_handle_socket_event [C9.2:1] Socket SO_ERROR [61: Connection refused]
2022-07-04 19:16:37.067294+0530 FabricSwift[51914:596539] [connection] nw_connection_get_connected_socket [C9] Client called nw_connection_get_connected_socket on unconnected nw_connection
2022-07-04 19:16:37.067425+0530 FabricSwift[51914:596539] TCP Conn 0x6000011370d0 Failed : error 0:61 [61]
assertion failed [thread_context != nullptr]: got an exception for an unknown thread
(ExceptionServer.cpp:809 handle_exception)
Message from debugger: Xcode has killed the LLDB RPC server to allow the debugger to detach from your process. You may need to manually terminate your process.
Full source is here https://github.com/PritishSawant/ReactNativeFabricSwiftTry
As far as I know, Fabric doesn't support Swift views.
@kelset I am just creating a bridge. I think that should work. It's not related to fabric anyway. Check this https://github.com/reactwg/react-native-new-architecture/discussions/40