2014-09-07 9 views
14

Ich habe eine einfache Klasse, die init Methode dauert eine Int und eine Callback-Funktion.Wie Callback-Funktionen in Swift übergeben

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

Dann in dem Viewcontroller ich habe dies:

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

Dies nicht, ich folgende erhalten funktioniert:

'Int' is not a subtype of 'SecondViewController'

Edit 1: Hinzufügen von vollständigem Code.

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

ich mit Swift gerade erst begonnen, so bin ich sehr grün. Wie sollen Callbacks weitergeleitet werden? Ich habe mir Beispiele angesehen und das sollte funktionieren, denke ich. Wurde meine Klasse falsch für die Art und Weise definiert, wie ich den Rückruf übergebe?

Dank

+0

Versuche 'self.displayTimeRemaining' vorbei . Swift benötigt möglicherweise einen expliziten Verweis auf die Instanzmethode, um Dinge zu disambiguieren. Ich weiß, das ist in anderen Sprachen üblich.(Leider habe ich keinen Mac handlich, so kann nicht testen, ob dies für Sie behebt.) – sapi

+0

Hat nicht funktioniert. :(Das ist der Fehler jetzt: ''SecondViewController ->() -> SecondViewController!' Hat kein Mitglied namens 'displayTimeRemaining''. Ich frage mich, ob ich vielleicht die Funktion falsch im Controller deklariert habe? Ich habe die grundlegende Syntax Sie siehe oben im Code: – Fernando

+0

sollten self.duration und self.start() in init() timer.duration und timer.start() sein? – davecom

Antwort

15

Ok, jetzt mit dem vollen Code konnte ich Ihr Problem replizieren. Ich bin nicht 100% sicher, was die Ursache ist, aber ich glaube, dass es etwas mit dem Verweisen auf eine Klassenmethode (displayTimeRemaining) zu tun hat, bevor die Klasse instanziiert wurde. Hier sind ein paar Möglichkeiten, um dieses:

Option 1: Deklarieren Sie die Handler-Methode außerhalb des SecondViewController Klasse:

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


class SecondViewController: UIViewController {  

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

Option 2: displayTimeRemaining in eine Art Verfahren durch die Klasse Hinzufügen Schlüsselwort zur Funktionsdeklaration.

class SecondViewController: UIViewController { 

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

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

Option 3: Ich glaube, dass dies die inline mit Swift Denkweise sein - einen Verschluss verwenden:

class SecondViewController: UIViewController { 

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

Ausgezeichnete Antwort! Option 2 ist diejenige, mit der ich zusammen war und großartig funktioniert. Option 3 sieht sauberer aus, aber es gibt mir jedes Mal einen Kompilierfehler mit XCode Beta 7. Nicht sicher, was der Deal dort ist. Das heißt, diese Option ist besser für einfache Rückrufe, wenn es etwas mehr beteiligt Option 2 ist besser, denke ich. Wie auch immer, danke für die Hilfe! : D – Fernando

+0

Ja ausgezeichnete Antwort, fand ich opt 2 am hilfreichsten. Für opt 3 müsste der Abschluss nicht in dem Funktionsaufruf sein, d. H. 'Timer (Dauer: 5, Handler: {println ($ 0)})' – izzy

+0

Beide funktionieren. Ich glaube, wenn eine Schließung der letzte Parameter zu einer Funktion ist, lässt swift den Parameter fallen und benutzt die oben gezeigte Syntax. –

0

Ihr Problem ist in der Zeile:

var timer = NSTimer() 

Sie keine NSTimer auf diese Weise instanziieren können. Es verfügt über Klassenmethoden, die ein Objekt für Sie generieren. Der einfachste Weg, um das Problem in diesem Fall zu erhalten, ist die Definition faul zu machen, etwa so:

lazy var timer = NSTimer() 

Auf diese Weise wird der Wert für den Timer wird tatsächlich erst in der Startmethode berührt werden, die es richtig einrichtet . HINWEIS: Es gibt wahrscheinlich einen sichereren Weg, dies zu tun.

+0

Ich habe das versucht, macht aber keinen Unterschied. Vielleicht behebt dies ein anderes Problem. Im Moment ist das Hauptproblem, wenn ich Time() im ViewController initiiere, wird es meine benutzerdefinierte Funktion nicht als Handler-Parameter nehmen. – Fernando

4

einfachste Weg

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