Как передать функции обратного вызова в 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()
Таким образом, значение для таймера на самом деле не будет затронуто до тех пор, пока метод запуска не установит его правильно. ПРИМЕЧАНИЕ. Вероятно, существует более безопасный способ сделать это.