Bagaimana mensyaratkan bahwa protokol hanya dapat diadopsi oleh kelas tertentu


91

Saya ingin protokol ini:

protocol AddsMoreCommands {
     /* ... */
}

hanya untuk diadopsi oleh kelas yang mewarisi dari kelas tersebut UIViewController. Halaman ini memberi tahu saya bahwa saya dapat menentukan bahwa itu hanya diadopsi oleh kelas (sebagai lawan dari struct) dengan menulis

protocol AddsMoreCommands: class {
}

tetapi saya tidak dapat melihat bagaimana mensyaratkan bahwa itu hanya diadopsi oleh kelas tertentu. Halaman itu kemudian berbicara tentang menambahkan whereklausul ke ekstensi protokol untuk memeriksa kesesuaian tetapi saya juga tidak dapat melihat bagaimana menyesuaikannya.

extension AddsMoreCommands where /* what */ {
}

Apakah ada cara untuk melakukan ini? Terima kasih!

Jawaban:


115
protocol AddsMoreCommands: class {
    // Code
}

extension AddsMoreCommands where Self: UIViewController {
    // Code
}

4
Saya hampir memilikinya ... Saya menulis selfalih-alih Self:-( Terima kasih banyak, itu berfungsi dengan baik!
emrys57

Bagi saya, ini menyebabkan beberapa keanehan sintaksis ketika saya menggunakan ini dalam hubungannya dengan casting.
Chris Prince

3
Ini tidak akan berfungsi jika Anda perlu menyertakan properti dalam protokol, karena ekstensi tidak dapat berisi properti yang disimpan.
shim

1
Itu dapat disimpan properti Anda hanya perlu menggunakan ini: objc_getAssociatedObject (self, & KeyName) sebagai? PropertyType
Michał Ziobro

Ini juga membutuhkan casting ketika deklarasi let / var memiliki tipe AddsMoreCommandstetapi metode yang Anda berikan untuk mengharapkanUIViewController
GoatInTheMachine

80

Ini juga dapat dicapai tanpa perpanjangan:

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

DIEDIT 2017/11/04 : Seperti yang ditunjukkan Zig , ini sepertinya menghasilkan peringatan pada Xcode 9.1. Saat ini ada masalah yang dilaporkan pada proyek Swift (SR-6265) untuk menghapus peringatan, saya akan mengawasinya dan memperbarui jawabannya sesuai.

EDITED 2018/09/29 : classdiperlukan jika variabel yang akan menyimpan instans harus lemah (seperti delegasi). Jika Anda tidak memerlukan variabel lemah, Anda dapat menghilangkan classdan cukup tulis berikut ini dan tidak akan ada peringatan:

protocol AddsMoreCommands where Self: UIViewController {
   // code
}

5
Betapa kebetulan bahwa saya mengklik pertanyaan berusia dua tahun dan menemukan solusi sempurna yang diposting satu jam yang lalu 😲
Oscar Apeland

Xcode 9.1 sekarang memberi saya peringatan tentang pepatah ini: Batasan tata letak yang berlebihan 'Self': 'AnyObject'. Batasan batasan tata letak 'Self': 'AnyObject' tersirat di sini. Mengubah kode saya ke format jawaban yang diterima tampaknya lebih baik.
Zig

2
Mulai dari Xcode 9.1, protokol khusus kelas sekarang digunakan AnyObjectsebagai pengganti class. protocol AddsMoreCommands: AnyObject where Self: UIViewController { // code }
dodgio

@dodgio masih mendapatkan peringatan yang sama menggunakanAnyObject
rgkobashi

1
@ DávidPásztor Anda benar, namun jika Anda ingin menggunakannya pada pola struktural seperti delegasi, untuk dapat membuat properti lemah, perlu menambahkan ´class´ secara eksplisit :)
rgkobashi

48

Karena masalah dalam jawaban sebelumnya, saya berakhir dengan pernyataan ini:

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

tidak ada peringatan di Xcode 9.1


5
Perbaiki saya jika saya salah, tetapi masalah dengan solusi di atas (yang menghasilkan peringatan di Xcode 9.1 dan yang lebih baru), apakah Anda tidak dapat menyatakan delegasi sebagai lemah?
Kyle Goslan

Juga, ketika saya menggunakan solusi ini dengan Swift 4.1, saya perlu sifat pemain dari AddsMoreCommandske UIViewControllermana saya ingin menghindari ...
fl034

9
Untuk menghindari tipe cast, Anda dapat melakukan ini:typealias AddsMoreCommandsViewController = UIViewController & AddsMoreCommands
plu

35

Sekarang di Swift 5 Anda dapat mencapai ini dengan:

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

Cukup berguna.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.