2015-08-12 16 views
11

Trong mục tiêu-C, tôi đã tạo một thể loại rất tiện dụng (một phần mở rộng, theo thuật ngữ Swift) của NSObject thêm khả năng thêm cặp khóa/giá trị tùy ý vào bất kỳ NSObject nào khi chạy. Nó sử dụng các đối tượng liên kết để đính kèm một từ điển có thể thay đổi cho đối tượng, và sau đó cung cấp các phương thức get và set nhận/đặt các cặp khóa/giá trị vào/từ từ điển đó. Nó chỉ là một vài dòng mã.Có cách nào để thêm tiện ích mở rộng vào AnyObject không?

Điều này làm cho nó có thể đính kèm cặp khóa/giá trị tùy ý vào bất kỳ đối tượng nào khi chạy, bao gồm các đối tượng được tạo bởi hệ thống. Đó là chìa khóa. Có những trường hợp khung hệ thống trả về một đối tượng cho bạn và bạn cần có khả năng đính kèm một giá trị cho nó.

Thủ thuật này cũng giúp tạo các danh mục có các biến mẫu mới. (. Ok, họ không thực sự, nhưng đối với nó cho phép bạn thêm các biến trạng thái mới để các đối tượng trong một thể loại)

này là không thể trong Swift 1.2 vì:

  • Swift không có một lớp cơ sở cho tất cả các đối tượng như NSObject trong Mục tiêu-C. Nó sử dụng AnyObject, là một giao thức.
  • Swift 1.2 không cho phép tiện ích mở rộng giao thức.

Tôi phải từ bỏ điều này trong Swift 1.2.

Nhưng Swift 2 cho phép tiện ích mở rộng giao thức. Tôi nghĩ "Tuyệt vời, bây giờ tôi có thể thêm phần mở rộng của tôi cho phép tôi thêm cặp khóa/giá trị vào AnyObject!"

Không có niềm vui.

Khi tôi cố gắng tạo ra phần mở rộng của tôi cho AnyObject:

extension AnyObject: AssociatedObjectProtocol 

Tôi nhận được thông báo lỗi

Protocol 'AnyObject' không thể được mở rộng

Arghh! Rất gần, nhưng không. Có vẻ như ngôn ngữ này cấm hoàn toàn việc mở rộng AnyObject. Tại sao điều này, và có cách nào xung quanh nó?

Tôi không sử dụng danh mục của mình trên NSObject thường xuyên, nhưng khi tôi làm, đó là một phao cứu sinh. Tôi muốn thêm nó vào túi thủ thuật của tôi trong Swift.

Tôi có thể thêm nó vào NSObject giống như tôi làm trong Objective-C, nhưng điều đó có nghĩa là nó chỉ hoạt động cho các đối tượng kế thừa từ NSObject - làm cho nó không hoạt động cho các lớp Swift gốc.

+1

Ghi chú ngẫu nhiên: Tôi không nghĩ bạn muốn giao thức bắt đầu bằng chữ thường. https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingBasics.html#//apple_ref/doc/uid/20001281-1002242-BBCIJGDB –

Trả lời

12

Thật không may là một giải pháp thay thế chính xác giống như bạn muốn không tồn tại. Vì vậy, tôi sẽ đề nghị để thực hiện một giao thức trong đó có một phần mở rộng để thêm hiện thực mặc định:

protocol A: AnyObject {} 

// in Swift you would rather use this 
protocol A: class {} 

// add default implementations 
extension A { 
    func aMethod() { 
     // code 
    } 
} 

// Example 
class B: A {} 

// use the method 
B().aMethod() 

Cách tiếp cận này không làm cho mọi tầng lớp tự động phù hợp với giao thức này (nhưng chỉ lớp học có thể phù hợp với nó). Vì vậy, bạn phải làm cho chúng phù hợp với chính mình. Vì bạn không sử dụng điều này nhiều như vậy nên đây sẽ là một giải pháp hợp lý.

+0

Tôi không hoàn toàn hiểu đề xuất của bạn . Bạn đang nói rằng tôi sẽ xác định chữ ký phương thức trong một giao thức, sau đó cung cấp mã như một phần mở rộng cho bất kỳ lớp nào mà tôi cần nó? Điều đó có nghĩa là tôi phải sao chép mã trong phần mở rộng cho mỗi lớp đích, đúng không? –

+0

@DuncanC Trong trường hợp này bạn không xác định bất kỳ yêu cầu nào trong giao thức và bạn có thể sử dụng phương thức trong phần mở rộng với bất kỳ lớp nào phù hợp với nó mà không yêu cầu mã bổ sung (ví dụ được thêm vào câu trả lời) – Qbyte

+0

ra khỏi mã giả trong câu trả lời của bạn. –

3

Dọc theo dòng @ câu trả lời Qbyte của, tuyên bố rằng NSObject phù hợp với một giao thức có nghĩa là hầu hết các lớp trong toàn bộ vũ trụ Cocoa/UIKit/Foundation sẽ kế thừa chức năng:

protocol MyProtocol { 
    func doSomething() 
} 

extension MyProtocol { 
    func doSomething() { 
     print("This is me, doing something.") 
    } 
} 

extension NSObject: MyProtocol { } 

Bạn vừa phù hợp 99% các lớp khung của Apple tới MyProtocol. Bạn có thể làm cho các lớp của riêng bạn phù hợp với MyProtocol bằng cách kế thừa từ NSObject hoặc đơn giản là tuân theo nó.

+0

Đây không phải là giải pháp thực sự. Nó hoàn toàn hợp pháp để sử dụng "mở rộng NSObject" nhưng nó có nghĩa là cho các lớp của riêng bạn, bạn cần phải làm cho tất cả các lớp của riêng bạn phù hợp với NSObjectProtocol – Charlesism

+0

Câu trả lời này là khá ok, nhưng sử dụng nó nó không cung cấp cho bạn một số kiểm tra thời gian biên dịch Swift cơ bản . Ví dụ, nếu bạn muốn có một biến 'var string: String {return self as! String} 'và bạn gọi' arrayInstance.string' trình biên dịch không cho bạn biết bất cứ điều gì, nhưng thao tác không thể thực hiện được nếu bạn thử '[" element "] như! String' trình biên dịch cho bạn biết rằng thao tác luôn thất bại –

+0

nếu bạn định làm cho NSObject tuân theo giao thức của bạn được mở rộng để bao gồm hành vi mặc định, sau đó có thể mở rộng NSObject trực tiếp thay vì có giao thức không? – Gobe

Các vấn đề liên quan