Objek X kelas Y tidak mengimplementasikan methodSignatureForSelector di Swift

89

Saya memiliki kelas Person yang dipakai beberapa kali. Setiap orang memiliki pengatur waktunya sendiri. Setelah di saya inituntuk Personsaya panggil 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)")
 }
...
...
}

Jadi saya mungkin memiliki 3 contoh Person dalam sebuah array Person[]. Saya mendapatkan kesalahan:

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

Saya membaca di tempat lain bahwa saya harus mewarisi NSObjecttetapi ini di Swift bukan Obj-C. Fungsinya ada di dalam kelas jadi saya tidak yakin apa yang harus dilakukan.

Johnston
sumber
4
Anda sudah tahu bahwa kelas harus mewarisi dari NSObject: class Person : NSObject { ... }. Apakah Anda mencari solusi lain?
Martin R

Jawaban:

160

Jangan anggap NSObjectsebagai kelas Objective-C, anggap saja sebagai kelas Cocoa / Foundation. Meskipun Anda menggunakan Swift dan bukan Objective-C, Anda masih menggunakan semua kerangka kerja yang sama.

Dua opsi: (1) tambahkan dynamicatribut ke fungsi yang ingin Anda rujuk sebagai pemilih:

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

Atau (2) nyatakan Personsebagai subclass dari NSObject, lalu panggil saja super.init()di awal penginisialisasi Anda:

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()
    }
}
Nate Cook
sumber
3
Anda juga harus bisa menghias deklarasi fungsi seperti ini @objc func timerTick(). NSTimer API tampaknya sangat bergantung pada Obj-C Runtime.
macshome
Panggilan bagus - ditambahkan ke jawaban
Nate Cook
1
Terima kasih ini MEMPERBAIKI masalah saya. Tapi bisakah Anda menjelaskan mengapa? Apa yang dibutuhkan bagian @objc?
Penyerang
NSTimermenggunakan penerusan pesan untuk memanggil pemilih yang ditargetkan, yang merupakan fitur Objective-C yang tidak ditangani pada tipe Swift secara default. Saat Anda menggunakan @objcatribut atau mewarisi dari kelas Objective-C, Anda memilih ke dalam beberapa fitur, termasuk penerusan pesan.
Nate Cook
2
Tak satu pun dari solusi ini diperlukan lagi. Cukup dengan mendeklarasikan fungsi selektor dynamic. Keduanya bagus dan keduanya masih berfungsi, tetapi menggunakan dynamicfungsi yang satu ini mungkin terlihat pendekatan yang lebih ringan.
matt
32

Sejak XCode6 beta 6, Anda dapat menggunakan fungsi 'dinamis'

dynamic func timerTick() { .... }
Kritsana U.
sumber
ini memecahkan masalah saya mencoba menggunakan UILocalizedIndexedCollation.currentCollation ()
DogCoffee
Ini adalah pendekatan yang lebih baik vs menjadikan seluruh kelas mewarisi dari NSObject.
bobics
8

Saya mengalami kesalahan serupa saat mencoba menggunakan di let encodedArchive = NSKeyedArchiver.archivedDataWithRootObject(archive) as NSDatamana arsip adalah array kelas khusus. Saya menemukan bahwa mendeklarasikan kelas khusus itu sebagai subkelas NSObject dan NSCoding berhasil. Ini akan membutuhkan beberapa baris lagi untuk menyesuaikan dengan protokol NSCoding sehingga akan terlihat seperti ini untuk memulai:

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

  func encodeWithCoder(_aCoder: NSCoder) {   }
}
Jeremy Rea
sumber