Расширение класса Objective-C

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

вот мой первый вопрос. В чем разница между использованием расширения класса для объявления частного метода и его вообще не объявлять (кажется, что он компилируется в run в обоих случаях)? (Пример 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

второй вопрос: в чем разница между объявлением ivars внутри расширения и объявлением его непосредственно внутри реализации? (Например, 3 против 4)

пример 3

@interface Class() {
    NSArray *mySortedArray;
}
@end

@implementation Class
@end

Пример 4

@implementation Class
NSArray *mySortedArray;
@end

у меня есть последний вопрос о соглашениях кодирования: когда я должен поставить подчеркивание (_) перед именем переменной?

спасибо

5 ответов


методы в классе расширений

раньше не было случая, когда вам не нужно было объявлять свои частные методы. До недавнего времени вам нужно было где-то объявить свои частные методы, и большинство людей выбрали расширение класса для этого. Из Xcode 4.4 (я считаю) компилятор достаточно умен, чтобы определить, какие методы должны быть частными в этой реализации, устраняя необходимость объявлять их в другом месте.

переменные в расширения класса

что касается примеров 3 и 4, Будьте осторожны. В пределах расширения класса переменная является переменной экземпляра для этого класса (Пример 3). Пример 4 объявляет глобальную переменную (из-за того, что она следует за семантикой глобальной переменной из C). Придерживайтесь примера 3 для переменных частного экземпляра.

правила кодирования

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


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

правильно.

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

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

в чем разница между объявлением ivars внутри расширения и объявлением его непосредственно внутри реализации?

в 4-м примере это глобальная переменная C, это не переменная экземпляра вашего класса.

когда я должен поставить подчеркивание ( _ ) перед именем переменной?

когда вы хотите, просто сделай это последовательно. Всегда или никогда.


в вопросе 1, Пример 2: Методы foo и bar, реализованные в классе, видны экземплярам класса. Если foo и bar не объявлены в отдельном файле заголовка, а файл реализации не доступен, другой класс не будет знать о существовании foo и bar. foo и bar являются частными методами; экземпляры класса по-прежнему будут отвечать на сообщения foo и bar. Кроме того, Xcode будет помечать предупреждение, если другой класс, который пытается отправить сообщение foo и bar, поскольку Xcode не может проверить (без объявления в заголовочном файле), что foo и bar существуют. Напротив, пример 1 объявление bar позволяет любому другому классу отправлять панель сообщений экземплярам класса. Xcode также не будет отмечать ошибку для любого сообщения, если класс @interface находится в файле заголовка, который является #import другим классом.

в вопросе 2, Пример 4: mySortedArray-это локальный неизменяемый массив, объявленный с локальной областью в классе. В mySortedArray в Примере 3, является переменной экземпляра типа NSArray доступен для другого класса, который создает экземпляр класса.


Надежда подкласс-категория-и-расширения может быть полезным для вас.