Đối tượng X của lớp Y không triển khai methodSignatureForSelector trong Swift


89

Tôi có một lớp Person được khởi tạo nhiều lần. Mỗi người có bộ đếm thời gian của riêng họ. Khi tôi gọi initcho Persontôi 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)")
 }
...
...
}

Vì vậy, tôi có thể có 3 trường hợp của Person trong một mảng Person[]. Tôi gặp lỗi:

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

Tôi đã đọc ở những nơi khác mà tôi nên kế thừa từ đó NSObjectnhưng đây là trong Swift không phải obj-C. Hàm nằm trong lớp nên tôi không chắc phải làm gì.


4
Bạn đã tìm ra rằng lớp nên kế thừa từ NSObject: class Person : NSObject { ... }. Bạn đang tìm kiếm một giải pháp khác?
Martin R

Câu trả lời:


160

Đừng nghĩ về NSObjectlớp Objective-C, hãy nghĩ về nó như lớp Cocoa / Foundation. Mặc dù bạn đang sử dụng Swift thay vì Objective-C, bạn vẫn đang sử dụng tất cả các framework giống nhau.

Hai tùy chọn: (1) thêm dynamicthuộc tính vào hàm mà bạn muốn tham chiếu làm bộ chọn:

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

Hoặc (2) khai báo Persondưới dạng lớp con của NSObject, sau đó chỉ cần gọi super.init()ở đầu trình khởi tạo của bạn:

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
Bạn cũng có thể trang trí khai báo hàm như thế này @objc func timerTick(). API NSTimer dường như phụ thuộc khá nhiều vào Thời gian chạy của Obj-C.
macshome

Tốt cuộc gọi - thêm vào câu trả lời
Nate Nấu

1
Cảm ơn điều này đã CỐ ĐỊNH vấn đề của tôi. Nhưng bạn có thể giải thích tại sao không? Nó cần phần @objc là gì?
Aggressor

NSTimersử dụng chuyển tiếp tin nhắn để gọi bộ chọn được nhắm mục tiêu, đây là một tính năng Objective-C không được xử lý trên các loại Swift theo mặc định. Khi bạn sử dụng @objcthuộc tính hoặc kế thừa từ lớp Objective-C, bạn đang chọn sử dụng một số tính năng, bao gồm chuyển tiếp thư.
Nate Cook

2
Cả hai giải pháp này đều không cần thiết nữa. Chỉ cần khai báo chức năng bộ chọn là đủ dynamic. Cả hai đều tốt và cả hai đều vẫn hoạt động, nhưng sử dụng dynamictrên một chức năng này có thể được xem là một cách tiếp cận nhẹ hơn.
matt

32

Kể từ XCode6 beta 6, bạn có thể sử dụng func 'động'

dynamic func timerTick() { .... }

điều này đã giải quyết được sự cố của tôi khi cố gắng sử dụng UILocalizedIndexedCollation.currentCollation ()
DogCoffee

Đây là một cách tiếp cận tốt hơn so với việc làm cho toàn bộ lớp kế thừa từ NSObject.
bobics

8

Tôi đã gặp lỗi tương tự khi cố gắng sử dụng let encodedArchive = NSKeyedArchiver.archivedDataWithRootObject(archive) as NSDatanơi lưu trữ là một mảng của lớp tùy chỉnh. Tôi thấy rằng việc khai báo lớp tùy chỉnh đó như một lớp con của NSObject và NSCoding đã thực hiện thủ thuật. Nó sẽ yêu cầu thêm một vài dòng để tuân theo giao thức của NSCoding, vì vậy nó sẽ trông giống như thế này để bắt đầu với:

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

  func encodeWithCoder(_aCoder: NSCoder) {   }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.