El objeto X de la clase Y no implementa methodSignatureForSelector en Swift


89

Tengo una persona de clase que se instancia varias veces.Cada persona tiene su propio temporizador. Sobre en mi initporque Personllamo startTimer().

class Person {
 var timer = NSTimer()
 func startTimer() {
    timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("timerTick"), userInfo: nil, repeats: true)
 }

 func timerTick() {
    angerLevel++
    println("Angry! \(angerLevel)")
 }
...
...
}

Entonces puedo tener 3 instancias de Person en una matriz de Person[]. Recibo un error:

2014-06-25 13:57:14.956 ThisProgram[3842:148856] *** NSForwarding: warning: object 0x113760048 of class '_TtC11ThisProgram6Person' does not implement methodSignatureForSelector: -- trouble ahead

Leí en otra parte que debería heredar, NSObjectpero esto está en Swift, no en Obj-C. La función está dentro de la clase, así que no estoy seguro de qué hacer.


4
Ya dimos cuenta de que la clase debe heredar de NSObject: class Person : NSObject { ... }. ¿Buscas una solución diferente?
Martin R

Respuestas:


160

No pienses NSObjecten una clase de Objective-C, piensa en ella como una clase Cocoa / Foundation. Aunque esté usando Swift en lugar de Objective-C, todavía está usando los mismos marcos.

Dos opciones: (1) agregue el dynamicatributo a la función a la que desea hacer referencia como selector:

    dynamic func timerTick() {
        self.angerLevel++
        print("Angry! \(self.angerLevel)")
    }

O (2) declare Personcomo una subclase de NSObject, luego simplemente llame super.init()al comienzo de su inicializador:

class Person: NSObject {
    var timer = NSTimer()
    var angerLevel = 0

    func startTimer() {
        print("starting timer")
        timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "timerTick", userInfo: nil, repeats: true)
    }

    func timerTick() {
        self.angerLevel++
        print("Angry! \(self.angerLevel)")
    }

    override init() {
        super.init()
        self.startTimer()
    }
}

3
También debería poder decorar la declaración de función de esta manera @objc func timerTick(). La API de NSTimer parece depender bastante del tiempo de ejecución de Obj-C.
macshome

Buena llamada - agregada a la respuesta
Nate Cook

1
Gracias, esto solucionó mi problema. ¿Pero puedes explicar por qué? ¿Qué necesita la parte @objc?
Agresor

NSTimerutiliza el reenvío de mensajes para llamar al selector de destino, que es una función de Objective-C que no se maneja en los tipos Swift de forma predeterminada. Cuando usa el @objcatributo o hereda de una clase Objective-C, está optando por varias funciones, incluido el reenvío de mensajes.
Nate Cook

2
Ninguna de estas soluciones ya es necesaria. Basta con declarar la función de selector dynamic. Ambos son buenos y aún funcionan, pero el uso dynamicde esta función puede verse como un enfoque más ligero.
Matt

32

Desde XCode6 beta 6, puede usar la función 'dinámica'

dynamic func timerTick() { .... }

esto resolvió mi problema al intentar usar UILocalizedIndexedCollation.currentCollation ()
DogCoffee

Este es un mejor enfoque que hacer que toda la clase herede de NSObject.
bobics

8

Tuve un error similar al intentar usar let encodedArchive = NSKeyedArchiver.archivedDataWithRootObject(archive) as NSDatadonde el archivo era una matriz de una clase personalizada. Descubrí que declarar esa clase personalizada como una subclase de NSObject y NSCoding funcionó. Requerirá algunas líneas más para cumplir con el protocolo de NSCoding, por lo que se verá así para empezar:

class Person: NSObject, NSCoding {
  init() {
    super.init()
  }

  func encodeWithCoder(_aCoder: NSCoder) {   }
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.