1

I created a class based on this code: https://gist.github.com/etartakovsky/06b8c9894458a3ff1b14

When I try to instantiate the class and call the tick methods, I get "unrecognized selector sent to instance" error. I reviewed the code over and over but don't understand why this is happening, any advice is appreciated:

StopWatch Class source:

import Foundation
import QuartzCore

class StopWatch: NSObject{

    private var displayLink: CADisplayLink!
    private let formatter = DateFormatter()

    var callback: (() -> Void)?
    var elapsedTime: CFTimeInterval!

    override init() {
        super.init()

        self.displayLink = CADisplayLink(target: self, selector: "tick:")
        displayLink.isPaused = true
        displayLink.add(to: RunLoop.main, forMode: RunLoopMode.commonModes)

        self.elapsedTime = 0.0

        formatter.dateFormat = "mm:ss,SS"
    }
    convenience init(withCallback callback: @escaping () -> Void) {
        self.init()
        self.callback = callback
    }
    deinit {
        displayLink.invalidate()
    }

    func tick(sender: CADisplayLink) {
        elapsedTime = elapsedTime + displayLink.duration
        callback?()
    }

    func start() {
        displayLink.isPaused = false
    }

    func stop() {
        displayLink.isPaused = true
    }

    func reset() {
        displayLink.isPaused = true
        elapsedTime = 0.0
        callback?()
    }

    func elapsedTimeAsString() -> String {
        return formatter.string(from: Date(timeIntervalSinceReferenceDate:elapsedTime))
    }

}

And here is the ViewController Code:

import UIKit

class ActivityViewController: UIViewController {

    let stopwatch = StopWatch()

    @IBOutlet weak var elapsedTimeLabel: UILabel!

    func tick() {
        elapsedTimeLabel.text = stopwatch.elapsedTimeAsString()
    }

    override func viewDidLoad() {

        super.viewDidLoad()
        tick()
        stopwatch.callback = self.tick
        stopwatch.start()


        // Do any additional setup after loading the view.
    }

}
Paulo Mattos
  • 18,845
  • 10
  • 77
  • 85
Starkus
  • 147
  • 8

3 Answers3

4

In Swift 3 use the #selector syntax

self.displayLink = CADisplayLink(target: self, selector: #selector(tick))

In Swift 4 additionally you have to insert @objc at the beginning of the action

@objc func tick(...
vadian
  • 274,689
  • 30
  • 353
  • 361
2

Try two things. Use the new (and safer) selector syntax introduced by Swift 3:

CADisplayLink(target: self, selector: #selector(tick(sender:)))

and be sure to expose your tick method to Objective-C (the rules have changed in Swift 4):

@objc func tick(sender: CADisplayLink) {
    ...
}
Paulo Mattos
  • 18,845
  • 10
  • 77
  • 85
1

To make it clear: unrecognized selector sent to instance is an error in MessagePassing scenario which means the desired selector which is:

func tick(sender: CADisplayLink) {...}

and has to receive the message is unrecognized. It cannot be found because of the wrong way of addressing to it.

as other members said, you have to change your target selector by adding #selector(tick):

self.displayLink = CADisplayLink(target: self, selector: #selector(tick))

you can find more details about the error in this thread

Mina
  • 2,167
  • 2
  • 25
  • 32