2014-09-07 11 views
14

Ho una classe semplice che il metodo init accetta una funzione Int e una funzione di callback.Come passare le funzioni di callback in Swift

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

Poi nel ViewController ho questo:

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

Questo non funziona, ottengo il seguente:

'Int' is not a subtype of 'SecondViewController'

Edit 1: Aggiunta di codice completo.

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

Ho appena iniziato con Swift quindi sono molto verde. Come dovresti passare i callback? Ho esaminato degli esempi e questo dovrebbe funzionare credo. La mia classe è definita in modo errato per il modo in cui sto passando la richiamata?

Grazie

+0

Prova a passare 'self.displayTimeRemaining' . Swift potrebbe aver bisogno di un riferimento esplicito al metodo di istanza per disambiguare le cose; So che è comune in altre lingue.(Purtroppo non ho un Mac a portata di mano, quindi non posso testare se questo lo risolve per te.) – sapi

+0

Non ha funzionato. :(Questo è l'errore ora: ''SecondViewController ->() -> SecondViewController!' Non ha un membro chiamato 'displayTimeRemaining'. Mi chiedo se forse ho dichiarato la funzione in modo errato all'interno del controller? Ho usato la sintassi di base che vedere nel codice sopra. – Fernando

+0

dovrebbe auto.duration e self.start() in init() essere timer.duration e timer.start()? – davecom

risposta

15

Ok, ora con il codice completo sono riuscito a replicare il problema. Non sono sicuro al 100% quale sia la causa, ma credo che abbia a che fare con il riferimento a un metodo di classe (displayTimeRemaining) prima che la classe venisse istanziata. Qui ci sono un paio di modi per aggirare questo:

Opzione 1: Dichiarare il metodo del gestore esterno del classe SecondViewController:

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


class SecondViewController: UIViewController {  

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

Opzione 2: Fare displayTimeRemaining in un metodo di tipo con l'aggiunta della classe dichiarazione da parola chiave a funzione.

class SecondViewController: UIViewController { 

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

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

Opzione 3: Credo che questa sarà la più in linea con il modo di pensare di Swift - utilizzare una chiusura:

class SecondViewController: UIViewController { 

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

Ottima risposta! L'opzione 2 è quella con cui sono andato e funziona alla grande. L'opzione 3 sembra più pulita, ma con XCode Beta 7 mi dà sempre un errore di compilazione. Non sono sicuro di quale sia l'accordo. Detto questo, questa opzione è migliore per i richiami semplici, se è qualcosa di più coinvolto, l'opzione 2 è meglio, penso. Comunque, grazie per l'aiuto! : D – Fernando

+0

Sì, ottima risposta, ho trovato opt 2 più utile. Per opt 3 non dovrebbe essere la chiusura nella chiamata di funzione, ad esempio 'Timer (durata: 5, gestore: {println ($ 0)})' – izzy

+0

Entrambe funzioneranno. Credo che quando una chiusura è l'ultimo parametro di una funzione, swift ti lascia cadere il parametro e usa la sintassi I mostrata sopra. –

0

il problema è in prima linea:

var timer = NSTimer() 

Non si può istanziare un NSTimer in questo modo. Ha metodi di classe che generano un oggetto per te. Il modo più semplice per aggirare il problema in questo caso è quello di rendere la definizione pigri, in questo modo:

lazy var timer = NSTimer() 

In questo modo il valore per il timer non sarà effettivamente essere toccato fino a quando il metodo start che lo imposta correttamente . NOTA: probabilmente esiste un modo più sicuro per farlo.

+0

Ho provato questo, ma non fa alcuna differenza. Forse questo risolve un altro problema. Per ora il problema principale è quando avvio Time() nel ViewController, non prenderà la mia funzione personalizzata come parametro del gestore. – Fernando

4

modo più semplice

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