无法为泛型类型的子类调用初始值设定项

时间:2014-11-25 02:39:14

标签: swift generics

更新:问题和标题已根据对初始问题的回复进行了重述。


我有一个基类,它实现了用于创建新实例的泛型类方法。该类方法的简化逻辑如下

class MyBaseClass {

    required init(_ record:MyRecordType) {
        println("Entered MyBaseClass.init")
        // Initialize base class from record
    }

    class func retrieveInstance<T:MyBaseClass>(name:String, callback:(T) -> ()) {
        let myRecord:MyRecordType = ... // Perform fetch to get a record for name
        let result = (T.self as T.Type)(myRecord) // Code currently crashes with BAD_ACCESS at this line
        callback(result)
    }
}

然后我实现了这个基类的子类,其逻辑类似于以下

class MySubClass : MyBaseClass {

    required init(_ record:MyRecordType) {
        println("Entered MySubClass.init")
        // Initialize subclass from record
        super.init(record)
    }
}

接下来,我尝试调用泛型类方法

class AnotherClass {
    func successCallback(result:MySubclass) {
        // Handle callback
    }
    MySubClass.retrieveInstance("objectName", callback:successCallback)
}

创建类的实例时 - 标有标记崩溃位置的注释的行 - 我期望调用MySubClass的init方法。 (这种奇怪的符号基于回复中建议的错误解决方法)

此代码不是为init调用MySubClass方法,而是使用BAD_ACCESS崩溃。我一直无法找到任何可以解释此崩溃的零引用或其他任何内容。

1 个答案:

答案 0 :(得分:5)

在@rintaro最初发布的答案中得到了很多帮助,我能够解决这个问题,尽管我会在一个单独的问题上发布一些奇怪的内容。

事实证明,使用以下语法初始化泛型类型的实例需要@rintaro是完全正确的:

let result = (T.self as T.Type)(myRecord)

只要基类MyBaseClass使用required标记声明此初始值设定项,此方法就有效:

public class MyBaseClass {
    public required init(_ record:MyRecordType) {
        ...
    }
}

,子类MySubClass实现了匹配的初始值设定项:

public class MySubClass : MyBaseClass {
    public required init (_ record:MyRecordType) {
        ...
        super.init(record)
    }
}

当事情失败的时候,当我实际上有一个3级的类层次结构并且初始化程序层次结构通过override进入混合时。要想象这一点,请考虑一组表示树结构中节点的类:

public class Node {
    public init(_ record:MyRecordType) {
       ...
    }
}

public class RootNode : Node {
    override public init(_ record:MyRecordType) {
        ...
        super.init(record)
    }
    public class func <T:RootNode>retrieveAll(success:(T) -> ()) {
        // Retrieve all instances of root node subclass T, and invoke success callback with new T instance
    }
}

public class ChildNode : Node {
    public init(_ record:MyRecordType, parentNode:Node) {
        ...
        super.init(record)
    }
    public class func <T:ChildNode>retrieveChildren(parent:Node, success:(T) -> ()) {
        // Retrieve all child T instances of parent node, and invoke success callback with new T instance
    {
}

问题出现在RootNoderetrieveAll方法的实现中。为了使其能够像@rintaro所描述的那样工作,我需要init中的RootNode标记required关键字。但是因为它还覆盖了Node的初始值设定项,所以它还需要override个关键字。所以我尝试在声明中使用这两个关键字:

override required public init(_ record:MyRecordType) {
    ...
}

Swift编译器接受这个,但是当我使用它来从retrieveAll方法中初始化一个实例时,它会崩溃并发生BAD_ACCESS。

我能够通过稍微更改NodeClass的方法签名来解决此问题,以便其RootNode子类不需要覆盖:

public class Node {
    public init(record:MyRecordType) {
        ...
    }
}
public class RootNode {
    public required init(_ record:MyRecordType) {
        ...
        super.init(record:record)
    }
}

通过执行此解决方法,我的RootNode子类可以正确实现所需的初始化程序,retrieveAll中的RootNode方法可以正确地实例化这些子类的实例。

相关问题