Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

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

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

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

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

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

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

Ответ 2

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

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

Ответ 3

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

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

Категории

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

Ответ 4

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

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

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

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

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

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

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

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

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

Ответ 5

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

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

Структуры Cocoa определяют многочисленные категории, большинство из которых - неофициальные протоколы. Часто они используют категории для группировки связанных методов. Вы можете внедрять категории в свой код для расширения классов без подкласса или группировать связанные методы. Однако вы должны знать об этих оговорках:

- > Вы не можете добавить переменные экземпляра в класс.
- > Если вы переопределите существующие методы класса, ваше приложение может вести себя непредсказуемо.

Ответ 6

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

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

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

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

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

Ответ 7

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

Ответ 8

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

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