Об'єкт X класу Y не реалізує methodSignatureForSelector у Swift


89

У мене є клас Person, який створюється кілька разів. Кожна людина отримує власний таймер. Після по моєму initдля Personмене зателефонувати 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)")
 }
...
...
}

Тож у мене може бути 3 екземпляри Person у масиві Person[]. Я отримую повідомлення про помилку:

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

Я ще десь читав, що мені слід успадкувати, NSObjectале це в Swift, а не в Obj-C. Функція знаходиться в класі, тому я не впевнений, що робити.


4
Ви вже зрозуміли, що клас повинен успадковувати від NSObject: class Person : NSObject { ... }. Шукаєте іншого рішення?
Martin R

Відповіді:


160

Не думайте про NSObjectклас Objective-C, а про клас какао / основи. Хоча ви використовуєте Swift замість Objective-C, ви все одно використовуєте ті самі рамки.

Два варіанти: (1) додати dynamicатрибут до функції, на яку ви хочете посилатися як на селектор:

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

Або (2) оголосіть Personяк підклас NSObject, а потім просто зателефонуйте super.init()на початку вашого ініціалізатора:

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
Ви також повинні мати можливість прикрасити оголошення функції таким чином @objc func timerTick(). API NSTimer, здається, в значній мірі залежить від часу виконання Obj-C.
macshome

Гарний дзвінок - додано до відповіді
Nate Cook

1
Дякую за це ВИПРАВЛЕНО моє питання. Але чи можете ви пояснити, чому? Для чого потрібна частина @objc?
Агресор

NSTimerвикористовує переадресацію повідомлень для виклику цільового селектора, який є функцією Objective-C, яка не обробляється у типах Swift за замовчуванням. Коли ви використовуєте @objcатрибут або успадковуєте клас Objective-C, ви обираєте кілька функцій, включаючи пересилання повідомлень.
Nate Cook

2
Жодне з цих рішень більше не потрібно. Досить оголосити функцію селектора dynamic. Вони обидва хороші, і обидва все ще працюють, але використання dynamicцієї однієї функції може сприйматися більш легким підходом.
matt

32

Починаючи з XCode6 beta 6, ви можете використовувати "динамічний" func

dynamic func timerTick() { .... }

це вирішило мою проблему, намагаючись використовувати UILocalizedIndexedCollation.currentCollation ()
DogCoffee

Це кращий підхід порівняно з тим, щоб увесь клас успадковувати від NSObject.
bobics

8

У мене сталася подібна помилка при спробі використання, let encodedArchive = NSKeyedArchiver.archivedDataWithRootObject(archive) as NSDataде архів був масивом нестандартного класу. Я виявив, що оголошення цього користувацького класу як підклас NSObject та NSCoding зробило свою справу. Для відповідності протоколу NSCoding знадобиться ще кілька рядків, тому для початку це виглядатиме приблизно так:

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

  func encodeWithCoder(_aCoder: NSCoder) {   }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.