New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swift support in native modules #207

Closed
mhart opened this Issue Mar 26, 2015 · 41 comments

Comments

Projects
None yet
@mhart

mhart commented Mar 26, 2015

(you all knew this was coming 馃樃 )

The current documentation suggests Swift is not yet supported, but I thought it would be good to have an issue to at least track progress on that, if it is indeed coming?

There are some related issues here, but I don't think any of them tackle Swift support at a high level:

  1. #68
  2. #115
  3. #23
@brentvatne

This comment has been minimized.

Show comment
Hide comment
@brentvatne

brentvatne Apr 15, 2015

Collaborator

@mhart - My understanding is that any Swift support would need to be a community driven effort, given that Facebook uses Objective C internally at the moment. Until this changes there's probably no need to have an issue tracking this, we have enough open issues already 馃槃

If you'd like to lead this effort it would definitely be welcome! Feel free to create another repo and get in touch in IRC.

Collaborator

brentvatne commented Apr 15, 2015

@mhart - My understanding is that any Swift support would need to be a community driven effort, given that Facebook uses Objective C internally at the moment. Until this changes there's probably no need to have an issue tracking this, we have enough open issues already 馃槃

If you'd like to lead this effort it would definitely be welcome! Feel free to create another repo and get in touch in IRC.

@brentvatne brentvatne closed this Apr 15, 2015

@mhart

This comment has been minimized.

Show comment
Hide comment
@mhart

mhart Apr 15, 2015

Damn 馃樋

I'm surprised it's not on your roadmap!

mhart commented Apr 15, 2015

Damn 馃樋

I'm surprised it's not on your roadmap!

@randomer

This comment has been minimized.

Show comment
Hide comment
@randomer

randomer Apr 16, 2015

Same here. Especially considering the fact that in case some not-yet-implemented native functionality is needed, it would be much easier for a JS developer to learn Swift than Objective-C (which at least at the first glance looks like a mess)

Same here. Especially considering the fact that in case some not-yet-implemented native functionality is needed, it would be much easier for a JS developer to learn Swift than Objective-C (which at least at the first glance looks like a mess)

@ide

This comment has been minimized.

Show comment
Hide comment
@ide

ide Apr 16, 2015

Collaborator

Not to derail the topic at hand but for context: there are lots of little things about Swift that make Objective-C the better choice for now. The tooling for Swift is premature in that build times are worse, every app that uses Swift adds ~6MB to its binary for the runtime, Xcode crashes frequently, the Swift compiler produces code with bugs, the language is changing in backwards-incompatible ways, etc. Apple will fix these issues but it will be a year or two before developing with Swift is better than developing with Objective-C.

2c: my experience learning the languages was that Objective-C was actually easier since it's a relatively thin layer above C and is a rather dynamic language. It also works well with all the iOS APIs whereas sometimes there are interop issues with Swift. So generally speaking, I expect developers to have a better time writing native React modules in Objective-C at this time.

That all said, eventually supporting Swift probably makes sense as it improves and exploring how Swift could export native methods to JS would be useful.

Collaborator

ide commented Apr 16, 2015

Not to derail the topic at hand but for context: there are lots of little things about Swift that make Objective-C the better choice for now. The tooling for Swift is premature in that build times are worse, every app that uses Swift adds ~6MB to its binary for the runtime, Xcode crashes frequently, the Swift compiler produces code with bugs, the language is changing in backwards-incompatible ways, etc. Apple will fix these issues but it will be a year or two before developing with Swift is better than developing with Objective-C.

2c: my experience learning the languages was that Objective-C was actually easier since it's a relatively thin layer above C and is a rather dynamic language. It also works well with all the iOS APIs whereas sometimes there are interop issues with Swift. So generally speaking, I expect developers to have a better time writing native React modules in Objective-C at this time.

That all said, eventually supporting Swift probably makes sense as it improves and exploring how Swift could export native methods to JS would be useful.

@frankbolviken

This comment has been minimized.

Show comment
Hide comment
@frankbolviken

frankbolviken Apr 21, 2015

Dissapointing..

Dissapointing..

@nicklockwood

This comment has been minimized.

Show comment
Hide comment
@nicklockwood

nicklockwood Apr 21, 2015

Contributor

We won't be using Swift internally within the framework for the foreseeable future for all the reasons that @ide mentions, however we would welcome support for writing modules and views in Swift.

The reason this is difficult at the moment is because we're heavily reliant on macros for setting up the bindings between Objective-C code and the JavaScript bridge, and Swift has no support for macros whatsoever.

I'm not particularly a fan of macros in general, but it makes this process simple and elegant to an extent that would be hard (if not impossible) to achieve any other way, and crucially it isolates the syntax from the implementation, giving us freedom to make changes to the infrastructure without constantly breaking everyone's existing code.

To support modules written in 100% swift, we would need to provide a totally separate mechanism for registering the module class, methods and properties because writing the bridging code that the Obj-C macros generate manually in Swift would be cumbersome and fragile (assuming that it's even possible).

In the future, once the APIs settle, we may be able to move to a more traditional protocol-based approach, which would be better suited to Swift. In the meantime though, if you don't mind writing a little bit of glue code in Objective-C, it's perfectly possible to implement the bulk of your native module logic in Swift if you wish to do so.

Contributor

nicklockwood commented Apr 21, 2015

We won't be using Swift internally within the framework for the foreseeable future for all the reasons that @ide mentions, however we would welcome support for writing modules and views in Swift.

The reason this is difficult at the moment is because we're heavily reliant on macros for setting up the bindings between Objective-C code and the JavaScript bridge, and Swift has no support for macros whatsoever.

I'm not particularly a fan of macros in general, but it makes this process simple and elegant to an extent that would be hard (if not impossible) to achieve any other way, and crucially it isolates the syntax from the implementation, giving us freedom to make changes to the infrastructure without constantly breaking everyone's existing code.

To support modules written in 100% swift, we would need to provide a totally separate mechanism for registering the module class, methods and properties because writing the bridging code that the Obj-C macros generate manually in Swift would be cumbersome and fragile (assuming that it's even possible).

In the future, once the APIs settle, we may be able to move to a more traditional protocol-based approach, which would be better suited to Swift. In the meantime though, if you don't mind writing a little bit of glue code in Objective-C, it's perfectly possible to implement the bulk of your native module logic in Swift if you wish to do so.

@robertjpayne

This comment has been minimized.

Show comment
Hide comment
@robertjpayne

robertjpayne Apr 22, 2015

Contributor

It is possible to utilise Swift without too much work. Because you solely need to generate some metadata for React Native you can get away with just creating nearly blank categories, though it does require at least 1 Objective-C implementation file per Swift class. ( No header or #import necessary! )

@ide @mhart @brentvatne @randomer @frankbolviken
See my gist here with example how-to:

https://gist.github.com/robertjpayne/855fdb15d5ceca12f6c5

Note that this implementation is pretty fragile and relies on a bit of knowledge about how react-native currently generates it's metadata for the bridging.

@nicklockwood is there any chance you'd be open to maintaining a set of Swift compatible macros? I'm just not sure how much of a moving target you expect the current macros to be.

Contributor

robertjpayne commented Apr 22, 2015

It is possible to utilise Swift without too much work. Because you solely need to generate some metadata for React Native you can get away with just creating nearly blank categories, though it does require at least 1 Objective-C implementation file per Swift class. ( No header or #import necessary! )

@ide @mhart @brentvatne @randomer @frankbolviken
See my gist here with example how-to:

https://gist.github.com/robertjpayne/855fdb15d5ceca12f6c5

Note that this implementation is pretty fragile and relies on a bit of knowledge about how react-native currently generates it's metadata for the bridging.

@nicklockwood is there any chance you'd be open to maintaining a set of Swift compatible macros? I'm just not sure how much of a moving target you expect the current macros to be.

@mhart

This comment has been minimized.

Show comment
Hide comment
@mhart

mhart Apr 22, 2015

@robertjpayne Very cool! Would be great to have a better home for this for people to follow if you do indeed want to keep it up to date (like a dedicated repo). I'm sure that would get quite popular 馃槃 But totally get that might be too much work if things are shifting rapidly.

I mean, ideally, Facebook would just add this sort of thing to their docs somewhere.

mhart commented Apr 22, 2015

@robertjpayne Very cool! Would be great to have a better home for this for people to follow if you do indeed want to keep it up to date (like a dedicated repo). I'm sure that would get quite popular 馃槃 But totally get that might be too much work if things are shifting rapidly.

I mean, ideally, Facebook would just add this sort of thing to their docs somewhere.

@joewalnes

This comment has been minimized.

Show comment
Hide comment

@robertjpayne Nice! 馃憤

@robertjpayne

This comment has been minimized.

Show comment
Hide comment
@robertjpayne

robertjpayne Apr 22, 2015

Contributor

Yea I thought about a repo but given it's only the single header file it seems excessive. I'll wait and see if @nicklockwood chimes in about the moving target.

Contributor

robertjpayne commented Apr 22, 2015

Yea I thought about a repo but given it's only the single header file it seems excessive. I'll wait and see if @nicklockwood chimes in about the moving target.

@mhart

This comment has been minimized.

Show comment
Hide comment
@mhart

mhart Apr 22, 2015

@robertjpayne I feel ya 鈥 I think the README would be larger than the actual code 馃槂, but that's what people would be interested in I'd say. I'd be fine with a gist if GitHub actually made them easy to follow and manage comments...

mhart commented Apr 22, 2015

@robertjpayne I feel ya 鈥 I think the README would be larger than the actual code 馃槂, but that's what people would be interested in I'd say. I'd be fine with a gist if GitHub actually made them easy to follow and manage comments...

@joewood

This comment has been minimized.

Show comment
Hide comment
@joewood

joewood Apr 22, 2015

How about adding this to react-native-cli as a command to add a Swift class to an existing app?

react-native addswift Foo

joewood commented Apr 22, 2015

How about adding this to react-native-cli as a command to add a Swift class to an existing app?

react-native addswift Foo

@nicklockwood nicklockwood reopened this Apr 22, 2015

@nicklockwood

This comment has been minimized.

Show comment
Hide comment
@nicklockwood

nicklockwood Apr 22, 2015

Contributor

Reopening this as it seems to be a useful place to track this discussion.

Contributor

nicklockwood commented Apr 22, 2015

Reopening this as it seems to be a useful place to track this discussion.

@brentvatne

This comment has been minimized.

Show comment
Hide comment
@brentvatne

brentvatne Apr 22, 2015

Collaborator

@nicklockwood - sounds good, seemed stagnant for a while but the discussion has really picked up since I closed the issue, go figure! 馃槃

Collaborator

brentvatne commented Apr 22, 2015

@nicklockwood - sounds good, seemed stagnant for a while but the discussion has really picked up since I closed the issue, go figure! 馃槃

@nicklockwood

This comment has been minimized.

Show comment
Hide comment
@nicklockwood

nicklockwood Apr 22, 2015

Contributor

@robertjpayne awesome work - I appreciate you taking the initiative with this.

I agree that this seems like Swift module support should be part of the core rather than something external because it will be very hard to ensure macros are kept in sync.

Your RCT_SWIFT_EXPORT_MODULE macro can be simplified to:

#define RCT_SWIFT_EXPORT_MODULE_PUSH(module_name, superclass, js_name) \
  @interface module_name : superclass \
  @end \
  @interface module_name (RCT_SWIFT_MODULE_EXPORT) <RCTBridgeModule> \
  @end \
  @implementation module_name (RCT_SWIFT_MODULE_EXPORT) \
  RCT_EXPORT_MODULE(js_name) \

I thought it could be reduced to just

#define RCT_SWIFT_EXPORT_MODULE_PUSH(module_name, superclass, js_name) \
  @interface module_name : superclass <RCTBridgeModule> \
  @end \
  @implementation module_name (RCT_SWIFT_MODULE_EXPORTS)  \
  RCT_EXPORT_MODULE(js_name) \

But it seems that with this approach, module_name isn't registered as conforming to RCTBridgeModule, which is a little strange (though probably easy to fix in the bridge logic itself).

Contributor

nicklockwood commented Apr 22, 2015

@robertjpayne awesome work - I appreciate you taking the initiative with this.

I agree that this seems like Swift module support should be part of the core rather than something external because it will be very hard to ensure macros are kept in sync.

Your RCT_SWIFT_EXPORT_MODULE macro can be simplified to:

#define RCT_SWIFT_EXPORT_MODULE_PUSH(module_name, superclass, js_name) \
  @interface module_name : superclass \
  @end \
  @interface module_name (RCT_SWIFT_MODULE_EXPORT) <RCTBridgeModule> \
  @end \
  @implementation module_name (RCT_SWIFT_MODULE_EXPORT) \
  RCT_EXPORT_MODULE(js_name) \

I thought it could be reduced to just

#define RCT_SWIFT_EXPORT_MODULE_PUSH(module_name, superclass, js_name) \
  @interface module_name : superclass <RCTBridgeModule> \
  @end \
  @implementation module_name (RCT_SWIFT_MODULE_EXPORTS)  \
  RCT_EXPORT_MODULE(js_name) \

But it seems that with this approach, module_name isn't registered as conforming to RCTBridgeModule, which is a little strange (though probably easy to fix in the bridge logic itself).

@robertjpayne

This comment has been minimized.

Show comment
Hide comment
@robertjpayne

robertjpayne Apr 22, 2015

Contributor

@nicklockwood the first interface is solely there to declare to Objective-C that the class exists since it's implemented in Swift. It's essentially just the public header file.

To add the protocol conformance it has to be done inside the category. Though theoretically the user could add the protocol in Swift.

Contributor

robertjpayne commented Apr 22, 2015

@nicklockwood the first interface is solely there to declare to Objective-C that the class exists since it's implemented in Swift. It's essentially just the public header file.

To add the protocol conformance it has to be done inside the category. Though theoretically the user could add the protocol in Swift.

@nicklockwood

This comment has been minimized.

Show comment
Hide comment
@nicklockwood

nicklockwood Apr 22, 2015

Contributor

The RCT_SWIFT_EXPORT_MODULE_PUSH/POP syntax is quite elegant, but it has shades of trying to reinvent the Objective-C language, which we've been trying to avoid (macros are seductive). I'm going to think about this for a bit and see if I can come up with something less obtrusive.

Contributor

nicklockwood commented Apr 22, 2015

The RCT_SWIFT_EXPORT_MODULE_PUSH/POP syntax is quite elegant, but it has shades of trying to reinvent the Objective-C language, which we've been trying to avoid (macros are seductive). I'm going to think about this for a bit and see if I can come up with something less obtrusive.

@nicklockwood

This comment has been minimized.

Show comment
Hide comment
@nicklockwood

nicklockwood Apr 22, 2015

Contributor

@robertjpayne I tried both those code examples before posting them. It seems to work without the extra category.

Contributor

nicklockwood commented Apr 22, 2015

@robertjpayne I tried both those code examples before posting them. It seems to work without the extra category.

@robertjpayne

This comment has been minimized.

Show comment
Hide comment
@robertjpayne

robertjpayne Apr 22, 2015

Contributor

@nicklockwood right! I agree about the macros, since there's less interface boilerplate it may not be necessary to have the PUSH/POP but just make the user define the interface, category and then add the export methods inside the category definition.

Contributor

robertjpayne commented Apr 22, 2015

@nicklockwood right! I agree about the macros, since there's less interface boilerplate it may not be necessary to have the PUSH/POP but just make the user define the interface, category and then add the export methods inside the category definition.

@nicklockwood

This comment has been minimized.

Show comment
Hide comment
@nicklockwood

nicklockwood Apr 22, 2015

Contributor

I was thinking that the RCT_SWIFT_EXPORT_METHOD macro could be called something like RCT_EXTERN_METHOD instead (meaning "this method is declared elsewhere"). Then we could implement RCT_EXPORT_METHOD in terms of RCT_EXTERN_METHOD:

#define RCT_EXPORT_METHOD(method) \
  RCT_EXTERN_METHOD(method)
  - (void)method

That way, we avoid duplicating the macro logic, which should make it easier to maintain.

Contributor

nicklockwood commented Apr 22, 2015

I was thinking that the RCT_SWIFT_EXPORT_METHOD macro could be called something like RCT_EXTERN_METHOD instead (meaning "this method is declared elsewhere"). Then we could implement RCT_EXPORT_METHOD in terms of RCT_EXTERN_METHOD:

#define RCT_EXPORT_METHOD(method) \
  RCT_EXTERN_METHOD(method)
  - (void)method

That way, we avoid duplicating the macro logic, which should make it easier to maintain.

@ide

This comment has been minimized.

Show comment
Hide comment
@ide

ide Apr 22, 2015

Collaborator

Re: class definition - I get the need for the category but think you could get rid of the first @interface declaration and pull in the swift bridging header instead.

Collaborator

ide commented Apr 22, 2015

Re: class definition - I get the need for the category but think you could get rid of the first @interface declaration and pull in the swift bridging header instead.

@nicklockwood

This comment has been minimized.

Show comment
Hide comment
@nicklockwood

nicklockwood Apr 22, 2015

Contributor

@ide but then you'd have to add the class to the bridging header, right? This way, you don't have to, as the Swift class doesn't need to reference any symbols in SwiftReactModuleExports.m

Contributor

nicklockwood commented Apr 22, 2015

@ide but then you'd have to add the class to the bridging header, right? This way, you don't have to, as the Swift class doesn't need to reference any symbols in SwiftReactModuleExports.m

@ide

This comment has been minimized.

Show comment
Hide comment
@ide

ide Apr 22, 2015

Collaborator

@nicklockwood oops - I meant generated header instead of the bridging header. It's just #import "App-Swift.h".

Collaborator

ide commented Apr 22, 2015

@nicklockwood oops - I meant generated header instead of the bridging header. It's just #import "App-Swift.h".

@robertjpayne

This comment has been minimized.

Show comment
Hide comment
@robertjpayne

robertjpayne Apr 22, 2015

Contributor

@ide I've never had good luck with the generated headers, the tooling for them is buggy, it's much more reliable to generate the a small interface stub to work with.

Contributor

robertjpayne commented Apr 22, 2015

@ide I've never had good luck with the generated headers, the tooling for them is buggy, it's much more reliable to generate the a small interface stub to work with.

@ide

This comment has been minimized.

Show comment
Hide comment
@ide

ide Apr 22, 2015

Collaborator

@robertjpayne have you had issues with the latest Xcode? Swift got a lot more tenable in the last release and a lot of compiler issues went away.

Collaborator

ide commented Apr 22, 2015

@robertjpayne have you had issues with the latest Xcode? Swift got a lot more tenable in the last release and a lot of compiler issues went away.

@robertjpayne

This comment has been minimized.

Show comment
Hide comment
@robertjpayne

robertjpayne Apr 22, 2015

Contributor

@ide yup, with my simple example I've tried just now and it refuses to generate a header for the class (Xcode 6.3.1). I think probably because the class is not referenced -anywhere- so the Swift compiler is probably stripping it.

Contributor

robertjpayne commented Apr 22, 2015

@ide yup, with my simple example I've tried just now and it refuses to generate a header for the class (Xcode 6.3.1). I think probably because the class is not referenced -anywhere- so the Swift compiler is probably stripping it.

@ide

This comment has been minimized.

Show comment
Hide comment
@ide

ide Apr 22, 2015

Collaborator

Boo Apple. OK - the @interface stub sounds good to me.

Collaborator

ide commented Apr 22, 2015

Boo Apple. OK - the @interface stub sounds good to me.

@robertjpayne

This comment has been minimized.

Show comment
Hide comment
@robertjpayne

robertjpayne Apr 22, 2015

Contributor

@nicklockwood I'll work on cleaning this up best I can so we don't use more macro magic than necessary.

It's going to look something like:

@interface MySwiftModule : NSObject <RCTBridgeModule>
@end
@implementation MySwiftModule (RCTBridgeModuleExterns)

RCT_EXTERN_MODULE(MySwiftModule)

RCT_EXTERN_METHOD(printMessage:(NSString *)message)
RCT_EXTERN_REMAP_METHOD(printMessage, printMessage:(NSString *)message)

@end

We could deduce this entirely into just the interface declaration if we're ok asking users to add @objc class func moduleName() -> String { return "MyJSModuleName" } to their Swift files if they want a custom name and creating macros that don't generate function implementations as they're not necessary anyways.

Contributor

robertjpayne commented Apr 22, 2015

@nicklockwood I'll work on cleaning this up best I can so we don't use more macro magic than necessary.

It's going to look something like:

@interface MySwiftModule : NSObject <RCTBridgeModule>
@end
@implementation MySwiftModule (RCTBridgeModuleExterns)

RCT_EXTERN_MODULE(MySwiftModule)

RCT_EXTERN_METHOD(printMessage:(NSString *)message)
RCT_EXTERN_REMAP_METHOD(printMessage, printMessage:(NSString *)message)

@end

We could deduce this entirely into just the interface declaration if we're ok asking users to add @objc class func moduleName() -> String { return "MyJSModuleName" } to their Swift files if they want a custom name and creating macros that don't generate function implementations as they're not necessary anyways.

@nicklockwood

This comment has been minimized.

Show comment
Hide comment
@nicklockwood

nicklockwood Apr 23, 2015

Contributor

We could derive the js name from the category name, but that might be a little too magical :-)

Contributor

nicklockwood commented Apr 23, 2015

We could derive the js name from the category name, but that might be a little too magical :-)

@nicklockwood

This comment has been minimized.

Show comment
Hide comment
@nicklockwood

nicklockwood Apr 23, 2015

Contributor

Another pattern I considered is

RCT_EXTERN_MODULE(MySwiftModule,
  RCT_EXTERN_METHOD(foo);
  RCT_EXTERN_METHOD(Bar);
)
Contributor

nicklockwood commented Apr 23, 2015

Another pattern I considered is

RCT_EXTERN_MODULE(MySwiftModule,
  RCT_EXTERN_METHOD(foo);
  RCT_EXTERN_METHOD(Bar);
)
@nicklockwood

This comment has been minimized.

Show comment
Hide comment
@nicklockwood

nicklockwood Apr 23, 2015

Contributor

This would have the benefit of generating all the boilerplate for you, and it feels a bit less magical than the push/pop to me. That may be purely subjective on my part though.

What do you think?

Contributor

nicklockwood commented Apr 23, 2015

This would have the benefit of generating all the boilerplate for you, and it feels a bit less magical than the push/pop to me. That may be purely subjective on my part though.

What do you think?

@robertjpayne

This comment has been minimized.

Show comment
Hide comment
@robertjpayne

robertjpayne Apr 23, 2015

Contributor

Yup I like that idea I'll try and get something working in the next few hours.

On 23/04/2015, at 12:11 pm, Nick Lockwood notifications@github.com wrote:

This would have the benefit of generating all the boilerplate for you, and it feels a bit less magical than the push/pop to me. That may be purely subjective on my part though.

What do you think?


Reply to this email directly or view it on GitHub.

Contributor

robertjpayne commented Apr 23, 2015

Yup I like that idea I'll try and get something working in the next few hours.

On 23/04/2015, at 12:11 pm, Nick Lockwood notifications@github.com wrote:

This would have the benefit of generating all the boilerplate for you, and it feels a bit less magical than the push/pop to me. That may be purely subjective on my part though.

What do you think?


Reply to this email directly or view it on GitHub.

@robertjpayne

This comment has been minimized.

Show comment
Hide comment
@robertjpayne

robertjpayne Apr 23, 2015

Contributor

Only thing is we still have to get the user to specify superclass for the stubbed interface. I can't find a way around that unless I can reliably get generated headers to work.

On 23/04/2015, at 12:11 pm, Nick Lockwood notifications@github.com wrote:

This would have the benefit of generating all the boilerplate for you, and it feels a bit less magical than the push/pop to me. That may be purely subjective on my part though.

What do you think?


Reply to this email directly or view it on GitHub.

Contributor

robertjpayne commented Apr 23, 2015

Only thing is we still have to get the user to specify superclass for the stubbed interface. I can't find a way around that unless I can reliably get generated headers to work.

On 23/04/2015, at 12:11 pm, Nick Lockwood notifications@github.com wrote:

This would have the benefit of generating all the boilerplate for you, and it feels a bit less magical than the push/pop to me. That may be purely subjective on my part though.

What do you think?


Reply to this email directly or view it on GitHub.

@nicklockwood

This comment has been minimized.

Show comment
Hide comment
@nicklockwood

nicklockwood Apr 23, 2015

Contributor

True. Maybe something more like this then?

@interface RCT_EXTERN_MODULE(MyModule, NSObject)

RCT_EXTERN_METHOD(foo);
RCT_EXTERN_METHOD(Bar);

@EnD

Contributor

nicklockwood commented Apr 23, 2015

True. Maybe something more like this then?

@interface RCT_EXTERN_MODULE(MyModule, NSObject)

RCT_EXTERN_METHOD(foo);
RCT_EXTERN_METHOD(Bar);

@EnD

@robertjpayne

This comment has been minimized.

Show comment
Hide comment
@robertjpayne

robertjpayne Apr 23, 2015

Contributor

@nicklockwood how does this look?

#define RCT_EXTERN_MODULE(objc_name, objc_supername) \
  RCT_EXTERN_REMAP_MODULE(objc_name, objc_name, objc_supername)

#define RCT_EXTERN_REMAP_MODULE(js_name, objc_name, objc_supername) \
  objc_name : objc_supername \
  @end \
  @interface objc_name (RCTExternModule) <RCTBridgeModule> \
  @end \
  @implementation objc_name (RCTExternModule) \
  RCT_EXPORT_MODULE(js_name)

#define RCT_EXTERN_METHOD(method) \
  RCT_EXTERN_REMAP_METHOD(, method)

#define RCT_EXTERN_REMAP_METHOD(js_name, method) \
  - (void)__rct_export__##method { \
  __attribute__((used, section("__DATA,RCTExport"))) \
  __attribute__((__aligned__(1))) \
    static const char *__rct_export_entry__[] = { __func__, #method, #js_name }; \

Allows two ways to make them:

Custom Module/Method Name:

@interface RCT_EXTERN_REMAP_MODULE(AwesomeJS, SwiftReactModule, NSObject)

RCT_EXTERN_REMAP_METHOD(doAwesome, printMessage:(NSString *)message)

@end
var AwesomeJS = require('NativeModules').AwesomeJS;
AwesomeJS.doAwesome("Hello World");

Inferred Module/Method Name:

@interface RCT_EXTERN_MODULE(SwiftReactModule, NSObject)

RCT_EXTERN_METHOD(printMessage:(NSString *)message)

@end
var SwiftReactModule = require('NativeModules').SwiftReactModule;
SwiftReactModule.printMessage("Hello World");
Contributor

robertjpayne commented Apr 23, 2015

@nicklockwood how does this look?

#define RCT_EXTERN_MODULE(objc_name, objc_supername) \
  RCT_EXTERN_REMAP_MODULE(objc_name, objc_name, objc_supername)

#define RCT_EXTERN_REMAP_MODULE(js_name, objc_name, objc_supername) \
  objc_name : objc_supername \
  @end \
  @interface objc_name (RCTExternModule) <RCTBridgeModule> \
  @end \
  @implementation objc_name (RCTExternModule) \
  RCT_EXPORT_MODULE(js_name)

#define RCT_EXTERN_METHOD(method) \
  RCT_EXTERN_REMAP_METHOD(, method)

#define RCT_EXTERN_REMAP_METHOD(js_name, method) \
  - (void)__rct_export__##method { \
  __attribute__((used, section("__DATA,RCTExport"))) \
  __attribute__((__aligned__(1))) \
    static const char *__rct_export_entry__[] = { __func__, #method, #js_name }; \

Allows two ways to make them:

Custom Module/Method Name:

@interface RCT_EXTERN_REMAP_MODULE(AwesomeJS, SwiftReactModule, NSObject)

RCT_EXTERN_REMAP_METHOD(doAwesome, printMessage:(NSString *)message)

@end
var AwesomeJS = require('NativeModules').AwesomeJS;
AwesomeJS.doAwesome("Hello World");

Inferred Module/Method Name:

@interface RCT_EXTERN_MODULE(SwiftReactModule, NSObject)

RCT_EXTERN_METHOD(printMessage:(NSString *)message)

@end
var SwiftReactModule = require('NativeModules').SwiftReactModule;
SwiftReactModule.printMessage("Hello World");
@robertjpayne

This comment has been minimized.

Show comment
Hide comment
@robertjpayne

robertjpayne Apr 23, 2015

Contributor

@nicklockwood unfortunately we have to redefine the method macro contents because the current RCT_REMAP_METHOD macro currently starts the concrete method's implementation which, because it's a category, overrides the swift method.

Best option would be to have these extern method macro contain the "header logic" and the non-extern methods macro contain the extern macro + implementation logic.

Contributor

robertjpayne commented Apr 23, 2015

@nicklockwood unfortunately we have to redefine the method macro contents because the current RCT_REMAP_METHOD macro currently starts the concrete method's implementation which, because it's a category, overrides the swift method.

Best option would be to have these extern method macro contain the "header logic" and the non-extern methods macro contain the extern macro + implementation logic.

@nicklockwood

This comment has been minimized.

Show comment
Hide comment
@nicklockwood

nicklockwood Apr 23, 2015

Contributor

@robertjpayne yep, this looks good to me. Yeah, I realised we'd have to reimplement RCT_EXPORT_METHOD by having it call RCT_EXTERN_METHOD (see my earlier comment), but I think that's not a problem if RCT_EXTERN_METHOD is going to be part of the core.

Contributor

nicklockwood commented Apr 23, 2015

@robertjpayne yep, this looks good to me. Yeah, I realised we'd have to reimplement RCT_EXPORT_METHOD by having it call RCT_EXTERN_METHOD (see my earlier comment), but I think that's not a problem if RCT_EXTERN_METHOD is going to be part of the core.

@robertjpayne

This comment has been minimized.

Show comment
Hide comment
@robertjpayne

robertjpayne Apr 23, 2015

Contributor

@nicklockwood cool, well if you're happy with this I'll go ahead and whip up a PR and remap RCT_EXPORT_METHOD to use RCT_EXTERN_METHOD.

Contributor

robertjpayne commented Apr 23, 2015

@nicklockwood cool, well if you're happy with this I'll go ahead and whip up a PR and remap RCT_EXPORT_METHOD to use RCT_EXTERN_METHOD.

@nicklockwood

This comment has been minimized.

Show comment
Hide comment
@nicklockwood

nicklockwood Apr 23, 2015

Contributor

@robertjpayne good call on RCT_EXTERN_REMAP_MODULE as well - I like the consistency there. I'll run this by the rest of the team today, but I'm pretty happy with this solution overall.

Contributor

nicklockwood commented Apr 23, 2015

@robertjpayne good call on RCT_EXTERN_REMAP_MODULE as well - I like the consistency there. I'll run this by the rest of the team today, but I'm pretty happy with this solution overall.

@nicklockwood

This comment has been minimized.

Show comment
Hide comment
@nicklockwood

nicklockwood Apr 23, 2015

Contributor

@robertjpayne please do :-)

Contributor

nicklockwood commented Apr 23, 2015

@robertjpayne please do :-)

@mhart

This comment has been minimized.

Show comment
Hide comment
@mhart

mhart Apr 25, 2015

Nice work ppl! 馃帀 So I guess this can be closed now thanks to b72acc2 ?

mhart commented Apr 25, 2015

Nice work ppl! 馃帀 So I guess this can be closed now thanks to b72acc2 ?

@vjeux vjeux closed this May 29, 2015

@facebook facebook locked as resolved and limited conversation to collaborators May 29, 2018

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.