Расширение класса Objective-C
Как довольно новый программист objective-c (с опытом работы в течение 4 лет), похоже, мне сложно понять, когда использовать расширения класса. Из того, что я понял (и, пожалуйста, исправьте меня, если я ошибаюсь), основное различие между категориями и расширениями состоит в том, что расширение предполагает, что вы реализуете методы внутри своей основной реализации, тогда как с категорией это может быть в другой реализации, Также кажется, что люди используют расширения, главным образом, для частных методов.
Вот мой первый вопрос. Какая разница между использованием расширения класса для объявления частного метода, а не объявлением его вообще (он, похоже, скомпилирован в обоих случаях)? (пример 1 против 2)
Пример 1
@interface Class()
-(void) bar;
@end
@implementation Class
-(void) foo {
[self bar];
}
-(void) bar {
NSLog(@"bar");
}
@end
Пример 2
@implementation Class
-(void) foo {
[self bar];
}
-(void) bar {
NSLog(@"bar");
}
@end
Второй вопрос: Какая разница между объявлением иваров внутри расширения и объявлением его непосредственно внутри реализации? (Пример 3 против 4)
Пример 3
@interface Class() {
NSArray *mySortedArray;
}
@end
@implementation Class
@end
Пример 4
@implementation Class
NSArray *mySortedArray;
@end
У меня есть последний вопрос о соглашениях о кодировании: когда я должен поставить знак подчеркивания (_) перед именем переменной?
Спасибо
Ответы
Ответ 1
Методы расширения класса
Никогда не случалось так, что вам не нужно было объявлять свои частные методы. До недавнего времени вам нужно было где-то объявлять свои частные методы, и большинство людей выбрали расширение класса для этого. Из Xcode 4.4 (я считаю) компилятор достаточно умен, чтобы определить, какие методы должны быть частными в рамках этой реализации, устраняя необходимость объявления их в другом месте.
Переменные в расширениях классов
Как и для примеров 3 и 4, будьте осторожны. Внутри расширения класса переменная является переменной экземпляра для этого класса (пример 3). Пример 4 объявляет глобальную переменную (из-за того, что она следует глобальной семантике переменных из C). Придерживайтесь примера 3 для ваших частных переменных экземпляра.
Соглашения о кодировании
Что касается соглашения о кодировании, то разработчику/команде решать, использовать ли подчеркивание или нет. Наша команда использует m_
для частных переменных экземпляра. Apple в своей документации, используя символы подчеркивания (что стиль именования для базовых переменных экземпляра для синтезированных свойств). Важно, быть последовательным во всем коде.
Ответ 2
Основное различие между категориями и расширениями состоит в том, что расширение предполагает, что вы реализуете методы внутри своей основной реализации, тогда как с категорией это может быть в другой реализации. Также кажется, что люди используют расширения, главным образом, для частных методов.
Правильно.
В чем разница между использованием расширения класса для объявления частного метода и вообще не объявлять его (он, кажется, компилируется в обоих случаях)?
Возможно, просто предупреждение компилятора относительно незаявленного селектора. (Конечно, он работает нормально - метод реализован и существует.) Также обратите внимание, что для компилятора требуется декларация (известная, правильная сигнатура функции), чтобы испускать ABI-совместимый, правильный двоичный код. Предположение, что он делает о незаявленных методах (а именно, что они возвращают id
и принимает переменные аргументы), может быть неверным - вызов функции с помощью указателя несовместимого типа - это поведение undefined.
Какая разница между объявлением ivars внутри расширения и объявлением его непосредственно внутри реализации?
В четвертом примере это глобальная переменная C, она не переменная экземпляра вашего класса.
когда я должен поставить знак подчеркивания (_) перед именем переменной?
Всякий раз, когда вы хотите, просто делайте это последовательно. Всегда или никогда.
Ответ 3
В вопросе 1, пример 2:
Методы foo и bar, реализованные в классе, видны экземплярам класса. Если foo и bar не объявлены в отдельном файле заголовка И файл реализации не доступен, другой класс не будет знать о существовании foo и bar. foo и bar - частные методы; экземпляры класса будут реагировать на сообщения foo и bar. Кроме того, Xcode будет отмечать предупреждение, если другой класс, который пытается сообщить foo и bar, поскольку Xcode не может проверить (без объявления в файле заголовка), что существуют foo и bar.
Напротив, объявление 1-го примера в баре позволяет любому другому классу отправлять панель сообщений экземплярам класса. Xcode также не будет отмечать ошибку для любого сообщения, чтобы bar, если @interface Class находится в заголовочном файле, который является #import другим классом.
В вопросе 2, пример 4:
mySortedArray - это локальный неизменяемый массив, объявленный с локальной областью действия класса. В примере 3 mySortedArray представляет собой переменную экземпляра типа NSArray, доступную для другого класса, которая создает экземпляр класса.
Ответ 4
Надежда subclass-category-and-extensions может быть вам полезна.
Ответ 5
Отличное объяснение по расширениям классов и категориям,
http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html