Переопределение методов с использованием категорий в Objective-C

87

Могу ли я использовать категорию класса для переопределения метода, который уже реализован с использованием категории? Как это:

1) Оригинальный метод

-(BOOL) method {
  return true;
}

2) Переопределенный метод

-(BOOL) method {
  NSLog(@"error?"); 
  return true; 
}

Будет ли это работать или это незаконно?

ретикс
источник

Ответы:

146

Из документации Apple :

Хотя язык Objective-C в настоящее время позволяет использовать категорию для переопределения методов, наследуемых классом, или даже методов, объявленных в интерфейсе класса, вам настоятельно не рекомендуется делать это . Категория не заменяет подкласс. Использование категории для переопределения методов имеет несколько существенных недостатков:

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

  • Категория не может надежно переопределить методы, объявленные в другой категории того же класса.

    Эта проблема имеет особое значение, потому что многие классы Какао реализованы с использованием категорий. Определяемый структурой метод, который вы пытаетесь переопределить, мог сам быть реализован в категории, поэтому не определено, какая реализация имеет приоритет.

  • Само наличие некоторых методов категорий может вызвать изменение поведения во всех фреймворках. Например, если вы переопределите windowWillClose:метод делегата в категории на NSObject, все оконные делегаты в вашей программе затем ответят, используя метод категории; поведение всех ваших экземпляров NSWindow может измениться. Категории, которые вы добавляете в класс фреймворка, могут вызвать загадочные изменения в поведении и привести к сбоям.

Бенуа
источник
Спасибо, но я это уже знаю. Мне просто интересно, законно мое дело или нет. Мой случай немного отличается от документов. :)
retix
Почему другое? В документе говорится, что это законно, ЕСЛИ исходный метод не входит в категорию, но настоятельно не рекомендуется. Тогда ты сможешь это сделать ...
Бенуа
1
Спасибо за совет. Я плохо говорю на этом языке. Я получил от вас новую информацию.
retix
1
Правильно ли переопределить метод категории, объявленный и реализованный в категории суперкласса?
BergP
2
Ссылка не работает, это новая версия? developer.apple.com/library/ios/documentation/Cocoa/Conceptual/…
RndmTsk
18

Вы можете сделать это, адаптировав подход Class Cluster или используя технику swizzling методов.

В противном случае поведение двух или более категоризированных методов не определено.

Мартин Бабачаев
источник
9

Ссылка на старую документацию мертва; лучшая замена, которую я смог найти, была здесь: Apple Docs :

Избегайте конфликтов имен методов категорий

Поскольку методы, объявленные в категории, добавляются к существующему классу, вы должны быть очень осторожны с именами методов.

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

Apple использует более легкое прикосновение, но суть та же: вы приглашаете катастрофу, потому что непредсказуемое поведение молчит.

AmitaiB
источник
2

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

Из этого руководства http://rypress.com/tutorials/objective-c/categories

Vinuta
источник