【问题标题】:How to avoid "variable was written to, but never read" warning with a timer in Swift如何在 Swift 中使用计时器避免“变量已写入,但从未读取”警告
【发布时间】:2016-10-24 19:49:41
【问题描述】:

我正在使用此代码来延迟 tableView 的出现/消失。

    var timer = NSTimer()
    let delay = 0.5
    timer = NSTimer.scheduledTimerWithTimeInterval(delay, target: self, selector: #selector(delayedHideTableView), userInfo: nil, repeats: false) // Warning: Variable 'timer' was written to, but never read

也许我对 timer 变量做错了什么,如何避免这个错误?我知道我可以使用 print(timer) 语句,但我认为这不是最佳做法。

【问题讨论】:

    标签: swift timer warnings var


    【解决方案1】:

    当类被deinit或视图被移除时,一定要记得使定时器失效,否则会导致以后难以找到的内存崩溃。

    所以只需添加:

    deinit {
      self.timer.invalidate()
    }
    

    在你的课堂上。

    由于没有 deinit 计时器、观察者等,我已经看到了很多奇怪的错误。所以要养成一个好习惯。

    【讨论】:

    • 实际上NSTimer 将保留其目标(并且运行循环保留计时器),因此只要计时器处于活动状态,就永远不会调用deinit。您需要在对象生命周期中的适当时间手动调用invalidate()。虽然在这种情况下 OP 的计时器不会重复 - 所以目标只会被保留直到它被触发。
    • 有趣的是,我在重复计时器上做了很多工作,但在非重复计时器上工作的很少。所以我不确定在这种情况下它是否重要。只是好奇,如果定时器被初始化,然后 tableView 以某种方式从 superview 中删除,然后定时器被触发,这会导致任何问题吗?当 tableView 是否仍在内存中时。
    • 只要目标处于活动状态,计时器就会一直保留它,因此即使您没有对给定目标的引用 - 计时器也会这样做。正如您所说,这正是为了防止尝试调用 deallocat(ed/ing) 对象上的方法而导致的问题。如果您正在寻找避免这种行为的方法,请查看CFRunLoopTimer - 它可以将闭包作为回调而不是目标和选择器。
    • @originaluser2 很高兴听到这个消息,我认为那些高级语言应该自动处理这些东西。但是,在我没有取消重复计时器之前,我确实发生了崩溃,这花费了我很多时间来调试。所以我不太明白你说的“只要目标处于活动状态,计时器就会保持目标”。我错过了什么吗?
    • 不看你的代码,我不能说问题是什么——但我向你保证NSTimer 保留了它的目标:) 看看target 参数的描述@ 987654321@
    【解决方案2】:

    在您的代码中存在一些问题:

    1. 您将 timer 声明为一个变量,您正在使用 NSTimer() 填充它,并且下面的 2 行将覆盖该值。那么,为什么首先将NSTimer 分配给timer

    2. 如果您不使用NSTimer.scheduledTimerWithTimeInterval(...) 返回的值,为什么要将其保存到timer

    3. 最后,要使用选择器将方法调用到不继承 NSObject 的类中,您应该使用 @objc 公开该方法。

    4. #selector 的正确语法是 #selector(ClassName.methodName)

    所以

    class Foo {
    
        func foo() {
            let delay = 0.5
            NSTimer.scheduledTimerWithTimeInterval(delay, target: self, selector: #selector(Foo.delayedHideTableView), userInfo: nil, repeats: false)
        }
    
        @objc func delayedHideTableView() {}
    }
    

    【讨论】:

      【解决方案3】:

      在您的示例中,您根本不需要 NSTimer 的变量。所以你可以删除

      var timer = NSTimer()
      

      正如用户代码指出的那样,它已经在那里启动了一个计时器。所以如果你需要这个变量,你应该这样做

      var timer:NSTimer
      

      这不会启动计时器,而是将属性的类型设置为正确的类型。

      但对您的问题的简短回答是,您可以让代码看起来像这样:

      let delay = 0.5
      NSTimer.scheduledTimerWithTimeInterval(delay, target: self, selector: #selector(delayedHideTableView), userInfo: nil, repeats: false)
      

      警告就会消失。

      【讨论】:

        【解决方案4】:

        不要创建timer 变量,因为它不是必需的。只需执行以下操作:

        NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: #selector(delayedHideTableView), userInfo: nil, repeats: false)
        

        即使您不需要 delay 变量,除非它动态更改。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-04-05
          • 2015-12-13
          • 1970-01-01
          • 1970-01-01
          • 2010-10-21
          • 2012-05-27
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多