Як вимагати, щоб протокол був прийнятий лише певним класом


91

Я хочу цей протокол:

protocol AddsMoreCommands {
     /* ... */
}

лише для прийняття класами, які успадковують від класу UIViewController. Ця сторінка говорить мені, що я можу вказати, що вона приймається класом (на відміну від структури) лише шляхом письма

protocol AddsMoreCommands: class {
}

але я не можу зрозуміти, як вимагати, щоб це було прийнято лише певним класом. Ця сторінка пізніше розповідає про додавання whereстатей до розширень протоколів для перевірки відповідності, але я не можу зрозуміти, як це адаптувати.

extension AddsMoreCommands where /* what */ {
}

Чи є спосіб зробити це? Дякую!

Відповіді:


115
protocol AddsMoreCommands: class {
    // Code
}

extension AddsMoreCommands where Self: UIViewController {
    // Code
}

4
У мене це мало не було ... Я писав selfзамість Self:-( Щиро дякую, це чудово працює!
emrys57

Для мене це викликає певну синтаксичну дивність, коли я використовую це разом із кастингом.
Кріс Принс

3
Це не спрацює, якщо вам потрібно включити властивість до протоколу, оскільки розширення не можуть містити збережені властивості.
шим

1
Він міг зберегти належне, вам потрібно використовувати лише це: objc_getAssociatedObject (self, & KeyName) як? PropertyType
Michał Ziobro

Це також вимагає кастингу, коли декларація let / var має тип, AddsMoreCommandsале метод, якому ви її UIViewController
передаєте,

80

Цього також можна досягти без розширення:

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

ВИДАЛЕНО 2017/11/04 : Як зазначив Zig , це, схоже, видає попередження на Xcode 9.1. В даний час є повідомлення про проблему проекту Swift (SR-6265) щодо видалення попередження, я буду стежити за ним і відповідно оновлювати відповідь.

EDITED 29.09.2018 : classпотрібно, якщо змінна, яка буде зберігати екземпляр, повинна бути слабкою (наприклад, делегат). Якщо вам не потрібна слабка змінна, ви можете пропустити classі просто напишіть наступне, і жодних попереджень не буде:

protocol AddsMoreCommands where Self: UIViewController {
   // code
}

5
Як випадково, що я натиснув на дворічне питання і знайшов ідеальне рішення, опубліковане годину тому 😲
Оскар Апеленд

Xcode 9.1 тепер дає мені попередження щодо цієї приказки: Надмірне обмеження макета 'Self': 'AnyObject'. Обмеження обмеження макета 'Self': тут мається на увазі 'AnyObject'. Зміна мого коду на формат прийнятої відповіді здається кращою.
Zig

2
Станом на Xcode 9.1 тепер використовуються лише протоколи класу AnyObjectзамість class. protocol AddsMoreCommands: AnyObject where Self: UIViewController { // code }
dodgio

@dodgio все ще отримує те саме попередження, використовуючиAnyObject
rgkobashi

1
@ DávidPásztor ви маєте рацію, однак, якщо ви хочете використовувати його за структурним шаблоном, таким як делегування, щоб зробити властивість слабким, потрібно явно додати "клас" :)
rgkobashi

48

Через проблему в попередній відповіді я отримав таку декларацію:

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

відсутні попередження в Xcode 9.1


5
Виправте мене, якщо я помиляюся, але проблема з цим у вирішенні вище (яке генерує попередження в Xcode 9.1 і вище) полягає в тому, що ви не можете оголосити делегата слабким?
Кайл Гослан,

Крім того, коли я використовую це рішення з Swift 4.1, мені потрібно відтворити властивості того, AddsMoreCommandsдо UIViewControllerякого я хотів уникнути ...
fl034

9
Щоб уникнути типового складання, ви можете зробити це:typealias AddsMoreCommandsViewController = UIViewController & AddsMoreCommands
Плюс

35

Тепер у Swift 5 ви можете досягти цього, виконавши:

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

Досить зручно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.