0

I'm trying to call a Method from Objective-C that has been defined using a Macro which wraps a Swift function. I'm getting the compilation error No visible @interface for 'NearbyMessages' declares the selector '__rct_export__disconnect' in Xcode when I try to call my Method though.

My Swift function looks like this:

// SomeInterface.swift

@objc
func disconnect() -> Void {
    // (disconnect logic here)
}

The Objective-C code looks like this:

// SomeInterface.m
@interface RCT_EXTERN_REMAP_MODULE(SomeInterfaceNameJS, SomeInterfaceNamePrivate, NSObject)

RCT_EXTERN_METHOD(disconnect);
-(void) invalidate {
    [self __rct_export__disconnect];   // No visible @interface for 'NearbyMessages' declares the selector '__rct_export__disconnect'
    NSLog(@"GNM_BLE: invalidate!");
}

@end

The macro RCT_EXTERN_METHOD (from React's RCTBridgeModule.h) is defined as:

#define RCT_EXTERN_METHOD(method) \
  _RCT_EXTERN_REMAP_METHOD(, method, NO)

#define _RCT_EXTERN_REMAP_METHOD(js_name, method, is_blocking_synchronous_method) \
  + (const RCTMethodInfo *)RCT_CONCAT(__rct_export__, RCT_CONCAT(js_name, RCT_CONCAT(__LINE__, __COUNTER__))) { \
    static RCTMethodInfo config = {#js_name, #method, is_blocking_synchronous_method}; \
    return &config; \
  }

By reading this, upon compilation the Method should be called __rct_export__disconnect, right?

So why is it not possible to use [self __rct_export__disconnect] - How else can I call this method?

4

1 回答 1

1

TL;DR: To answer the question, call [self.class __rct_export__disconnect];. But it is better (and an only future-proof way in case the __rct_export__ prefix changes in the next versions of React Native) is to call the disconnect() function directly.


Objective-C allows having two main types of methods.

First type is the instance method, which operates on an instance of the Objective-C class. In the body of this method, self is a pointer to the instance of the object on the heap, hence the name. Through the self pointer you can access other instance methods, instance variables etc. It is declared/defined with a minus (-) sign in the beginning.

Second type is the class method, which operates on class objects (a specific Obj-C construct). It is most commonly used when you'd use a static function in other languages (with some caveats and quirks related to inheritance of course). In the body of this method, self is a pointer to the class object. Through it you can call other class methods, but you don't have access to any concrete instances of the object.

The difference is explained well here.


In your case, this macro defines a class method:

#define _RCT_EXTERN_REMAP_METHOD(js_name, method, is_blocking_synchronous_method) \
  + (const RCTMethodInfo *)RCT_CONCAT(__rct_export__, RCT_CONCAT(js_name, RCT_CONCAT(__LINE__, __COUNTER__))) { \
    static RCTMethodInfo config = {#js_name, #method, is_blocking_synchronous_method}; \
    return &config; \
  }

And this method is an instance method:

- (void)invalidate {
    [self __rct_export__disconnect];   // No visible @interface for 'NearbyMessages' declares the selector '__rct_export__disconnect'
    NSLog(@"GNM_BLE: invalidate!");
}

When you call [self __rct_export__disconnect];] from the instance method, the self points to the instance of your class. The __rct_export__disconnect is defined as a class method (see macro), and thus it is not defined on the instances of the object.

于 2020-06-04T15:41:20.007 回答