【发布时间】:2019-09-20 13:03:42
【问题描述】:
最后更新部分解决方案!
附加的是产生奇怪行为的代码。我从一个快速的操场上复制了它,所以它应该可以很好地运行。
我在我的项目中创建了一个子类,并将它作为具体类型传递给我的泛型类。但是,我很快注意到只调用了基类方法。这与下面的myBase 和mySub 一起显示。尽管泛型类被实例化为<mySub>,但只调用了基方法。子类的打印行从不显示。
好吧,我找到了一个简单的方法,那就是不从 NSObject 继承。当我使用 swift 本机类时,实际上调用了子类方法。它们是 secondBase 和 secondSub。
从 NSObject 继承时,如何将子类传递给泛型类并让实际的子类接收调用?
为什么行为会有所不同?
import Foundation
// The Protocol
protocol P {
init ()
func doWork() -> String
}
// Generic Class
class G<T: P> {
func doThing() -> String {
let thing = T()
return thing.doWork()
}
}
// NSObject Base Class with Protocol
class A1: NSObject, P {
override required init() {
super.init()
}
func doWork() -> String {
return "A1"
}
}
// NSObject Sub Class
class B1: A1 {
required init() {
super.init()
}
override func doWork() -> String {
return "B1"
}
}
// Swift Base Class
class A2: P {
required init() {
}
func doWork() -> String {
return "A2"
}
}
// Swift Sub Class
class B2: A2 {
required init() {
super.init()
}
override func doWork() -> String {
return "B2"
}
}
print ("Sub class failure with NSObject")
print ("Recieved: " + G<B1>().doThing() + " Expected: B1 - NSObject Sub Class Generic (FAILS)")
print ("\nSub class success with Swift Native")
print ("Recieved: " + G<B2>().doThing() + " Expected: B2 - Swift Sub Class Generic (SUCCEEDS)")
print("")
#if swift(>=5.0)
print("Hello, Swift 5.0")
#elseif swift(>=4.1)
print("Hello, Swift 4.1")
#elseif swift(>=4.0)
print("Hello, Swift 4.0")
#elseif swift(>=3.0)
print("Hello, Swift 3.x")
#else
print("Hello, Swift 2.2")
#endif
输出:
Sub class failure with NSObject
Recieved: A1 Expected: B1 - NSObject Sub Class Generic (FAILS)
Sub class success with Swift Native
Recieved: B2 Expected: B2 - Swift Sub Class Generic (SUCCEEDS)
Hello, Swift 5.0
部分解决方案更新:
将协议一致性从基类移动到子类允许子类正确运行。定义变为:
class A1: NSObject
class B1: A1, P
问题是当不需要超出它的功能时,根本不能直接使用基类。如果要遵守的协议具有关联的类型,这主要是一个问题。如果这是真的,您必须有一个符合泛型使用协议的具体类。
这里的一个用例是期望泛型中的基类(具有涉及关联类型的协议),它允许某些东西在不关心传入的实际子类的情况下运行。这实际上最终成为穷人的类型形式在某些情况下擦除。您仍然可以在子类中使用相同的泛型。
G<A1>()
G<B1>()
这来自一个类似的问题:Generic Class does not forward delegate calls to concrete subclass
部分选项是:
- 删除 NSObject 并仅使用 swift 本机类
- 当需要 NSObject 时,尝试将协议一致性与 NSObject 继承分离
更新以下想法:不起作用
我将测试提供额外的层是否会改变行为。基本上有 3 层,从 NSObject 继承的基类,添加协议但从基类和然后特定类继承的基协议类。如果它可以在这种情况下区分基本协议类和特定子类,那么这将是所有用例中的一种功能性解决方法。 (并且可以解释为什么 Apple 的 NSManagedObject 可以正常工作)
不过看起来还是个 bug。
【问题讨论】:
-
无论是否从
NSObject继承基类,我都看不到子类方法调用行为的任何问题。 -
对我来说,当使用在线 swift playground 和 swift 5.0 运行代码时,这会正确打印(如您所料)。也许您需要再试一次或重新启动 Xcode 或其他东西。投票结束。
-
现在这很有趣。可以试试早期版本的 swift 吗?
-
这发生在 swift 游乐场和我的两个项目中。 Playground 是 swift 5。项目是 swift 4.2(我认为,会仔细检查,肯定不会转换为 5)。重新启动 Xcode。将重新启动我的计算机。 Xcode:版本 10.2.1 (10E1001)
-
重启没有帮助。关于下一步尝试什么的任何想法?
标签: swift generics inheritance