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

Tim*_*ean 6 generics swift

更新:问题和标题已根据对初始问题作出的更改进行了重述.


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

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,我使用如下所示的逻辑实现此基类的子类

class MySubClass : MyBaseClass {

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

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

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

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

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

Tim*_*ean 5

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

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

let result = (T.self as T.Type)(myRecord)
Run Code Online (Sandbox Code Playgroud)

只要基类MyBaseClass使用required标记声明此初始化程序,这就可以工作:

public class MyBaseClass {
    public required init(_ record:MyRecordType) {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

子类MySubClass实现匹配的初始化器:

public class MySubClass : MyBaseClass {
    public required init (_ record:MyRecordType) {
        ...
        super.init(record)
    }
}
Run Code Online (Sandbox Code Playgroud)

然而,当事情失败时,我实际上有一个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
    {
}
Run Code Online (Sandbox Code Playgroud)

问题发生在RootNode类的retrieveAll方法的实现中.为了使它像@rintaro所描述的那样工作,我需要用initin RootNode标记required关键字.但是因为它也覆盖了初始化器Node,所以它还需要有override关键字.所以我尝试在声明中使用两个关键字:

override required public init(_ record:MyRecordType) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

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