0

I have my custom class in extension UIImage like this

extension UIImage {   
    class AssetItem: NSObject {
    }
}    

when I try get class from NSClassFromString like this

NSClassFromString("UIImage.AssetItem")

I receive nil. How I can do it? I need get it class from String.


actually I try to do a tree with names, for can get exec like it NavigationBar.additionMenu and receive string "NavigationBar.additionMenu".

protocol EIAssetRoot {
}

protocol EIAssetFolder {
    static func name(_ key: String) -> String
}

extension EIAssetFolder {

    static func name(_ key: String = #function) -> String {
        let full = "\(String(reflecting: self)).\(key)"
        let lastSpace = full.components(separatedBy: ":").last ?? full
        let components = lastSpace.components(separatedBy: ".")
        var rootComponents = components
        var rootFounding = false
        repeat {
            rootComponents = rootComponents.dropLast()
            let name = rootComponents.joined(separator: ".")
            if let anyClass = NSClassFromString(name) {
                if anyClass is EIAssetRoot {
                    rootFounding = true
                }
            }
        } while rootComponents.count > 0 && rootFounding == false

        let keyComponents = components.dropFirst(rootComponents.count)
        let name = keyComponents.joined(separator: ".")
        return name
    }

}

extension UIImage {
    @objc class AssetItem: NSObject, EIAssetRoot {
        class NavigationBar: EIAssetFolder {
            static var additionMenu: String { get { return name() } }
            static var save: String { get { return name() } }
            static let toLeft: String { get { return name() } }
            static func toRight: String { get { return name() } }
        }
    }
}

this I try build string from class name and trunc first part to class EIAssetRoot

I don't like doing in by enum because it looks like .NavigationBar(.Menu(.SecondMenu(.additionMenu))) too meny ()

EvGeniy Ilyin
  • 1,817
  • 1
  • 21
  • 38

2 Answers2

1

You need to "unhide" AssetItem by moving it out of the UIImage extension and up to the top level. Objective-C can never "see" a nested type like UIImage.AssetItem — and NSClassFromString is Objective-C / Cocoa.

However, it would be even better to ask yourself why you need this. In Swift, an attempt to use NSClassFromString is first and foremost a Bad Smell. You are probably trying to do something here that can be done in a correct Swifty way, without involving Objective-C Cocoa at the back end. But you have not revealed what it is.

matt
  • 515,959
  • 87
  • 875
  • 1,141
0

You will have to access the class by an explicitly defined name like this. These symbols are defined in the global scope in Objective-C (so no .'s are allowed in the name):

extension UIImage {
    @objc(UIImageAssetItem)
    class AssetItem: NSObject {
    }
}

let cls = NSClassFromString("UIImageAssetItem")

rolling_codes
  • 15,174
  • 22
  • 76
  • 112