RNNewArchitectureApp icon indicating copy to clipboard operation
RNNewArchitectureApp copied to clipboard

How to use view created in swift inside an objective-c++ file?

Open pritsawa opened this issue 2 years ago • 2 comments

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

pritsawa avatar Jul 05 '22 05:07 pritsawa

As far as I know, Fabric doesn't support Swift views.

kelset avatar Jul 05 '22 08:07 kelset

@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

pritsawa avatar Jul 05 '22 09:07 pritsawa