Как передать функции обратного вызова в Swift

У меня есть простой класс, метод init принимает Int и функцию обратного вызова.

class Timer {
  var timer = NSTimer()
  var handler: (Int) -> Void

  init(duration: Int, handler: (Int) -> Void) {
      self.duration = duration
      self.handler = handler
      self.start()
  }
  @objc func someMethod() {        
      self.handler(10)
  }
}

Тогда в ViewController у меня есть следующее:

var timer = Timer(duration: 5, handler: displayTimeRemaining)
func displayTimeRemaining(counter: Int) -> Void {
    println(counter)
}

Это не работает, я получаю следующее:

'Int' is not a subtype of 'SecondViewController'

Изменить 1: добавление полного кода.

Timer.swift

import UIKit

class Timer {
    lazy var timer = NSTimer()
    var handler: (Int) -> Void

    let duration: Int
    var elapsedTime: Int = 0

    init(duration: Int, handler: (Int) -> Void) {
        self.duration = duration
        self.handler = handler
        self.start()
    }

    func start() {
        self.timer = NSTimer.scheduledTimerWithTimeInterval(1.0,
            target: self,
            selector: Selector("tick"),
            userInfo: nil,
            repeats: true)
    }

    func stop() {
        timer.invalidate()
    }

    func tick() {
        self.elapsedTime++

        self.handler(10)

        if self.elapsedTime == self.duration {
            self.stop()
        }
    }

    deinit {
        self.timer.invalidate()
    }
}

SecondViewController.swift

import UIKit

class SecondViewController: UIViewController {

    @IBOutlet var cycleCounter: UILabel!
    var number = 0

    var timer = Timer(duration: 5, handler: displayTimeRemaining)

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func btnIncrementCycle_Click(sender: UIButton){
        cycleCounter.text = String(++number)
        println(number)
    }

    func displayTimeRemaining(counter: Int) -> Void {
        println(counter)
    }
}

Я только начал с Swift, поэтому я очень зеленый. Как вы должны проходить обратные вызовы? Я смотрел примеры, и это должно работать, я думаю. Является ли мой класс некорректным для способа передачи обратного вызова?

Спасибо

Ответы

Ответ 1

Хорошо, теперь с полным кодом я смог реплицировать вашу проблему. Я не уверен на 100%, в чем причина, но я считаю, что это связано с ссылкой на метод класса (displayTimeRemaining) до того, как был создан экземпляр класса. Вот несколько способов обойти это:

Вариант 1: объявить метод обработчика вне класса SecondViewController:

func displayTimeRemaining(counter: Int) -> Void {
  println(counter)
}


class SecondViewController: UIViewController {    

  // ...
  var timer = Timer(duration: 5, handler: displayTimeRemaining)

Вариант 2: Сделать displayTimeRemaining в методе типа, добавив ключевое слово класса в объявление функции.

class SecondViewController: UIViewController {

  var timer: Timer = Timer(duration: 5, handler: SecondViewController.displayTimeRemaining)

  class func displayTimeRemaining(counter: Int) -> Void {
    println(counter)
  }

Вариант 3: Я считаю, что это будет самым строгим с использованием стиля Swift - используйте закрытие:

class SecondViewController: UIViewController {

var timer: Timer = Timer(duration: 5) {
        println($0) //using Swift anonymous method params
    }

Ответ 2

Простейший способ

override func viewDidLoad() {
        super.viewDidLoad()

        testFunc(index: 2, callback: { str in
            print(str)
        })

    }


    func testFunc(index index: Int, callback: (String) -> Void) {
        callback("The number is \(index)")
    }

Ответ 3

Ваша проблема в строке:

var timer = NSTimer()

Вы не можете создавать NSTimer таким образом. Он имеет методы класса, которые генерируют для вас объект. Самый простой способ обойти проблему в этом случае - сделать определение ленивым, например:

lazy var timer = NSTimer()

Таким образом, значение для таймера на самом деле не будет затронуто до тех пор, пока метод запуска не установит его правильно. ПРИМЕЧАНИЕ. Вероятно, существует более безопасный способ сделать это.