Материал является примером, который демонстрирует возможности языка и не претендует на звание «хороший код». Материал предназначен начинающим разработчикам для общего ознакомления. Весь свой информационный мусор, я коллекционирую на своей стене в ВК, так что добро пожаловать. Немного от себя Вот уж не знаю почему, но многих протоколы пугают, их боятся использовать, понимать и в целом избегают как огня, что является в корне неверным выбором. Иными словами, если Вам не нравятся протоколы, Вы просто не умеете их готовить. Если разобраться поглубже, язык Swift, является крайне продуманным и собрал в себе все лучшее из многообразия языков. Он быстрый, продуманный и очень оптимизированный. Каждый его инструмент, всегда преследует определенную цель и не всегда понятно с первого раза, какую же такую цель преследует изучаемый инструмент, но поверьте, цель есть всегда. Так и у протоколов есть масса возможностей и перекочевали они с Objective-C не просто так. Начнем мы с простого и плавно перейдем к более сложному (хотя протоколы весьма просты в усвоении и очень даже функциональны). Вопреки критике, я буду все так же, подробно, разбирать каждый момент т.к. напоминаю, что материал предназначен именно для начинающих разработчиков. Ну что же, давайте начинать. Давайте начнем с постановки простой, фейковой задачи. Нам необходимо разработать функцию, которая получает некий класс/структуру, берет свойство count и возвращает нам квадрат этого значения, пускай в Int. Эту функцию мы будем передавать другим разработчикам, чтобы они могли её использовать. Казалось бы, в чем проблема? Но давайте подумаем... Какой тип данных указать во входных параметрах функции? Any? Не очень удачное решение т.к. никто не знает какой тип данных будет использован в ней и приведение типов выполнить не получится. Можно конечно решить ситуацию посредством дженериков, но это тема для другой публикации. Подумайте немного, над этой задачей. Она не так проста как кажется на первый взгляд и все было бы печально, если бы не протоколы. Посмотрите на код ниже, и начинайте постигать убийственную мощь протоколов. Внезапно и удивительно, но оказывается, что протокол является типом данных. Мы можем его создать, описать и использовать. В момент создания протокола, Вы просто описываете содержимое потенциального типа, который будет его использовать (будет следовать протоколу, будет подписан на протокол и т.д.), а потом в момент создания типа, указываете протокол, чтобы сказать компилятору «привет, я класс и я следую протоколу», если тип не соответствует протоколу, Xcode выдаст подсказку и в большинстве случаев, даже предложит исправить несоответствие. В коде выше, как Вы уже вероятно догадались, мы создали простой протокол, который декларирует простое свойство count и его тип данных, не более (конструкция { get }, говорит о том, что свойство должно быть доступно для чтения) А потом, с его помощью(протокола), создали функцию из первоначальной задачи. Давайте теперь создадим класс, который соответствует протоколу. синтаксис такой же как при наследовании классов Так как у нас были указания исключительно о необходимости наличия свойства count для чтения, нам никто не запрещает использовать константу и класс выше соответствует декларации. Теперь создадим структуру под наш протокол. У нее есть, еще свойство, помимо count, но это не является нарушением протокола т.к. протокол говорить только о том, что должно быть, а не то, чего быть не должно. Давайте попробуем это с нашей функцией. Все работает. Давайте добавим классу MegaClass, свойство property для наглядности. Теперь обратите внимание на важный момент. Если мы будем обращаться к типу, который соответствует протоколу внутри функции, даже при наличии иных свойств/методов, нам будет доступно только описанное в протоколе. Грубо говоря, протокол определяет, что конкретно есть у типа и дает возможность с этим взаимодействовать. Точно таким же образом, мы можем поместить разные типы в массив если они соответствуют определенному протоколу. В общем протокол простыми словами это - тип данных, декларация описывающая тип и средство обобщения различных типов т.к. его можно использовать с class, struct, enum. Теперь я думаю понятно, когда вы будете передавать свой код другому разработчику, он всегда сможет привести свои типы к соответствию с необходимым протоколом без каких-либо сложностей. Конечно же протоколы умеют в наследование, причем множественное и типы данных могут соответствовать нескольким протоколам Если класс имеет суперкласс в виде класса, который соответствует какому-либо протоколу, то естественно он так же будет ему соответствовать. Опять же ожидаемо и использование подобных типов в работе без каких либо проблем. Давайте для более простого понимая, представим следующее: протоколы Папа, Мама и общий протокол Ребенок. Некий класс Класс, который соответствует протоколу Ребенок у которого есть подкласс Подкласс. Некая функция/массив/что-либо еще,  умеющие работать с типами, которые соответствуют протоколу Мама  Мы можем передать в функцию/массив и т.д. которые требуют соответствие протоколу Мама как Класс так и Подкласс т.к. они оба соответствую ему (протоколу Мама) через наследование. Эта логичная концепция конечно бывает сложна для понимания, но на самом деле очень проста. Необходимо просто переварить. А еще лучше просто побаловаться в коде. Ничего не заменит практику. Если классу необходимо наследовать какой-либо класс и соответствовать протоколу/протоколам, то первым указывается суперкласс, а далее идут протоколы. Протоколы могут декларировать так же методы и инициализаторы, но про инициализаторы в протоколах лучше говорить в отдельной статье т.к. это обширный материал, пока могу сказать, что инициализатор следует помечать как обязательный для потенциальных подклассов, через required как видно из листинга выше, нам необязательно использовать аргумент инициализатора в подобной реализации т.к. протокол определяет инициализатор, а не  его тело. С методами та же история, почти... обратите внимание - для удобства восприятия, я помечаю типы цифрами, никогда не делайте так в коде мы определяем тип метода, а что в нем происходит, протокол не интересует Если метод должен изменять значения, то его следует пометить как mutating, это не обязательное требование, но его игнорирование заблокирует нормальное использование такого протокола со структурами. Хотя протоколы можно использовать с различными типами, мы можем ограничить протокол только для использования с классами ранее использовалось для декларирования слабых ссылок (в Swift 5 вызовет ошибку) обратите внимание констукция { get set } говорит о том, что свойство должно уметь менять значение т.е. константой его объявлять нельзя, только переменной. И как обсуждалось ранее, get разрешает использовать константы. Использовать set без get нельзя. сейчас практическое применение может понадобится, например для использования опциональных методов. Это невозможно в Swift реализации, но было возможно в Objective-c, а так как Swift обратно совместим с ним, мы все же можем использовать эту возможность. не забудте импортировать Foundation для доступа к @objc но в таком случае у нас нет жесткой необходимости использовать AnyObject т.к. подобный протокол и так не будет функционировать со структурами. Соответственно опциональные методы как следует из названия не являются обязательными и класс без них, вполне себе будет соответствовать протоколу Ну вот мы и добрались до истинной мощи протоколов. Казалось бы, ну декларация, ну удобная,  но мне и так нормально, сами используйте свои протоколы, мне и так хорошо. Работаю я один, свой код знаю, все пучком. Нет! Это ошибочное суждение!Уверен сейчас, ваше мировоззрение изменится раз и навсегда, а первая мысль будет «черт, почему я не использовал это раньше...», начнем. Сейчас вам должно уже быть все понятно. Есть два протокола, который декларируют по свойству. Протокол который наследуется от них и два типа, класс со структурой. А теперь добавим вот такой код Однако здравствуйте, я думаю вы уже поняли, все эти возможности появляются у наших типов, которые соответствуют протоколу в доступе. В расширениях протокола можно не только объявлять методы, но и задавать им логику. Дополнять протокол вычисляемыми значениями и даже определять инициализатор, но с нюансами. Давайте изменим наш код добавим инициализатор в протокол, это заставит нас изменить наш класс (структуры не касается т.к. структуры не наследуются) и расширим наш SuperProtocol дополнительным инициализатором нам необходимо вызывать существующий инициализатор в расширении, гарантируя таким образом полную инициализацию типа. Но как я уже говорил ранее, инициализаторы в протоколах - отдельная история. Диспетчеризация методов, посмотрите на код как думаете, какой метод будет вызван? method dispatch работает таким образом, что отдает приоритет типу, а константа myClass относится к типу ClassExample т.к. неявное присваивание типа, определяет её как класс, а не протокол. Но если мы явно укажем тип ProtocolExample, то будет вызван метод протокола. Соответственно во всех функциях/методах/массивах и т.д., во всем, что работает с типом протокола, приоритет будет за методом протокола. 2. Можно перечислять несколько протоколов для взаимодействия 3. В протоколах нельзя определять доступы (private и т.д.), но можно сделать вот так За сим, я думаю достаточно. Еще конечно есть сопоставления протоколов, но там уже будет необходимо понимание дженериков, протоколы с использованием дженериков, а дженерики это как я уже говорил - другая история.  Итоги по протоколам: Используются с class, struct, enum Не хранят состояние Могут быть унаследованы другими протоколами Поддерживают множественное наследование В расширениях можно описывать логику Не указывают слабые ссылки Не контролируют доступ без расширений See you later... Разработчик