【问题标题】:Swift: test for expiration / invalidation of NSTimer seems to failSwift:测试 NSTimer 的过期/失效似乎失败了
【发布时间】:2023-04-04 07:05:01
【问题描述】:

使用 Swift,我很难测试 NSTimer 的到期/失效。

特别是,为什么像while timer1 != nil { }while timer1?.valid { } 这样的测试在看似明显无效并直接设置为nil 之后似乎没有逃脱空循环。

我已经复习了几个与 NSTimer 相关的问题,除非 Obj-C 中有一个版本,由于我对 ObjC 的理解很差,我根本不认为这是同一个问题,否则我不相信这一点被(直接)覆盖。

请注意,我不是要直接“修复”代码,而是要理解。

//  ViewController.swift
//  NSTimerTest


import UIKit

class ViewController: UIViewController {

    var z:Int = 0
    var timer1:NSTimer? = nil

    @IBOutlet var lblMessage: UILabel
    @IBOutlet var lbl2: UILabel
    @IBAction func btnPress(sender: AnyObject) {
        doBtnPress()
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        z = 0
        lblMessage.text = "Timer was called \(z) times."
        lbl2.text = "waiting for countdown"

    }


    func doBtnPress(){
        lblMessage.text = "doBtnPress!!"
        timer1 = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "doTimedAction", userInfo: nil, repeats: true)

        // All of the below infinitely loop 
        // while timer1?.valid { }  // <=== never escapes, also depreciated in IOS 8.0 ???
        // while timer1 { }       // <==== never escapes
        // while timer1 != nil { } // <==== never escapes 
        // while z >= 0 { }       //  <==== test counter instead, but no use 


        lbl2.text = "timer has been invalidated"
    }

    func doTimedAction(){
        lblMessage.text = "Timer was called \(++z) times."

        if z >= 10 {
            timer1?.invalidate()
            timer1 = nil
            z = -1      
        }

    }     
}

如您所见,我有两个标签 - 一个简单地更新为 NSTimer 被调用的次数,另一个在我使计时器无效后更新。

如上所述,测试行被注释掉后,事情就按我的预期工作了。指示定时器调用次数的标签每秒(或左右)更新一次,并立即但实际上不正确地显示“定时器已失效”的语句)

但是,我希望取消注释后面的三行中的任何一行应该允许计时器运行 10 次迭代,然后失效,从而允许显示“计时器无效”消息。然而,相反,我最终无限地陷入了空循环,好像条件永远不会成真。 UI 根本没有更新。

除了测试计时器之外,我还尝试测试计数器 z,但这也不起作用,这让我相信还有一些我不理解的更基本的东西在起作用。例如,在位置中使用while z &gt;= 0 { println("z is \(z)")} 会导致z is 0——循环无限的原因。但同样,如果我注释掉这一行,z 实际上确实会增加,因为标签确实发生了变化,反映了柜台 z 中的手杖。

再次,我希望更多地了解为什么事情会失败(即我在这里无法理解的内容)。我知道,例如,我可以通过让 doTimedAction() 函数直接更新标签来使这个“工作”——但这无助于我理解为什么我的测试失败。

【问题讨论】:

    标签: timer swift nstimer


    【解决方案1】:

    当您在循环中时,您正在阻止计时器触发,因为计时器和循环都在同一个线程上。

    查看Run Loops 上的文档,以及this post 关于在后台线程上创建NSTimer 的文档。

    【讨论】:

    • 你能解释一下吗?当 while 循环不存在(注释掉)时,计时器确实每 1 秒触发一次,并且 z 递增。同时,标签会立即更新(不会延迟显示)。在我看来,这似乎表明 NSTimer 在它自己的线程上,调用 doTimedAction。好的,现在让我们在 z >= 0 {} 时实现。我希望这会阻止下一行被击中,但与此同时,还没有实现 timer1 并设置为触发,因此增加 z 并最终允许我们退出循环,10 次迭代 l 之后当 z 设置为 -1 ...
    • ... 在这种情况下,阻塞计时器是什么意思。循环阻塞了怎么办?
    • 好吧,冒着过于简单化的风险,当程序正在执行你的 while 循环时,同一个程序中的其他任何东西都不能执行,除非它在不同的线程上(并且计时器是't)。请参阅关于运行循环的答案中的新评论。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-15
    • 1970-01-01
    • 1970-01-01
    • 2018-09-06
    • 2020-08-08
    • 2015-11-26
    相关资源
    最近更新 更多