ccgus / CocoaScript

JavaScript + the Cocoa frameworks, and then ObjC brackets show up to party as well.
Other
618 stars 58 forks source link

Can't call Swift functions from Mocha loaded framework #47

Open mludowise opened 7 years ago

mludowise commented 7 years ago

I wrote a framework in Swift but cannot access classes marked as @objc public from cocoascript after loading the framework using Mocha.

I created an example to illustrate this. In my example, I wrote a Sketch plugin that uses Mocha to load my framework TestFramework.framework and attempts to access classes in the framework to display a window on command. The framework has a Swift class called WindowController which displays a Window when calling WindowController.shared().showWindow(nil) (or [[WindowController shared] showWindow:nil] in Objective-C). After loading the framework in Mocha, the class WindowController is never accessible despite being marked as @objc public. However, when I created an Objective-C class in the Framework called WrapperClass which is just a wrapper class for WindowController, I'm able to access it from CocoaScript.

I confirmed that both WindowController and WrapperClass are publicly accessible when the framework is loaded into an Objective-C app (TestAppOC which is also contained in my example).

To illustrate this, install my example plugin in Sketch and go to Plugins > Test Framework > Open with Swift or Open with Objective-C. The source code for the framework and test app can be opened in XCode in TestFramework/TestFramework.xcworkspace.

Am I doing something wrong or does CocoaScript not support calling Swift classes from dynamically loaded frameworks?

ccgus commented 7 years ago

I'm guessing there's some namespace issues / de-mangling that will have to be resolved when calling Swift classes from CocoaScript. I haven't messed around enough to know what those would be though.

mludowise commented 7 years ago

Ahah! I think I figured it out.

It looks like declaring the Swift class as @objc public class ClassName { ... } doesn't work but using the following does:

@objc(ClassName)
public class ClassName {
...
}

According to Apple's documentation, the former is supposed to work so I'm not sure why only the later notation does.

mludowise commented 7 years ago

FWIW My working solution is on a branch.

I diffed the generated the "TestFramework-Swift.h" file generated when building the framework in XCode and it looks like when using @objc public class SwiftWrapper Xcode assigns the class an autogenerated classname, in my case it was "_TtC13TestFramework12SwiftWrapper". When using the @obc(SwiftWrapper) notation, it kept the same class name I assigned it in Swift.