Swift 3:Convenience Initializer扩展基金会'计时器'挂起

时间:2016-12-24 19:48:11

标签: swift timer swift3 initializer convenience-methods

我试图在Swift 3中扩展Foundation的MSVCR120.DLL类,添加了一个便利初始化器。但它对基金会提供的初始化程序的调用永远不会返回。

这个问题在以下简单的演示中说明,该演示可以作为Playground运行。

Timer

控制台输出:

Next statement never returns

进一步研究,

•我编写了类似的代码扩展import Foundation extension Timer { convenience init(target: Any) { print("Next statement never returns") self.init(timeInterval: 1.0, target: target, selector: #selector(Target.fire), userInfo: nil, repeats: true) print("This never executes") } } class Target { @objc func fire(_ timer: Timer) { } } let target = Target() let timer = Timer(target: target) (使用实例初始化程序的其他基础类之一)。结果:没问题。

•为了消除Objective-C的原因,我将包装的初始化程序更改为URLProtocol方法并提供了Swift闭包。结果:同样的问题。

3 个答案:

答案 0 :(得分:4)

我实际上并不知道答案,但我在实际应用程序中运行此操作时看到调试器存在无限递归(因此挂起)。我怀疑这是因为你实际上并没有调用Timer的指定初始化器。这个事实并不明显,但是如果你尝试子类化Timer并调用super.init(timeInterval...)编译器会抱怨,并且标题中super.init(timeInterval...)上还有一个奇怪的“未继承”标记。

我可以通过调用self.init(fireAt:...)来解决此问题:

extension Timer {
    convenience init(target: Any) {
        print("Next statement never returns") // but it does
        self.init(fireAt: Date(), interval: 1, target: target, 
            selector: #selector(Target.fire), userInfo: nil, repeats: true)
        print("This never executes") // but it does
    }
}

准备好你会...

答案 1 :(得分:2)

我看到与无限递归的matt所描述的相同的问题。 -[NSCFTimer release]在同一个对象上反复调用。通过从实例初始化程序中调用类初始化程序,可以在纯Objective-C中重现此行为。

@implementation NSTimer (Foo)

- (instancetype)initWithTarget:(id)t {
    return [NSTimer timerWithTimeInterval:1 target:t selector:@selector(description) userInfo:nil repeats:NO];
}

@end

编译器抱怨指定的初始化程序没有被调用,这似乎与修复问题有关,但没有解释递归调用。

warning: convenience initializer missing a 'self' call to another initializer

答案 2 :(得分:0)

@matt的答案有效。

是的,我在我的应用程序中也看到了无限递归 - CFReleases。 Swift书很清楚便利初始化器必须调用指定的初始化器。但是,并没有说出惩罚是什么。无限递归虽然令人惊讶,但似乎是合理的。

但是,请查看这两个声明,您可以通过选择单击或命令单击Xco​​de中的其中一个方法来查看这些声明:

init(timeInterval interval: TimeInterval, repeats: Bool, block: @escaping (Timer) -> Void)

convenience init(fire date: Date, interval: TimeInterval, repeats: Bool, block: @escaping (Timer) -> Void)

我觉得那里有些不对劲。 @matt建议的函数,附加的(" fire")参数解决了我的问题,标记为 convenience 。我使用的功能,标记便利,我认为(作为一个Swift新手)是指定的。但它只有一个参数。咦?

我想我会提交一个错误,指出 Apple在错误的功能上以某种方式获得便利关键字。这可能是因为Swift真的没有头文件,对吗?所以我想知道当我们选择点击基础功能时我们会看到什么。可能他们的工作流程中有一个步骤容易出现人为错误?