Протокол против категории

Может кто-нибудь объяснить различия между протоколами и категориями в Objective-C? Когда вы используете один над другим?

7 ответов

Решение

Протокол - это то же самое, что интерфейс в Java: это, по сути, контракт, который гласит: "Любой класс, реализующий этот протокол, также будет реализовывать эти методы".

Категория, с другой стороны, просто привязывает методы к классу. Например, в Какао я могу создать категорию для NSObject что позволит мне добавить методы к NSObject класс (и, конечно же, все подклассы), хотя у меня на самом деле нет доступа кNSObject,

Подводя итог: протокол указывает, какие методы реализует класс; категория добавляет методы к существующему классу.

Таким образом, правильное использование каждого из них должно быть ясным: используйте протоколы для объявления набора методов, которые должен реализовать класс, и используйте категории для добавления методов в существующий класс.

Протокол гласит: "Вот некоторые методы, которые я хотел бы , чтобы вы реализовали". Категория говорит: "Я расширяю функциональность этого класса с помощью этих дополнительных методов".

Теперь я подозреваю, что ваше замешательство связано с использованием Apple фразы "неофициальный протокол". Вот ключевой (и самый запутанный) момент: неформальный протокол на самом деле не является протоколом вообще. Это на самом деле категория по NSObject. Какао широко использует неформальные протоколы для предоставления интерфейсов для делегатов. Так как @protocol Синтаксис не разрешал дополнительные методы до Objective-C 2.0, Apple реализовала дополнительные методы, чтобы ничего не делать (или возвращать фиктивное значение), и требовала, чтобы методы вызывали исключение. Не было никакого способа обеспечить это через компилятор.

Теперь, с Objective-C 2.0, @protocol синтаксис поддерживает @optional ключевое слово, помечающее некоторые методы в протоколе как необязательные. Таким образом, ваш класс соответствует протоколу, если он реализует все методы, помеченные как @required, Компилятор может определить, реализует ли ваш класс все необходимые методы, что значительно экономит время. IPhone SDK использует исключительно Objective-C 2.0 @protocol синтаксис, и я не могу придумать вескую причину не использовать его в какой-либо новой разработке (за исключением приложений Mac OS X Cocoa, которые должны работать в более ранних версиях Mac OS X).

Категории:

Категория - это способ добавления новых методов ко всем экземплярам существующего класса без изменения самого класса.

Вы используете категорию, когда хотите добавить функциональность к существующему классу, не производя от этого класса или не переписывая оригинальный класс.

Допустим, вы используете NSView объекты в какао, и вы хотите, чтобы все случаи NSView были в состоянии выполнить некоторые действия. Очевидно, что вы не можете переписать NSView класс, и даже если вы производите от него, не все NSView объекты в вашей программе будут вашего производного типа. Решение состоит в том, чтобы создать категорию на NSView, который вы затем используете в своей программе. До тех пор, как вы #import заголовочный файл, содержащий объявление вашей категории, он будет выглядеть так, как будто каждый NSView Объект отвечает на методы, которые вы определили в исходном файле категории.

Протоколы:

Протокол - это набор методов, которые любой класс может выбрать для реализации.

Вы используете протокол, когда хотите предоставить гарантию того, что определенный класс будет реагировать на определенный набор методов. Когда класс принимает протокол, он обещает реализовать все методы, объявленные в заголовке протокола. Это означает, что любые другие классы, которые используют этот класс, могут быть уверены, что эти методы будут реализованы, без необходимости знать что-либо еще о классе.

Это может быть полезно при создании семейства похожих классов, которые должны взаимодействовать с общим классом "контроллера". Связь между классом контроллера и контролируемыми классами может быть упакована в один протокол.

Примечание: язык Objective-C не поддерживает множественное наследование (класс может быть производным только от одного суперкласса), но большая часть той же функциональности может быть обеспечена протоколами, поскольку класс может соответствовать нескольким различным протоколам.

Насколько я понимаю, протоколы немного похожи на интерфейсы Java. Протоколы объявляют методы, но реализация зависит от каждого класса. Категории кажутся чем-то вроде миксинов Руби. С помощью категорий вы можете добавлять методы в существующие классы. Даже встроенные классы.

Протокол позволяет вам объявить список методов, которые не ограничены каким-либо конкретным классом или категориями. Методы, объявленные в протоколе, могут быть приняты любым классом / категориями. Класс или категория, которые принимают протокол, должны реализовывать все необходимые методы, объявленные в протоколе.

Категория позволяет добавлять дополнительные методы в существующий класс, но они не допускают дополнительных переменных экземпляра. Методы, которые добавляет категория, становятся частью типа класса.

Определения из "Программирование в Objective-C" С.Г.Кочана:

Категории:

Категория предоставляет вам простой способ модульного определения класса на группы или категории связанных методов. Это также дает вам простой способ расширить существующее определение класса, даже не имея доступа к исходному исходному коду для класса и не создавая подкласс.

Протоколы:

Протокол - это список методов, которые совместно используются классами. Методы, перечисленные в протоколе, не имеют соответствующих реализаций; они должны быть реализованы кем-то другим (как вы!). Протокол предоставляет способ определения набора методов, которые так или иначе связаны с указанным именем. Методы обычно документируются, чтобы вы знали, как они должны выполняться, и чтобы вы могли реализовать их в своих определениях классов, если это необходимо. В протоколе указывается набор методов, некоторые из которых вы можете по желанию реализовать, а другие - что вам необходимо реализовать. Если вы решите внедрить все необходимые методы для определенного протокола, вы должны будете принять или принять этот протокол. Вы можете определить протокол, в котором все методы являются необязательными, или протокол, в котором требуются все.

Протоколы - это контракты для реализации указанных методов. Любой объект, который соответствует протоколу, соглашается предоставить реализации для этих методов. Хорошим использованием протокола было бы определение набора методов обратного вызова для делегата (где делегат должен отвечать на все методы).

Категории предоставляют возможность расширять текущий объект, добавляя к нему методы (методы класса или экземпляра). Хорошее использование категории - расширение класса NSString для добавления функциональности, которой раньше не было, например, добавление метода для создания новой строки, которая преобразует получатель в 1337 5P34K.

NSString *test = @"Leet speak";
NSString *leet = [test stringByConvertingToLeet];
Другие вопросы по тегам