无法为泛型类型的子类调用初始化程序 [英] Unable to call initializer for subclass of generic type
问题描述
更新:问题和标题已根据针对初始问题所做的更改进行了重新说明。
我有一个基类实现了创建新实例的泛型类方法。这个类方法的简化逻辑如下所示:
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屋!