Reputation: 4287
I want to instantiate a class by using a string but I'm having problems. That's what I try to do:
let aClass = NSClassFromString("MyApp.Outer.Inner") as! SomeProtocol.Type
....
public class Outer {
public class Inner: SomeProtocol {
init() {...}
}
}
That's crashing (because NSClassFromString returns nil
But that's working:
let aClass = NSClassFromString("MyApp.Inner") as! SomeProtocol.Type
....
public class Inner: SomeProtocol {
init() {...}
}
Doesn't NSClassFromString
work for nested classes?
Background:
I have many "inner" classes that I use as templates to create objects (instead of storing them in .plist
files, which is kind of annoying). I want to encapsulate them in an "Outer" class to have them better organised.
Thanks for any help :)
EDIT: I saw the question that this seems to be a duplicate of. But that's not a viable solution:
(Note this snippet won't run by itself -- the class A.B has to be referenced at least once somewhere in your process in order to be registered with the ObjC runtime. This could be as simple as putting let t = A.B.self somewhere in your app's startup code.)
I'm doing this approach with NSClassFromString
because I want to avoid adding too much stuff for every inner class I create. I don't want to constantly add this to my startup code.
Upvotes: 4
Views: 536
Reputation: 17040
If you run this code:
import Foundation
class Outer: NSObject {
class Inner: NSObject {}
}
print(NSStringFromClass(Outer.Inner.self))
You will get something like the following:
_TtCC8Untitled5Outer5Inner
As you can see, embedded classes have their names mangled differently from how you'd expect. I believe the mangling format is undocumented, as well, so you can't rely on this not changing in some future Swift release.
If you need to be able to access a class using its name in the Objective-C runtime, you can use the @objc
attribute to give it a custom Objective-C name. Unfortunately, the @objc
keyword doesn't allow dots, but you can use underscores for a similar effect:
class Outer: NSObject {
@objc (Outer_Inner) class Inner: NSObject {}
}
EDIT: I should clarify that even with the @objc
keyword specified, the inner class will still need to be accessed by Swift code before it will be available to the Objective-C runtime, and thus before functions like NSClassFromString()
will work.
Upvotes: 4