Swift language NSClassFromString
Less hacky solution here: https://stackoverflow.com/a/32265287/308315
Note that Swift classes are namespaced now so instead of "MyViewController" it'd be "AppName.MyViewController"
Deprecated since XCode6-beta 6/7
Solution developed using XCode6-beta 3
Thanks to the answer of Edwin Vermeer I was able to build something to instantiate Swift classes into an Obj-C class by doing this:
// swift file
// extend the NSObject class
extension NSObject {
// create a static method to get a swift class for a string name
class func swiftClassFromString(className: String) -> AnyClass! {
// get the project name
if var appName: String? = NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleName") as String? {
// generate the full name of your class (take a look into your "YourProject-swift.h" file)
let classStringName = "_TtC\(appName!.utf16count)\(appName)\(countElements(className))\(className)"
// return the class!
return NSClassFromString(classStringName)
}
return nil;
}
}
// obj-c file
#import "YourProject-Swift.h"
- (void)aMethod {
Class class = NSClassFromString(key);
if (!class)
class = [NSObject swiftClassFromString:(key)];
// do something with the class
}
EDIT
You can also do it in pure obj-c:
- (Class)swiftClassFromString:(NSString *)className {
NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
NSString *classStringName = [NSString stringWithFormat:@"_TtC%d%@%d%@", appName.length, appName, className.length, className];
return NSClassFromString(classStringName);
}
I hope this will help somebody !
Instantiating a nested class using NSClassFromString in swift
I find that the following works in a playground (Xcode 8.2 / Swift 3):
// inheriting NSObject is required for `@objc`, at which point `@objc` is optional
class A: NSObject {
class B: NSObject {
override var description: String { return "foo" }
}
}
let str = NSStringFromClass(A.B.self)
guard let anyClass = NSClassFromString(str)
else { fatalError("no class") }
// cast to a type that defines `init()` so we can instantiate
guard let nsClass = anyClass as? NSObject.Type
else { fatalError("class isn't NSObject") }
// call `.init()`, not `nsClass()`; constructor syntax is for static types only
let instance = nsClass.init()
print(instance) // -> "foo"
The oddball class "name" string is because the ObjC runtime doesn't understand nested classes (or other kinds of types that Swift can define but ObjC can't) -- within Swift itself, such mangled names are how types, functions and such get uniquely defined. (For example, name mangling is also how function overloading works: func foo()
and func foo(num: Int) -> Bool
have different mangled names internally.)
The bridging machinery can still be made to dynamically resolve a class given its properly mangled Swift name, but Swift name mangling is an implementation detail and subject to change. (At least until Swift 4 locks down the ABI.) So it's safe to pass the result of NSStringFromClass
to NSClassFromString
within the same program, but not safe to (e.g.) record a mangled name once in testing, ship that mangled name as a string literal or resource in your app, and expect it to work with NSClassFromString
later.
Instead, if you want your nested class (or any other Swift-defined class) to have a reliably known name for use in the ObjC runtime, give it an @objc(name)
(as described in the docs):
@objc class A: NSObject {
@objc(A_B) class B: NSObject { /*...*/ }
}
guard let anyClass = NSClassFromString("A_B")
else { fatalError("no class") }
(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.)
Using NSClassFromString() on a Swift declared class requires a fully qualified name
Annoyingly, I stumble across the answer as soon as I post this (Despite searching for hours).
You must put @objc(SwiftClassName)
above your swift class.
Like:
@objc(SubClass)
class SubClass: SuperClass {...}
Then all of your original Objective-c code will see these classes and not try to do anything funky with them!
Thanks to @klaus
Original post can be found here:
https://stackoverflow.com/a/24448786/846035
NSClassFromString works well in OC, but crashes in Swift
Swift classes are namespaced now so instead of "SecondViewController" it'd be "AppName.SecondViewController"
let nameSpace = NSBundle.mainBundle().infoDictionary!["CFBundleExecutable"] as! String
let controllerName = "SecondViewController"
let controller:AnyClass = NSClassFromString(nameSpace + "." + controllerName)!
let viewController = (controller as! UIViewController.Type).init()
navigationController?.pushViewController(viewController, animated: true)
iOS: In a Swift class, how to use NSClassFromString of a Obj-C Class?
Assuming self.navigationController
exists in this controller, here is your swift version of the code:
let viewControllers = self.navigationController!.viewControllers
var viewExists = false
for obj in viewControllers {
if let running = obj.value(forKey: "synchroRunning") as? Bool {
self.performSelector(onMainThread: #selector(startSpinner), with: nil, waitUntilDone: false)
} else {
self.synchroClick(nil)
}
viewExists = true
}
You do not need NSClassFromString
to find out if type is of a ViewController
, it a typed array in Swift therefore is guaranteed to be of type ViewController
. Make sure to check viewControllers.count > 0
before looping over it if you expect it to be empty.
Related Topics
The Best Way to Remove Duplicate Values from Nsmutablearray in Objective-C
Wait For Firebase to Load Before Returning from a Function
How to Change the Push and Pop Animations in a Navigation Based App
How to Send Mail from an Iphone Application
Disabling User Selection in Uiwebview
Get Button Click Inside Uitableviewcell
Iphone 6 Plus Resolution Confusion: Xcode or Apple'S Website? For Development
Programmatically Retrieve Memory Usage on Iphone
Nsfilemanager.Defaultmanager().Fileexistsatpath Returns False Instead of True
How to Check If a String Contains Another String in Objective-C
Starting Iphone App Development in Linux
Swift - Get Device'S Wifi Ip Address
Delete/Reset All Entries in Core Data
What Is the Documents Directory (Nsdocumentdirectory)
What's the Difference Between the Atomic and Nonatomic Attributes