我有一个类,该类派生自具有属性的基类。
@interface TestProp: NSObject
@property (nonnull, nonatomic) NSString *prop;
@end
@interface TestBase: NSObject
@end
@interface TestClass: TestBase
- (nullable TestProp *)testGetter;
- (void)testSetter:(nullable TestProp *)test;
@property (nullable, nonatomic, readonly, getter=testGetter) TestProp *test;
@end
@implementation TestProp
@end
@implementation TestBase
@end
@implementation TestClass { TestProp *_test; }
- (TestProp *)testGetter { return _test; }
- (void)testSetter:(TestProp *)test { _test = test; }
@end
我编写了一个快速扩展,以使该属性在基类中可用。
extension TestBase {
var test: TestProp? {
guard let testClass = self as? TestClass else { return nil }
return testClass.test
}
}
问题是testClass.test
从TestBase
而不是TestClass
调用吸气剂。这将导致无限递归,从而破坏堆栈。
这是缺陷吗?有什么方法可以使它正常工作吗?
更新
当我第一次想到它时,我希望可以将其视为一个函数。
extension TestBase {
var test: TestProp? {
return nil
}
}
会发生以下情况:
func callback(_ testBase: TestBase) {
guard let prop = testBase.prop else { return }
…
}
callback(TestBase()) // uses TestBase.prop
callback(TestClass()) // uses TestClass.prop
那没有用。实际行为是
callback(TestBase()) // uses TestBase.prop
callback(TestClass()) // uses TestBase.prop
属性不能像功能一样工作。所以扩展名
extension TestBase {
var test: TestProp? {
guard let testClass = self as? TestClass else { return nil }
return testClass.test
}
}
是我试图强制使用TestCase.prop
。
我正试图避免
func callback(_ testBase: TestBase) {
guard let prop = (testBase as? TestClass)?.prop else { return }
…
}
最终更新
我发现了一种有效的方法,如果您有兴趣,请参阅我的答案。
但是,这不值得。解决方案太复杂了。我创建了一个私有的全局函数。
private func prop(_ testBase: TestBase) -> TestProp {
return (testBase as? TestClass)?.prop
}
然后在回调中
func callback(_ testBase: TestBase) {
guard let prop = prop(testBase) else { return }
…
}
不是面向对象的,而是简单的。
答案 0 :(得分:2)
撇开代码“闻起来”的事实(从超类引用子类,将属性添加到子类,然后在扩展中添加到基类,而不是直接在基类上添加属性-在一个超类),这是因为Swift和其他许多编程语言一样都是静态调度的,这意味着它将急切地将方法调用(在这种情况下为getter)解析为固定的内存地址。
这导致Swift将基类中的getter地址解析为一个地址,因为扩展中声明的内容不可覆盖:Overriding methods in Swift extensions,http://blog.flaviocaetano.com/post/this-is-how-to-override-extension-methods/。
这就是为什么您获得无限递归的原因。
解决方案很简单,在基类中声明属性,在基类中返回nil并在子类中返回实际属性。
答案 1 :(得分:0)
感谢@Cristik的静态与动态调度技巧,我设法使其正常工作。
protocol TestBaseProp {
var test: TestProp? { get }
}
extension TestBaseProp {
var test: TestProp? {
guard let testClass = self as? TestClass else { return nil }
return testClass.test
}
}
extension TestBase: TestBaseProp { }
注意:我尝试过
extension TestBaseProp {
var test: TestProp? { return nil }
}
但这没用。