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

StackOverflow https://stackoverflow.com/questions/522341

Вопрос

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

Это было полезно?

Решение

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

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

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

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

Редактировать Январь 2012

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

Другие советы

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Лучший способ взглянуть на это различие заключается в том, что: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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top