Closed RomanSlyepko closed 5 years ago
I believe this maybe related to this https://medium.com/@maximbilan/ios-objective-c-project-nsclassfromstring-method-for-swift-classes-dbadb721723
If you use Swift classes in the Objective C project, you may be faced with the problem, that NSClassFromString method always returns nil. You need to call NSClassFromString from Swift code first of all, and don’t forget about format:
#appName.#className
But if you have many targets in your project or the name of the project is different than the name of the target you need to use the following format:
#appName_#targetName.#className
extension NSObject {
class func swiftClassFromString(className: String) -> AnyClass! {
if var appName: String? = NSBundle.mainBundle().objectForInfoDictionaryKey(“CFBundleName”) as! String? {
let fAppName = appName!.stringByReplacingOccurrencesOfString(“ “, withString: “_”, options: NSStringCompareOptions.LiteralSearch, range: nil)
return NSClassFromString(“\(fAppName).\(className)”)
}
return nil;
}
}
I havent got the opportunity to integrate swift with objective-c since swift became abi stable not so long ago.
Please provide some example code (upload a zip here) to test this.
Thanks.
@clsource well, yes. It's related to the way Swift class names are generated and consequently to the usage of NSClassFromString
in Jasonette internals.
That's why in JasonComponentFactory
it should extract a raw name (without module and target names) and only then use it in [NSString stringWithFormat:@"Jason%@Component", capitalizedType]
Try this in your swift code
https://stackoverflow.com/a/30895110
All swift classes use the Product Module Name a dot and the classname for their namespace (Module.Class). If you wanted to use "MySwiftClass" name for the class within your Objective-C code; you can add @objc(MySwiftClass)
annotation to expose the same swift class name (without the module):
@objc(MySwiftClass)
class MySwiftClass{
...
}
Then
Class myClass = NSClassFromString(@"MySwiftClass");
Will contain the class instead of being nil.
If thats not working maybe this addition to the JasonComponentFactory.m
will do.
+ (UIView *)build:(UIView *)component withJSON:(NSDictionary *)child withOptions:(NSMutableDictionary *)options{
NSString *capitalizedType = [child[@"type"] capitalizedString];
NSString *componentClassName = [NSString stringWithFormat:@"Jason%@Component", capitalizedType];
if(componentClassName){
Class<JasonComponentProtocol> ComponentClass = NSClassFromString(componentClassName);
if(!ComponentClass) {
// Maybe a is a Swift Component. NSClassFromString return nil on these.
// see https://stackoverflow.com/questions/28706602/nsclassfromstring-using-a-swift-file
NSString *prefix = [[NSBundle mainBundle] infoDictionary][@"CFBundleExecutable"];
NSString *swiftClassName = [NSString stringWithFormat:@"%@.%@", prefix, componentClassName];
ComponentClass = NSClassFromString(swiftClassName);
}
@RomanSlyepko it works?
yes, @objc(MySwiftClass)
works fine
Extending with custom components doesn't work for Swift classes. There is an issue in
JasonComponentFactory
in methodbuild:withJSON:withOptions:
:NSClassFromString(componentClassName)
returns nil for Swift classes, because Swift class name have a different format:<appName>.<className>
or<appName>_<targetName>.<className>
instead of just<className>
in Obj-C classes.Therefore component class names must have a prefix for Swift classes, i.e.
MyAppName.JasonSuperComponent