Swift 无法为泛型类型的子类调用初始值设定项
更新:问题和标题已根据回应初始问题所做的更改进行了重述Swift 无法为泛型类型的子类调用初始值设定项,swift,generics,Swift,Generics,更新:问题和标题已根据回应初始问题所做的更改进行了重述 我有一个基类,它实现了创建新实例的泛型类方法。该类方法的简化逻辑如下 class MyBaseClass { required init(_ record:MyRecordType) { println("Entered MyBaseClass.init") // Initialize base class from record } class func retrieveIns
我有一个基类,它实现了创建新实例的泛型类方法。该类方法的简化逻辑如下
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 AnotherClass {
func successCallback(result:MySubclass) {
// Handle callback
}
MySubClass.retrieveInstance("objectName", callback:successCallback)
}
在创建类的实例时(用标识崩溃位置的注释标记的行),我希望调用MySubClass
中的init方法。(这种奇怪的表示法基于回复中建议的bug解决方法)
此代码不是为
MySubClass
调用init
方法,而是由于访问错误而崩溃。我一直找不到任何零引用或任何其他可以解释这次崩溃的东西。在@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)
}
}
然而,失败的地方是,我实际上有一个三级类层次结构,初始化器层次结构通过一个覆盖进入混合。要设想这一点,考虑一组表示树结构中节点的类:
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
{
}
Swift编译器接受这一点,但当我使用它从retrieveAll
方法中初始化实例时,它会因访问错误而崩溃
我可以通过稍微更改NodeClass
的方法签名来解决这个问题,这样它的RootNode
子类就不需要重写:
public class Node {
public init(record:MyRecordType) {
...
}
}
public class RootNode {
public required init(_ record:MyRecordType) {
...
super.init(record:record)
}
}
通过这样做,我的RootNode
子类可以正确地实现所需的初始值设定项,而RootNode
中的retrieveAll
方法可以正确地实例化这些子类的实例。我无法重现错误的访问。我假设您正在使用某个异步调用,可能问题就在那里。@rintaro-我终于能够找出问题所在。事实证明,它与异步无关,而是与混合重写的初始值设定项和所需的初始值设定项有关(我将在下面发布完整的描述)。因为你的答案至少让我指出了正确的方向,我想在这里给你正确的答案,但你似乎已经删除了你的答案。如果您想让我感谢您的帮助,请随时重新发布。一旦您在基类和子类上添加了所需的初始值设定项,您就可以使用T()
@seanwoodward-不幸的是,这似乎不是真的。当我使用T(myRecord)调用初始值设定项时,它失败了,当我按照rintaro建议的方式调用它时。T(myRecord)的失败似乎是因为在获取实例的“record”属性时发生了错误的访问异常,该属性本应设置为传入的“myRecord”值。感谢您注意到这一点。对泛型初始值设定项T()
的调用在简单测试中对我有效。我希望这些问题能在编译器的未来版本中得到解决。据我所知,init函数必须有“必需”的说明符,否则它将无法工作。
override required public init(_ record:MyRecordType) {
...
}
public class Node {
public init(record:MyRecordType) {
...
}
}
public class RootNode {
public required init(_ record:MyRecordType) {
...
super.init(record:record)
}
}