Swift 4 计时器因 NSException 崩溃 [英] Swift 4 Timer Crashes with NSException

查看:105
本文介绍了Swift 4 计时器因 NSException 崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在寻找一种在 Swift 4 中使用计时器的方法,并查看了 这篇 文章.我在 xcode 中测试了我的代码,当计时器第一次计时(在本例中为 10 秒后)时,应用程序崩溃并出现错误,尽管构建成功.

I've been searching for a way to use a Timer in Swift 4 and looked at this article. I test out my code in xcode and when the the timer first ticks (in this case after 10 seconds) the app crashes and I get an error, although the build succeeded.

2017-11-20 19:54:42.781502-0700 Rock Prodigy[3022:554505] -[_SwiftValue   tick]: unrecognized selector sent to instance 0x608000051520
2017-11-20 19:54:42.791278-0700 Rock Prodigy[3022:554505] ***  Terminating app due to uncaught exception 'NSInvalidArgumentException',   reason: '-[_SwiftValue tick]: unrecognized selector sent to instance  0x608000051520'
*** First throw call stack:
(
0   CoreFoundation                      0x000000010360d1ab __exceptionPreprocess + 171
1   libobjc.A.dylib                     0x0000000102ca2f41 objc_exception_throw + 48
2   CoreFoundation                      0x000000010368da34 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
3   CoreFoundation                      0x00000001035900a8 ___forwarding___ + 1432
4   CoreFoundation                      0x000000010358fa88 _CF_forwarding_prep_0 + 120
5   Foundation                          0x000000010270e1ee __NSFireTimer + 83
6   CoreFoundation                      0x000000010359d2a4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20
7   CoreFoundation                      0x000000010359cf62 __CFRunLoopDoTimer + 1026
8   CoreFoundation                      0x000000010359cb1a __CFRunLoopDoTimers + 266
9   CoreFoundation                      0x0000000103594534 __CFRunLoopRun + 2308
10  CoreFoundation                      0x00000001035939b9 CFRunLoopRunSpecific + 409
11  GraphicsServices                    0x00000001090e29c6 GSEventRunModal + 62
12  UIKit                               0x0000000103a885e8 UIApplicationMain + 159
13  Rock Prodigy                        0x000000010238b637 main + 55
14  libdyld.dylib                       0x0000000107aa1d81 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 

这是我的 swift 4 代码

Here is my swift 4 code

import UIKit

class GeneralFitness: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    var timer: Timer! = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(tick), userInfo: nil, repeats: true)

    @objc func tick() {
        print("tick")
    }


}

如果您有任何问题,请告诉我.

Let me know if you have any questions.

推荐答案

正如 Andrea 所说,你应该实例化计时器在 viewDidLoad 中.另外文档说:

As Andrea said, you should instantiate the timer in viewDidLoad. Also the documentation says:

选择器应具有以下签名:timerFireMethod:(包括一个冒号以指示该方法接受一个参数).

The selector should have the following signature: timerFireMethod: (including a colon to indicate that the method takes an argument).

并且不要忘记在例如 viewDidDisappear 中禁用此计时器.您不能在 deinitinvalidate 它,因为重复计时器保持对其目标的强引用,并且您的 deinit 不会被调用那么长时间因为计时器正在运行.如果您在 viewDidDisappear 中删除它,您可能需要在 viewDidAppear 中创建计时器.

And don't forget to disable this timer in, for example, viewDidDisappear. You can't invalidate it in deinit because the repeating timer keeps a strong reference to its target, and your deinit will not get called as long as the timer is running. And if you remove it in viewDidDisappear, you might want to create the timer in viewDidAppear.

因此,结果如下:

class ViewController: UIViewController {

    weak var timer: Timer?

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        timer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(tick(_:)), userInfo: nil, repeats: true)
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)

        timer?.invalidate()
    }

    @objc func tick(_ timer: Timer) {
        print("tick")
    }

}

或者您可以使用基于块的渲染,使用 [weak self] 模式,并且计时器不会保持对视图控制器的强引用,在这种情况下,您可以 使用 deinit:

Or you can use the block-based rendition, with [weak self] pattern, and the timer won't keep a strong reference to the view controller, in which case you can use deinit:

class ViewController: UIViewController {

    var timer: Timer?

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        timer = Timer.scheduledTimer(withTimeInterval: 10, repeats: true) { [weak self] timer in  // the `[weak self] reference is only needed if you reference `self` in the closure
            print("tick")
        }
    }

    deinit {
        timer?.invalidate()
    }

}

这篇关于Swift 4 计时器因 NSException 崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆