it-swarm.com.ru

В чем разница между наследованием и категориями в Objective-C

Может ли кто-нибудь объяснить мне разницу между категориями и наследованием в Цели C? Я прочитал запись в Википедии и обсуждение категорий там не выглядит иначе, чем наследование. Я также посмотрел обсуждение этой темы в книге "Разработка открытого iPhone" и до сих пор не понимаю.

57
hhafez

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

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

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

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

Изменить январь 2012 г.

Вещи изменились сейчас. С текущим LLVM-компилятором и современной 64-битной средой исполнения вы можете добавлять iVars и свойства к расширениям класса (не категориям). Это позволяет вам держать частные iVars вне публичного интерфейса. Но если вы объявите свойства для iVars, они все равно могут быть доступны/изменены через KVC, потому что в Objective-C до сих пор не существует такого понятия, как закрытый метод.

96
Abizern

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

Чтобы увидеть, насколько это может быть полезно, посмотрите на: CocoaDev

17
Terry Wilcox

Одной из любимых иллюстраций категорий Objective-c в действии является NSString. NSString определяется в платформе Foundation, которая не имеет представления о представлениях или окнах. Однако, если вы используете NSString в приложении Какао, вы заметите, что оно отвечает на сообщения типа – drawInRect:withAttributes:.

AppKit определяет категорию для NSString, которая предоставляет дополнительные методы рисования. Категория позволяет добавлять новые методы в существующий класс, поэтому мы все еще имеем дело с NSStrings. Если бы вместо этого AppKit реализовал рисование путем создания подклассов, нам пришлось бы иметь дело с "AppKitStrings" или "NSSDrawableStrings" или чем-то в этом роде.

Категории позволяют добавлять специфичные для приложения или домена методы к существующим классам. Это может быть довольно мощным и удобным.

11
amrox

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

К сожалению, это не всегда так или даже желательно. Очень часто вам дают набор двоичных библиотек/объектов и набор заголовков.

Затем для класса требуется новая функциональность, чтобы вы могли сделать несколько вещей:

  1. создайте новый класс вместо целого класса - реплицируйте все его функции и члены, затем перепишите весь код, чтобы использовать новый класс.

  2. создайте новый класс-оболочку, который содержит класс stock в качестве члена (композитинг), и перепишите кодовую базу, чтобы использовать новый класс.

  3. бинарные патчи библиотеки для изменения кода (удачи)

  4. заставить компилятор видеть ваш новый класс как старый и надеяться, что он не зависит от определенного размера или места в памяти и конкретных точек входа.

  5. специализация подкласса - создайте подклассы для добавления функциональности и измените код драйвера для использования подкласса - теоретически проблем должно быть немного, и если вам необходимо добавить элементы данных, это необходимо, но объем памяти будет другим. У вас есть преимущество в том, что в подклассе есть и новый код, и старый код, и вы можете выбрать, какой из них использовать: метод базового класса или переопределенный метод.

  6. измените необходимый класс 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 был создан с помощью этого метода. Вы не можете добавлять методы только к элементам данных, и это не было предназначено для создания гигантских опухолей кода, прикрепленного к базовым классам, но оно имеет свои преимущества перед строго типизированными языками.

4
Chris Reid

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

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

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

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

Кто-нибудь знает, есть ли ситуации, когда категории абсолютно необходимы?

3
user3881658

Категория похожа на миксин: модуль в Ruby или как интерфейс в Java. Вы можете думать об этом как о "голых методах". Когда вы добавляете категорию, вы добавляете методы в класс. В статье Википедии есть хорошие вещи .

2
Charlie Martin

Лучший способ взглянуть на это различие заключается в следующем: 1. Наследование: когда вы хотите, чтобы это было точно по-вашему. пример: AsyncImageView для реализации отложенной загрузки. Что делается путем наследования UIView. 2. Категория: Просто хочу добавить дополнительный вкус к нему. пример: мы хотим заменить все пробелы в текстовом поле текста

   @interface UITextField(setText)
      - (NSString *)replaceEscape;
   @end

   @implementation UITextField(setText)
      - (NSString *)replaceEscape
      {
         self.text=[self.text stringByTrimmingCharactersInSet:
                           [NSCharacterSet whitespaceCharacterSet]];
         return self.text;
      }
   @end

--- Это добавит новое свойство в текстовое поле для вас, чтобы избежать всех пробелов. Так же, как добавление нового измерения без полного изменения его пути.

0
Avik Roy