无法为泛型类型的子类调用初始化程序 [英] Unable to call initializer for subclass of generic type

查看:74
本文介绍了无法为泛型类型的子类调用初始化程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新:问题和标题已根据针对初始问题所做的更改进行了重新说明。




我有一个基类实现了创建新实例的泛型类方法。这个类方法的简化逻辑如下所示:

  class MyBaseClass {

required init(_ record :MyRecordType){
println(Entered MyBaseClass.init)
//从记录初始化基类
}
$ b $ class func retrieveInstance< T:MyBaseClass>( name:String,callback:(T) - >()){
let myRecord:MyRecordType = ... //执行fetch获取名称
的记录let result =(T.self as T.Type)(myRecord)//当前代码在BAD_ACCESS这一行中崩溃
回调(结果)
}
}

然后用这样的逻辑实现这个基类的一个子类:
$ b $ pre $ $ $ $ c> class MySubClass:MyBaseClass {

需要init(_ record:MyRecordType){
println(Entered MySubClass.init)
//从记录$ b $初始化子类b super.init(记录)
}
}

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

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

在创建类的实例时 - 标有注释的行标识了崩溃位置 - 我期待init方法从 MySubClass 调用。 (这个奇数表示法是基于回复中提出的错误解决方法)



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

解决方案

答案最初由@rintaro发布,我能解决这个问题,但仍然有一个奇怪的问题,我将在一个单独的问题下发布。



事实证明,使用以下语法初始化泛型类型的实例时,@ printaro是绝对正确的:

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

只要基类 MyBaseClass 使用所需的标记声明此初始化器:

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

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

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

如果事情失败了,但是当我实际上有一个3级的类层次结构并且初始化程序层次结构通过重写进入混音。想象一下,考虑一组代表树状结构中的节点的类:

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

public class RootNode:Node {
覆盖public init(_ record: (成功:(T) - >()MyAcceptType){
...
super.init(记录)
}
public class func< T:RootNode> retrieveAll ){
//检索根节点子类T的所有实例,并用新的T实例
}
}

调用成功回调函数public class ChildNode:Node {
public init(_ record:MyRecordType,parentNode:Node){
...
super.init(record)
}
public class func< T:ChildNode> ; retrieveChildren(parent:Node,success:(T) - >()){
//检索父节点的所有子T实例,并用新T实例调用成功回调
{
}

执行 RootNode 类的 retrieveAll 方法时会出现问题。为了使它像@rintaro所描述的那样工作,我需要在 RootNode 中的 init 标记为必填关键字。但是因为它也覆盖了 Node 的初始值设定项,所以它也需要覆盖关键字。所以我尝试在声明中使用这两个关键字:

 覆盖必需的公共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 可以正确地实现所需的初始化程序,并且 retrievev RootNode 中的eAll 方法可以正确地实例化这些子类的实例。


UPDATE: Question and title have been restated based on changes that were made in response to the initial question.


I've got a base class that implements a generic class method for creating new instances. The simplified logic of this class method is as follows

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)
    }
}

I then implement a subclass of this base class with logic like the following

class MySubClass : MyBaseClass {

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

Next, I try to invoke the generic class method

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

When creating an instance of the class - the line marked with a comment identifying the crash location - I am expecting the init method from MySubClass to be invoked. (This odd notation is based on the bug workaround suggested in the replies)

Instead of calling the init method for MySubClass, this code crashes with a BAD_ACCESS. I have been unable to find any nil references or anything else that would explain this crash.

解决方案

With a lot of help from the answer originally posted by @rintaro, I was able to solve this problem, although there is still an oddity that I will post under a separate question.

As it turns out, @rintaro was absolutely correct in the need to initialize the instance of the generic type using the following syntax:

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

This works as long as the base class MyBaseClass declares this initializer with a required tag:

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

and the subclass MySubClass implements the matching initializer:

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

Where things fail, however is when I actually have a 3-level class hierarchy and the initializer hierarchy throughs an override into the mix. To envision this, consider a set of class that represents nodes in a tree structure:

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
    {
}

The problem occurs in the implementation of the RootNode class's retrieveAll method. In order for it to work as described by @rintaro, I need the init in RootNode to be marked with the required keyword. But because it also overrides the initializer from Node, it also needs to have the override keyword. So I try to use both keywords in the declaration:

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

The Swift compiler accepts this, but when I use it to initialize an instance from within the retrieveAll method, it crashes with a BAD_ACCESS.

I was able to work around this problem by changing the method signature of the NodeClass just slightly so that its RootNode subclass doesn't need to override:

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

By doing this workaround, my subclasses of RootNode can properly implement the required initializer, and the retrieveAll method in RootNode can properly instantiate instances of those subclasses.

这篇关于无法为泛型类型的子类调用初始化程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆