Swift 3:方便的初始值设定项扩展基础&x27;s';定时器';悬挂
我试图在Swift 3中扩展Foundation的Swift 3:方便的初始值设定项扩展基础&x27;s';定时器';悬挂,swift,timer,swift3,initializer,convenience-methods,Swift,Timer,Swift3,Initializer,Convenience Methods,我试图在Swift 3中扩展Foundation的Timer类,添加一个方便的初始值设定项。但它对基金会提供的初始值设定项的调用从未返回 这个问题在下面的演示中得到了说明,它可以作为一个游乐场运行 import Foundation extension Timer { convenience init(target: Any) { print("Next statement never returns") self.init(timeInterval:
Timer
类,添加一个方便的初始值设定项。但它对基金会提供的初始值设定项的调用从未返回
这个问题在下面的演示中得到了说明,它可以作为一个游乐场运行
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)
控制台输出:
Next statement never returns
下一个语句永远不会返回
进一步研究,
<> >我编写了类似的代码扩展<代码> URLPrase(使用实例初始化器的唯一其他基础类之一)。结果:没问题
•为了消除Objective-C内容作为可能的原因,我将包装的初始值设定项更改为
init(timeInterval:repeats:block:)
方法,并提供了快速关闭。结果:同样的问题。我实际上不知道答案,但我在一个实际的应用程序中使用调试器运行这个程序时发现存在无限递归(因此挂起)。我怀疑这是因为你实际上没有调用计时器的指定初始值设定项。这一事实并不明显,但是如果您尝试将Timer子类化并调用super.init(timeInterval…
,编译器会抱怨,并且在头中的super.init(timeInterval…
上有一个奇怪的“not inheritable”标记
我可以通过调用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
}
}
你要做的就是…我看到了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
@matt的答案很有效 是的,我在我的应用程序中也看到了无限递归——CFReleases。Swift手册明确指出,方便初始值设定者必须调用指定的初始值设定者。但它没有说明惩罚是什么。一个无限递归,虽然令人惊讶,但似乎是合理的 但是,请查看这两个声明,您可以通过在Xcode中单击其中一个方法的选项或命令来查看它们:
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”)参数,为我解决了这个问题,标记为方便。我使用的功能,没有标记方便,我想(作为一个敏捷的新手)因此被指定。但它少了一个参数。嗯
我想我应该提交一个bug,说明苹果不知何故在错误的函数上获得了便利关键字。这可能是因为Swift确实没有头文件,对吗?所以,当我们选择点击一个基础函数时,我们想知道我们看到了什么。可能他们的工作流程中有一个步骤容易出现人为错误?Swift手册中说规则2:一个方便的初始值设定项必须调用同一类中的另一个初始值设定项。规则3:方便的初始值设定项必须最终调用指定的初始值设定项。规则不禁止便利初始值设定项调用同一类的另一个便利初始值设定项。在其他类中,定义一个方便初始值设定项调用另一个方便初始值设定项实际上是可行的。因此,您应该随原始问题一起发送错误报告<代码>计时器是一种特殊情况。如何显示生成的标题是一件微妙的事情,将被忽略。您是对的,@OOPer。所有初始值设定者最终都应该调用指定的初始值设定者,所以只要我的方便初始值设定者调用另一个初始值设定者,无论是否指定,它都应该工作。我现在已经在原始版本上提交了Apple Bug Reporter问题ID 29804952。在附加说明中,我问函数X的参数如何比函数Y少一个,但函数Y是一个标记方便的参数。谢谢大家。标题中的“not Inheritable”标记表示它不能用作子类的初始化器,因为它是从Obj-C工厂方法(
timerWithTimeInterval:target:selector:userInfo:repeats:
)导入的,该方法只返回NSTimer
实例(因此不能用于创建子类实例)。虽然我不明白为什么这会使它无限递归(不能用我自己的Obj-C工厂方法进行复制),但是它可能是NSTimer
实现中的某个东西在执行它。最奇怪的是。