25

The following code prints nil, despite ListCell is a valid class.

var lCellClass : AnyClass! = NSClassFromString("ListCell");

println(lCellClass);

The docs are saying that method returns

The class object named by aClassName, or nil if no class by that name is currently loaded. If aClassName is nil, returns nil.

I also tried to get NSClassFromString() of current viewcontroller which is LOADED but still get nil

What can be the problem ?

Update: Even trying to do this NSClassFromString("Array") I still get nil

holex
  • 23,961
  • 7
  • 62
  • 76
nsinvocation
  • 7,559
  • 3
  • 41
  • 46

4 Answers4

81

The NSClassFromString function does work for (pure and Objective-C-derived) swift classes, but only if you use the fully qualified name.

For example, in a module called MyApp with a pure swift class called Person:

let personClass: AnyClass? = NSClassFromString("MyApp.Person")

The module name is defined by the "Product Module Name" (PRODUCT_MODULE_NAME) build setting, typically the same name as your target (with some normalization applied to e.g. remove spaces).

This is atypical, but if the class you're loading is in the current module and you don't know the module name at compile-time e.g. because the code is compiled as part of multiple targets, you can look up the bundle name dynamically, which usually corresponds to the module name:

let moduleName = Bundle.main.infoDictionary!["CFBundleName"] as! String
let personClass: AnyClass? = NSClassFromString(moduleName + "." + "Person")

I don't recommend this however unless you really don't know at compile-time.

See Using Swift Class Names with Objective-C APIs in Using Swift With Cocoa and Objective-C for more information.

Jack Lawrence
  • 10,664
  • 1
  • 47
  • 61
  • 2
    Interesting! Thanks for that. – dasdom Jul 04 '14 at 09:20
  • 1
    And that's why I love SO!! – Ashley Mills Jul 04 '14 at 09:22
  • 1
    +1 Just curious is it documented anywhere like that? – Janak Nirmal Jul 04 '14 at 09:43
  • Not currently, please file a bug report on the swift documentation at http://bugreport.apple.com – Jack Lawrence Jul 07 '14 at 00:49
  • let navButtonClass = NSClassFromString("UINavigationButton")! if let topView = searchBar.subviews.first { for subView in topView.subviews { if subView is navButtonClass { // subView.tintColor = UIColor.whiteColor() // subView.enabled = true } } } Trying to cast something as the return type of NSClassFromString does not work – SwiftMatt Jan 15 '16 at 09:42
  • 1
    In your example "MyApp" would be the target name, rather than the project name. So the universal example for "MyCustomClass " would be something like: `NSClassFromString(Bundle.main.infoDictionary!["CFBundleName"] as! String + "." + "MyCustomClass")` – Sasho Apr 18 '18 at 10:12
  • Once your project name includes space, then it is necessary to replace the space with "_" in "Bundle.main.infoDictionary!["CFBundleName"] as! String". – Albert Zou Oct 30 '18 at 04:59
  • would anyone care to add a hlper to swift runtime so that we won't have to incorporate this fragileness into the app code??? – Anton Tropashko Jun 18 '20 at 13:02
23

It's also possible to specify a name for the symbol in Objective-C which omits the namespace in objective C by using the @objc annotation. If you prefer to use the name without the module, just use the same class name:

@objc(Foobar)
class Foobar{

}

NSClassFromString("Foobar") will return the class Foobar.

Osmund
  • 772
  • 6
  • 13
0

This may be problem that your class have not extend from NSObject. As by default swift does not have superclass.

Rinku
  • 910
  • 13
  • 28
0

For example:

Just using UIViewController as an example,

func getVc(from stringName: String) -> UIViewController? {
    let appName = Bundle.main.infoDictionary!["CFBundleName"] as! String
    guard let vc = NSClassFromString(appName + "." + stringName) as? UIViewController.Type else {
        return nil
    }
    return vc.init()
}

If your App name contains "-" or number, just replace them with "_"

Cemal Eker
  • 1,266
  • 1
  • 9
  • 24
Jay Mine
  • 21
  • 1
  • 2