将Class.Type传递给函数Swift

时间:2017-05-12 21:43:21

标签: swift design-patterns architecture override factory-pattern

为一个项目的覆盖系统工作,该项目具有一个核心代码库,安装在带有子模块的客户端项目中,客户端特定的文件和覆盖存在于各自的项目中。

这是一个令人费解的设置,但是以这种方式设置架构有商业原因 - 即我们需要对核心项目进行更新,同时允许客户端对特定视图进行更改,控制器,模型 - 所以我们需要逐个客户端的灵活性。

我已经构建了一个覆盖系统,其工厂模式为99%。当我需要一个对象时,我通过调用它来实例化它:

let factory = Factory()    
let object = try factory.getObject(named: "MyObject", ofType: MyObject.self)

如果存在覆盖,工厂将实例化覆盖(例如:override_MyObject),否则它将实例化默认值(MyObject)。现在我只是坚持在Factory中对这些AnyObjects进行类型转换,以便它们能够运行init()。在这段代码中,我传递了一个泛型类型“T”,但是我无法在这里使用T来自getInstance:

let object = try getInstance(name: named) as? T

T是泛型类型,并且没有MyObject实例所做的init()方法。并且Swift不允许我传入MyObject.self并在as中引用该param?铸造声明。

这是操场上的完整源代码。它现在完全正常工作,因为我说的是? MyObject.Type而不是使用T来转换对象。我需要能够使用我传入getObject函数的类型来转换从getInstance返回的对象。

HELP!任何帮助非常感谢。

//: Playground - noun: a place where people can play

import UIKit

protocol TestProt {
    func testMe() -> String
}

@objc(MyObject)
class MyObject: NSObject, TestProt {
    func testMe() -> String {
        return "Hello from Base"
    }
    required override init() {

    }
}

@objc(override_MyObject)
class override_MyObject: MyObject {
    override func testMe() -> String {
        return "Hello from Override"
    }
    required override init() {

    }
}

class Factory {

    let overridePrefix: String = "override_"

    private func getInstance(name: String) throws -> AnyClass {

        do {
            let object = try checkOverride(name)
            return object
        } catch {
            throw FactoryError.defaultError
        }

    }

    public func getObject<T>(named: String, ofType: T.Type) throws -> AnyObject {
        do {
            let object = try getInstance(name: named) as? MyObject.Type
            if let dynamicObject = object?.init() {
                dynamicObject.testMe()
                return dynamicObject
            } else {
                throw FactoryError.defaultError
            }
        }
        catch {
            throw FactoryError.defaultError
        }
    }

    func checkOverride(_ className: String) throws -> AnyClass {

        let overrideClassName = overridePrefix + className

        if let object = NSClassFromString(overrideClassName) {
            print("\(overrideClassName) does exist")
            return object

        } else if let object = NSClassFromString(className) {
            print("\(className) does exist")
            return object

        } else {
            print("\(overrideClassName) does not exist")
            throw FactoryError.defaultError
        }
    }

    enum FactoryError: Error {
        case defaultError
    }

}

let factory = Factory()
let object = try factory.getObject(named: "MyObject", ofType: MyObject.self)
object.testMe()

3 个答案:

答案 0 :(得分:0)

不确定你想要实现什么,但考虑重新评估你的解决方案,这是非常糟糕的代码。如果这是你想要实现的目标,那么这可能是你的解决方案。

public func getObject<T: MyObject>(named: String, ofType: T.Type) throws -> AnyObject {
    do {
        let object = try getInstance(name: named) as? T.Type
        if let dynamicObject = object?.init() {
            dynamicObject.testMe()
            return dynamicObject
        } else {
            throw FactoryError.defaultError
        }
    }
    catch {
        throw FactoryError.defaultError
    }
}

答案 1 :(得分:0)

为什么不在您的协议中添加init?它大大简化了事情,任何类型的代码都是相同的。

 mph         80     75     70     65     60     55     50     45     40 etc..
 20            
 40
 50            5
 60                 
 80                                                     8      7       6
 90                                9      9
 100

答案 2 :(得分:0)

然后你的视图,视图控制器和模型应该与init()方法有共同的协议。在你的情况下,你被迫将NSObject作为你的基类。

在下面的解决方案中,我创建了一个名为BaseInitializable的协议,该协议由父类实现。查看getObject方法。

import UIKit

protocol BaseInitializable: class {
    func testMe() -> String
    init()
}

@objc(Parent)
class Parent: NSObject, BaseInitializable {


    func testMe() -> String {
        return "Hello from Base"
    }

    required override init() {
        super.init()
        print("parent constructor called")
    }

}

@objc(override_Child)
class override_Child: Parent {
    override func testMe() -> String {
        return "Hello from Override"
    }

    required init() {
        super.init()
        print("child constructor called")

    }
}

@objc(override_Cousin)
class override_Cousin: Parent {
     override func testMe() -> String {
        return "Hello from cousin Override"
    }

    required init() {
        super.init()
        print("cousin constructor called")

    }
}

class Factory {

    let overridePrefix: String = "override_"

    private func getInstance(name: String) throws -> AnyClass {

        do {
            let object = try checkOverride(name)
            return object
        } catch {
            throw FactoryError.defaultError
        }

    }

    public func getObject<T: BaseInitializable>(named: String, ofType: T.Type) throws -> AnyObject {
        do {
            let object = try getInstance(name: named) as? BaseInitializable.Type
            if let dynamicObject = object?.init() {
                dynamicObject.testMe()
                return dynamicObject
            } else {
                throw FactoryError.defaultError
            }
        }
        catch {
            throw FactoryError.defaultError
        }
    }

    func checkOverride(_ className: String) throws -> AnyClass {

        let overrideClassName = overridePrefix + className

        if let object = NSClassFromString(overrideClassName) {
            print("\(overrideClassName) does exist")
            return object

        } else if let object = NSClassFromString(className) {
            print("\(className) does exist")
            return object

        } else {
            print("\(overrideClassName) does not exist")
            throw FactoryError.defaultError
        }
    }

    enum FactoryError: Error {
        case defaultError
    }

}

let factory = Factory()
let object = try factory.getObject(named: "Child", ofType: Parent.self) 
object.testMe()