Может ли кто-нибудь объяснить мне разницу между категориями и наследованием в Objective C? Я читал the entry in Wikipedia, и обсуждение категорий там не похоже на наследование. Я также рассмотрел дискуссию по этой теме в книге «Open iPhone Development», и я до сих пор ее не понимаю.В чем разница между наследованием и категориями в Objective-C
ответ
Иногда наследование просто кажется более сложным, чем того стоит. Он корректно используется, когда вы хотите добавить что-то в существующий класс, который является изменением поведения этого класса.
С категорией вы просто хотите, чтобы существующий объект сделал немного больше. Как уже было сказано, если вы просто хотите иметь класс строк, который обрабатывает сжатие, вам не нужно подклассифицировать класс string, вы просто создаете категорию, которая обрабатывает сжатие. Таким образом, вам не нужно изменять тип используемых классов строк.
Ключ в том, что категории только добавляют методы, вы не можете добавлять переменные в класс с помощью категорий. Если класс нуждается в большем количестве свойств, тогда он должен быть подклассифицирован. (Edit: вы можете использовать ассоциативное хранилище, я полагаю).
Категории - отличный способ добавить функциональность и в то же время соответствовать объектно-ориентированному принципу, чтобы предпочесть композицию над наследованием.
Редактировать января 2012
Все изменилось в настоящее время. С текущим компилятором LLVM и современной 64-битной средой выполнения вы можете добавить iVars и свойства в класс расширения (без категорий). Это позволяет сохранить личные iVars из открытого интерфейса. Но, если вы объявляете свойства для iVars, их все равно можно получить/изменить через KVC, потому что в Objective-C по-прежнему не существует частного метода.
Следует отметить, что вы можете * объявлять свойства для существующих ivars с помощью категорий. Под этим я подразумеваю, что вы можете объявить '@ property' и либо' @ synhesize', либо '@ dynamic' в реализации. Я сделал это с помощью свойств 'readonly', хотя, я думаю, они могут быть использованы для чего угодно. То есть, если 'MyClass' имеет' int myVar', то 'MyClass (MyCategory)' может иметь свойство для 'myVar'. – jbrennan
Правда, но это все еще не означает _add_ хранения. – Abizern
Существует такая вещь, как частный метод в Objective-C. Это метод, который определен в @implementation или объявлен в безымянной категории. – Cthutu
Категории позволяют добавлять методы к существующим классам. Поэтому вместо подкласса NSData для добавления ваших новых методов шифрования фанки вы можете добавить их непосредственно в класс NSData. Каждый объект NSData в вашем приложении теперь имеет доступ к этим методам.
Чтобы увидеть, насколько полезным это может быть, посмотреть на: CocoaDev
вы уверены, что просто создав категорию из NSData везде, где используется NSData, эта категория используется, я думал, что вам нужно чтобы категория представляла NSData для использования вместо NSData – hhafez
Она не применяется автоматически к объектам NSData, вам все равно нужно #import заголовок, в котором вы определяете категорию. – Abizern
Нет, классы представляют. Все объекты NSData получают методы загружаемых категорий. – Chuck
A Категория походит на Mixin: модуль в Ruby, или несколько, как интерфейс в Java. Вы можете думать об этом как о «голых методах». Когда вы добавляете категорию, вы добавляете методы в класс. Статья в Википедии содержит good stuff.
, но вы по-прежнему создаете новый класс, не так ли? Так в чем разница между этим и наследованием – hhafez
Нет, вы не создаете новый класс. Вы добавляете методы к существующему классу. – Chuck
@ charlie-martin - Существует большая разница между Ruby Mixins и Objective-C, модуль Ruby не связан с классом, в котором он смешивается, но категория «привязана» к классу. – rnk
Одной из любимых иллюстраций категорий Objective-c в действии является NSString. NSString определяется в рамках Foundation, которая не имеет представления о просмотрах или окнах. Однако, если вы используете NSString в приложении Cocoa, вы заметите, что он отвечает на такие сообщения, как – drawInRect:withAttributes:
.
AppKit определяет категорию для NSString, которая предоставляет дополнительные методы рисования. Эта категория позволяет добавлять новые методы в существующий класс, поэтому мы все еще имеем дело с NSStrings. Если AppKit вместо этого реализует рисование путем подкласса, нам придется иметь дело с «AppKitStrings» или «NSSDrawableStrings» или что-то в этом роде.
Категории позволяют добавлять к существующим классам приложения или методы, относящиеся к домену. Это может быть довольно мощным и удобным.
Если вам, как программисту, предоставляется полный набор исходных кодов для библиотеки или приложения кода, вы можете сходить с ума и изменить все, что вам нужно, чтобы достичь цели программирования с помощью этого кода.
К сожалению, это не всегда так или даже желательно. Много раз вам предоставляется бинарная библиотека/набор объектов и набор заголовков, с которыми можно обойтись.
Тогда новая функциональность требуется для класса, так что вы могли бы сделать несколько вещей:
создать новый класс целое вместо исходного класса - тиражирование все его функции и члены затем переписать все код для использования нового класса.
создать новый класс-оболочку, содержащий класс запаса в качестве члена (компоновку) и переписать код для использования нового класса.
бинарные патчи библиотеки, чтобы изменить код (удачи)
силы компилятор, чтобы увидеть свой новый класс, как и старый, и надеюсь, что это не зависит от определенного размера или места в памяти и конкретные точки входа.
Специализация подкласса - создание подклассов для добавления функциональности и изменения кода драйвера для использования подкласса вместо этого - теоретически проблем должно быть несколько, и если вам нужно добавить данные, это необходимо, но объем памяти будет отличаться , У вас есть преимущество наличия как нового кода, так и старого кода, доступного в подклассе, и выбора метода использования, метода базового класса или переопределенного метода.
изменить необходимый класс objc с определением категории, содержащим методы для выполнения того, что вы хотите, и/или переопределить старые методы в классах запасов.
Это также может исправить ошибки в библиотеке или настроить методы для новых аппаратных устройств или что-то еще. Это не панацея, но позволяет добавлять метод класса без перекомпиляции неизмененного класса/библиотеки. Первоначальный класс одинаков для кода, объема памяти и точек входа, поэтому устаревшие приложения не прерываются. Компилятор просто помещает новый метод (ы) в среду выполнения как принадлежащий этому классу и переопределяет методы с той же сигнатурой, что и в исходном коде.
пример:
У вас есть класс Bing, который выводит на терминал, но не к последовательному порту, и теперь это то, что вам нужно. (по какой-то причине). У вас есть Bing.h и libBing.so, но не Bing.m в вашем наборе.
Класс Bing делает все виды материалов внутри, вы даже не знаете всего, что у вас есть просто публичный api в заголовке.
Вы умны, поэтому вы создаете категорию (SerialOutput) для класса Bing.
[Bing_SerialOutput.m] @interface Bing (SerialOutput) // a category - (void)ToSerial: (SerialPort*) port ; @end @implementation Bing (SerialOutput) - (void)ToSerial: (SerialPort*) port { ... /// serial output code /// } @end
Компилятор обязуется создать объект, который может быть связан с вашим приложением и время выполнения теперь знает, что Bing реагирует на @selector (ToSerial :) и вы можете использовать его, как если бы класс Bing был построен это способ. Вы не можете добавлять только те элементы данных, и это не предназначалось для создания гигантских опухолей кода, привязанных к базовым классам, но оно имеет свои преимущества перед строго типизированными языками.
Лучший способ посмотреть на эту разницу в том, что: 1. наследования: если хотите, чтобы превратить его именно в вашем пути. пример: AsyncImageView для реализации ленивой загрузки. Это делается путем наследования UIView. 2. category: Просто хочу добавить к нему дополнительный аромат. пример: Мы хотим, чтобы заменить все пробела из текста текстового поля в
@interface UITextField(setText)
- (NSString *)replaceEscape;
@end
@implementation UITextField(setText)
- (NSString *)replaceEscape
{
self.text=[self.text stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceCharacterSet]];
return self.text;
}
@end
--- Это добавит новое свойство TextField для вас, чтобы избежать всех пробелов. Точно так же, как добавление к нему нового измерения без полного изменения его пути.
Я думаю, что это очень запутанный ответ. Грамматика ужасна. Совершенно неясно, что подразумевается под поэтической феноменологией, такой как «аромат», «измерение» и «путь». Именование категории (setText) и метода (replaceEscape) для удаления пробелов из текстового поля плохо выбраны, а не описательны. Кроме того, нетрудно сказать, что категории добавляют новые свойства в текстовое поле. Я предполагаю, что «свойство» в этом контексте следует интерпретировать как «метод». – Fnord23
Его просто добавление метода. 'replaceEscape' в поле класса IUText. –
Категория - это функция языка Objective-C, которая позволяет добавлять методы (интерфейс и реализацию) в класс без необходимости создания подкласса. В пределах вашей программы нет разницы во времени выполнения - между исходными методами класса и методами, добавленными в категорию. Методы в категории становятся частью типа класса и наследуются всеми подклассами класса.
Как и в случае с делегированием, категории не являются строгой адаптацией шаблона Decorator, выполняя намерение, но придерживаясь другого пути реализации этого намерения. Поведение, добавленное категориями, является артефактом времени компиляции и не является чем-то динамически приобретенным. Более того, категории не инкапсулируют экземпляр расширяемого класса.
Какао-каркасы определяют многочисленные категории, большинство из которых являются неофициальными протоколами. Часто они используют категории для группировки связанных методов. Вы можете внедрять категории в свой код для расширения классов без подкласса или группировать связанные методы. Однако вы должны знать об этих оговорках:
-> Вы не можете добавить переменные экземпляра в класс.
-> Если вы переопределите существующие методы класса, ваше приложение может вести себя непредсказуемо.
«Методы в категории становятся частью типа класса, и наследуются всеми подклассами класса». Это важное заявление. Как только вы добавите метод в класс, все его подклассы могут получить доступ к этому методу. Поэтому рекомендуется написать категорию в отдельном файле «Class + Category.h», чтобы, если вам не нужен файл .m, вы просто не импортируете его. –
Я думаю, что некоторые из этих ответов, по крайней мере, указывают на мысль о том, что наследование представляет собой более тяжелый способ добавления функциональности к существующему классу, в то время как категории более легкие.
Наследование используется, когда вы создаете новую иерархию классов (все колокола и свистки) и, возможно, приносит много работы, когда выбирается как способ добавления функциональности к существующим классам.
Как здесь кто-то здесь ... Если вы используете наследование для добавления нового метода, например, в NSString, вам нужно пойти и изменить тип, который вы используете, в любом другом коде, в котором вы хотите использовать этот новый способ. Если, однако, вы используете категории, вы можете просто вызвать метод на существующих типах NSString, без подкласса.
Те же цели могут быть достигнуты с помощью либо, но категории, похоже, дают нам возможность, которая проще и требует меньшего обслуживания (возможно).
Кто-нибудь знает, есть ли ситуации, когда категории абсолютно необходимы?
Похоже, вы должны начать отдельный вопрос, касающийся «... бывают ситуации, когда категории абсолютно необходимы?» –
@bobobobo «медведь» как в «несущей бремя путешествия», а не «опускание своей души» – griotspeak