2017-11-21 16 views
3

스위프트 4에서 타이머를 사용할 방법을 찾고 있었고 this 기사를 보았습니다. xcode에서 내 코드를 테스트하고 타이머가 처음 틱 (이 경우 10 초 후)되면 응용 프로그램이 다운되고 빌드가 성공했지만 오류가 발생합니다.NSException으로 스위프트 4 타이머가 충돌 함

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) 

여기에 4 코드

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") 
    } 


} 

문의 사항이 있으면 알려주세요 내 신속하다.

귀하의 타이머가 잘못된 방법으로 초기화

답변

4

Andrea said, 당신은 viewDidLoad에 타이머를 인스턴스화해야합니다. 또한 the documentation says : timerFireMethod: (있어서 인수 걸리는 표시하는 결장 포함)

선택기 다음 특성을 가져야한다.

예를 들어 viewDidDisappear에서이 타이머를 사용 중지하는 것을 잊지 마세요. 반복 타이머가 해당 대상에 대한 강력한 참조를 유지하고 타이머가 실행되는 동안에는 deinit이 호출되지 않으므로 invalidatedeinit에 넣을 수 없습니다. viewDidDisappear에서 제거하면 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] 패턴, 블록 기반 연주를 사용할 수 있으며, 타이머가 뷰 컨트롤러에 대한 강한 참조를 유지하지 않을 경우에

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() 
    } 

} 
+0

위대한 리드! 스위프트 4에서는 viewDidAppear (그렇지 않으면 내 코드가 추락)로 타이머 설정을 이동해야했습니다. –

5

이유는

당신이 속성을 초기화하는 클로저를 사용하는 경우, 인스턴스의 나머지 부분은 아직 폐쇄가 실행되는 시점에서 초기화되지 않았 음을 기억 . 즉, 클로저에서 다른 속성 값에 액세스 할 수 없다는 것을 의미합니다. 이러한 속성에는 기본값이 있습니다. 또한

:

또한 암시 적 자기 속성을 사용하거나 인스턴스의 방법 중 하나를 호출 할 수 없습니다

따라서

, 당신의 문제를 해결하기 위해, 당신은 이동해야합니다 (here 참조) 그러한 코드는 viewDidLoad 안에 있습니다. 그래서 당신이 시도 할 수 있습니다 :

import UIKit 

class ViewController: UIViewController { 
    weak var timer: Timer? 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     Timer.scheduledTimer(withTimeInterval: 10, repeats: true, block: { [weak self] timer in 
     self?.timer = timer 
     self?.tick() 
     }) 
    } 

    deinit { 
     self.timer?.invalidate() 
    } 

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

이제 작동합니다. 10 초 후에 타이머가 꺼지더라도 viewDidLoad 함수에서 타이머를 호출해야합니다. 감사합니다 –

0

빠른 4

import UIKit 

class ViewController: UIViewController { 

    var timer: Timer! 

    override func viewDidLoad() { 
     super.viewDidLoad() 


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

    func updateValue(){ 

     print("Timer is call") 
    } 
} 
이 시도 : 당신은 deinit 사용할 수
+0

이 코드는 컴파일되지 않습니다 :'func updateValue()'에 @objc가 없습니다. –