简体   繁体   中英

Swift Initializer by Class Name causes Error: Class is of type "Protocol"

I have the following 2 classes and a protocol: WeatherFacade and WeatherObject, which is of type of the protocol ModelObjects (WeatherObject conforms to ModelObjects and is type ModelObjects). I want to create an instance of the WeatherObject by it's name but I get error:

'init' is a member of the type; use 'type(of: ...)' to initialize a new object of the same dynamic type

The WeatherFacade class consists of a Networking Class and a WeatherObject properties and init like so:

let networking: Networking
let model: ModelProtocol

init(model: String) {
    self.networking = Networking()


    let namespace = Bundle.main.infoDictionary!["CFBundleExecutable"] as! String

    let className: ModelProtocol = NSClassFromString("\(namespace).\(model)") as! ModelProtocol

    self.model = className.init()//error here
}

ModelProtocol looks like this

protocol ModelProtocol{

    func parse<T: Decodable>(data: Data) throws -> Array<T>?

}

WeatherObject is nothing at this point, just a classname that conforms to ModelProtocol like so:

class WeatherModel: NSObject, ModelProtocol {}

The class in question uses the standard init() . How can I get an instance of my WeatherObject by passing in the name?

This line:

class WeatherModel: NSObject, ModelProtocol {}

causes error. You should better try to show enough code to reproduce your issue.


Anyway, you have two major problems.

First, this declaration let className: ModelProtocol declares className as an instance conforming to the protocol ModelProtocol . It's not the declaration for a type.

Second, there is no default initializer in Swift. When you want to call init() on a type variable conforming to a protocol, the protocol needs to declare init() .

So, your protocol should be something like this:

protocol ModelProtocol{

    func parse<T: Decodable>(data: Data) throws -> Array<T>?

    init()

}

You need to add required initializer to conform to it:

class WeatherModel: NSObject, ModelProtocol {

    func parse<T: Decodable>(data: Data) throws -> Array<T>? {
        //...
        return [/*...*/]
    }

    override required init() {
        super.init()
    }
}

And then, you can write something like this:

init(model: String) {
    self.networking = Networking()

    let namespace = Bundle.main.infoDictionary!["CFBundleExecutable"] as! String

    let classType: ModelProtocol.Type = NSClassFromString("\(namespace).\(model)") as! ModelProtocol.Type

    self.model = classType.init()
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM