Cách yêu cầu một giao thức chỉ có thể được chấp nhận bởi một lớp cụ thể


91

Tôi muốn giao thức này:

protocol AddsMoreCommands {
     /* ... */
}

chỉ được chấp nhận bởi các lớp kế thừa từ lớp đó UIViewController. Trang này cho tôi biết tôi có thể chỉ định rằng nó chỉ được chấp nhận bởi một lớp (trái ngược với cấu trúc) bằng cách viết

protocol AddsMoreCommands: class {
}

nhưng tôi không thể thấy cách yêu cầu rằng nó chỉ được chấp nhận bởi một lớp cụ thể. Trang đó sau đó nói về việc thêm wherecác mệnh đề vào phần mở rộng giao thức để kiểm tra sự phù hợp nhưng tôi cũng không thể biết cách điều chỉnh điều đó.

extension AddsMoreCommands where /* what */ {
}

Có cách nào để làm việc này không? Cảm ơn!

Câu trả lời:


115
protocol AddsMoreCommands: class {
    // Code
}

extension AddsMoreCommands where Self: UIViewController {
    // Code
}

4
Tôi rất gần đã có nó ... Tôi đã viết selfthay vì Self:-( Cảm ơn bạn rất nhiều, đó là hoạt động tốt!
emrys57

Đối với tôi, điều này gây ra một số kỳ lạ về cú pháp khi tôi sử dụng điều này kết hợp với ép kiểu.
Chris Prince

3
Điều này sẽ không hoạt động nếu bạn cần bao gồm một thuộc tính trong giao thức, vì các tiện ích mở rộng không thể chứa các thuộc tính được lưu trữ.
shim

1
Nó có thể đã được lưu trữ thích hợp, bạn chỉ cần sử dụng cái này: objc_getAssociatedObject (self, & KeyName) as? PropertyType
Michał Ziobro

Điều này cũng đòi hỏi đúc khi tuyên bố let / var có kiểu AddsMoreCommandsnhưng một phương pháp mà bạn vượt qua nó để hy vọng mộtUIViewController
GoatInTheMachine

80

Điều này cũng có thể đạt được mà không cần mở rộng:

protocol AddsMoreCommands: class where Self: UIViewController {
   // code
}

CHỈNH SỬA 2017/11/04 : Như Zig đã chỉ ra, điều này dường như tạo ra một cảnh báo trên Xcode 9.1. Hiện tại có một vấn đề được báo cáo về dự án Swift (SR-6265) để loại bỏ cảnh báo, tôi sẽ theo dõi và cập nhật câu trả lời cho phù hợp.

EDITED 2018/09/29 : classlà cần thiết nếu biến sẽ lưu trữ cá thể cần phải yếu (chẳng hạn như một đại biểu). Nếu bạn không cần một biến yếu, bạn có thể bỏ qua classvà chỉ viết như sau và sẽ không có bất kỳ cảnh báo nào:

protocol AddsMoreCommands where Self: UIViewController {
   // code
}

5
Làm thế nào trùng hợp ngẫu nhiên là nó mà tôi nhấp vào một câu hỏi cũ hai năm và tìm thấy một giải pháp hoàn hảo đăng một giờ trước 😲
Oscar Apeland

Xcode 9.1 hiện đưa ra cảnh báo cho tôi về câu nói này: Ràng buộc bố cục dự phòng 'Tự': 'AnyObject'. Ràng buộc về bố cục 'Tự': 'AnyObject' được ngụ ý ở đây. Thay đổi mã của tôi thành định dạng của câu trả lời được chấp nhận có vẻ tốt hơn.
Zig

2
Đối với Xcode 9.1, các giao thức chỉ dành cho lớp hiện nay được sử dụng AnyObjectthay vì class. protocol AddsMoreCommands: AnyObject where Self: UIViewController { // code }
dodgio

@dodgio vẫn nhận được cùng một cảnh báo sử dụngAnyObject
rgkobashi

1
@ DávidPásztor bạn là đúng, tuy nhiên nếu bạn muốn sử dụng nó trên một mô hình cấu trúc như đoàn, để có thể làm cho bất động sản yếu nó là cần thiết để thêm'class' rõ ràng :)
rgkobashi

48

Vì một vấn đề trong câu trả lời trước, tôi đã kết thúc với khai báo này:

protocol AddsMoreCommands where Self : UIViewController { 
    // protocol stuff here  
}

không có cảnh báo trong Xcode 9.1


5
Hãy sửa cho tôi nếu tôi sai, nhưng vấn đề với điều này so với giải pháp ở trên (đang tạo ra cảnh báo trong Xcode 9.1 trở lên), đó là bạn không thể khai báo ủy quyền là yếu?
Kyle Goslan

Ngoài ra, khi tôi sử dụng giải pháp này với Swift 4.1, tôi cần phải tính dàn diễn viên của AddsMoreCommandsđể UIViewControllermà tôi muốn tránh ...
fl034

9
Để tránh kiểu truyền, bạn có thể làm như sau:typealias AddsMoreCommandsViewController = UIViewController & AddsMoreCommands
plu

35

Bây giờ trong Swift 5, bạn có thể đạt được điều này bằng cách:

protocol AddsMoreCommands: UIViewController {
     /* ... */
}

Khá tiện dụng.

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.