Reputation: 15471
Say I have a class called ExampleClass
.
Say I then write code like so:
@objc(ExampleClass)
class ExampleClass: NSObject {
@objc class func exampleFunc() -> Void {
}
}
With an Objective-C file header like so:
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
@interface RCT_EXTERN_MODULE(ExampleClass, NSObject)
RCT_EXTERN_METHOD(exampleFunc)
@end
Which I then consume in my React Native app like so:
console.log('exampleClass', React.NativeModules.ExampleClass);
console.log('exampleFunc', React.NativeModules.ExampleClass.exampleFunc)
The first console log results in {exampleFunc: f}
The second results in undefined
,
Calling the function: React.NativeModules.ExampleClass.exampleFunc()
results in an app crash with:
Exception 'exampleFunc is not a recognized Objective-C method.' was thrown while invoking setupLogger on target ExampleClass with params (
While changing only the Swift so that it reads:
@objc(ExampleClass)
class ExampleClass: NSObject {
@obj func exampleFunc() -> Void {
}
}
results in calling the function (which, yes) does nothing at present.
How can I expose class level variables? I am trying to write functional Swift, and I am using class methods to simulate structs.
Upvotes: 3
Views: 2192
Reputation: 87
I know I'm kinda late to the party but I recently faced the same problem and I fixed it using a different approach. Adding to the answer given above by @thejoelpatrol, a different approach would be to store the object's reference created by react native in some static
variable that would be accessible by you. Then we can use the variable to access the object created by react-native anytime.
Whenever React Native tries to instantiate the class, it would come to the init. inside the init, we can save the reference to the object created by RN.
@objc public class MyClass {
@objc public static var shared: MyClass?
init() {
MyClass.shared = self
}
}
The .m
bridge file is as follows:
@interface RCT_EXTERN_MODULE(MyClass)
RCT_EXTERN_METHOD(myClassMethod)
@end
Upvotes: 2
Reputation: 173
I believe the problem is that RCT_EXPORT_METHOD()
only works on instance methods, not class methods, according to my own similar problem and some discussion here: https://github.com/facebook/react-native/issues/2311
My use case is trying to bridge a getInstance()
method for a Swift singleton class. This is problematic because when you reference NativeModules.ExampleClass
from javascript, which has been exported with RCT_EXTERN_MODULE()
, RN calls init()
on its own, which you don't want for a singleton (init()
reference: https://samwize.com/2017/02/09/calling-a-view-controller-function-from-react-native/)
The best way I've found to accomplish this is pretty ugly. I have a dummy wrapper class that does nothing except call methods on the singleton, and this is the class I export to Objective C (and therefore to React Native). It's basically like this:
@objc(StupidWrapperClass)
class StupidWrapperClass : NSObject {
@objc(pseudoSingletonSomeMethod)
public func pseudoSingletonSomeMethod() {
let singleton = ActualClass.getInstance()
singleton.someMethod()
}
}
and then in the .m bridge file:
@interface RCT_EXTERN_MODULE(StupidWrapperClass, NSObject)
RCT_EXTERN_METHOD(pseudoSingletonSomeMethod)
@end
You could do something like this for a class method, too:
@objc(StupidWrapperClass)
class StupidWrapperClass : NSObject {
@objc(pseudoClassMethod)
public func pseudoClassMethod() {
ActualClass.theRealClassMethod()
}
}
Upvotes: 2