Mam klasę Person, której instancja jest uruchamiana wiele razy. Każda osoba ma swój własny licznik czasu. Po w moim init
dla Person
zadzwonię 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)")
}
...
...
}
Więc mogę mieć 3 wystąpienia Person w tablicy Person[]
. Otrzymuję błąd:
2014-06-25 13:57:14.956 ThisProgram[3842:148856] *** NSForwarding: warning: object 0x113760048 of class '_TtC11ThisProgram6Person' does not implement methodSignatureForSelector: -- trouble ahead
Czytałem gdzie indziej, po czym powinienem dziedziczyć, NSObject
ale to jest w języku Swift, a nie Obj-C. Funkcja znajduje się w klasie, więc nie wiem, co robić.
class Person : NSObject { ... }
. Szukasz innego rozwiązania?Odpowiedzi:
Nie myśl o
NSObject
klasie Objective-C, myśl o niej jak o klasie Cocoa / Foundation. Mimo że używasz Swift zamiast Objective-C, nadal używasz tych samych frameworków.Dwie opcje: (1) dodaj
dynamic
atrybut do funkcji, do której chcesz się odwołać jako selektor:dynamic func timerTick() { self.angerLevel++ print("Angry! \(self.angerLevel)") }
Lub (2) zadeklaruj
Person
jako podklasęNSObject
, a następnie wywołajsuper.init()
na początku swojego inicjatora: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() } }
źródło
@objc func timerTick()
. Wydaje się, że API NSTimer jest dość zależne od środowiska wykonawczego Obj-C.NSTimer
używa przekazywania wiadomości do wywołania selektora docelowego, co jest funkcją celu-C, która nie jest obsługiwana domyślnie w typach Swift. Używając@objc
atrybutu lub dziedzicząc z klasy Objective-C, decydujesz się na kilka funkcji, w tym przekazywanie wiadomości.dynamic
. Obie są dobre i nadal działają, ale użyciedynamic
tej jednej funkcji może być postrzegane jako bardziej lekkie podejście.Od wersji beta 6 XCode6 możesz używać funkcji „dynamicznej”
dynamic func timerTick() { .... }
źródło
Wystąpił podobny błąd podczas próby użycia,
let encodedArchive = NSKeyedArchiver.archivedDataWithRootObject(archive) as NSData
gdzie archiwum było tablicą klasy niestandardowej. Okazało się, że zadeklarowanie tej klasy niestandardowej jako podklasy NSObject i NSCoding załatwiło sprawę. Będzie to wymagało jeszcze kilku wierszy, aby dostosować się do protokołu NSCoding, więc na początku będzie wyglądać mniej więcej tak:class Person: NSObject, NSCoding { init() { super.init() } func encodeWithCoder(_aCoder: NSCoder) { } }
źródło