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

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

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

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

Спасибо


person Jean-Francois Gagnon    schedule 03.02.2013    source источник
comment
mySortedArray в примере 4 является переменной C, если вы не добавите {} вокруг нее   -  person Jano    schedule 03.02.2013
comment
Что касается подчеркиваний, принято добавлять их к переменным экземпляра, например: _mySortedArray   -  person Aaron Wojnowski    schedule 03.02.2013
comment
Я добавлю, что это соглашение, предложенное Apple. См. Объявленные свойства и переменные экземпляра   -  person Jano    schedule 03.02.2013


Ответы (5)


Методы в расширениях классов

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

Переменные в расширениях классов

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

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

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

person WDUK    schedule 03.02.2013
comment
Значит ли это, что на данный момент у расширений классов нет реального варианта использования, верно? - person SexyBeast; 14.10.2014
comment
@Cupidvogel Совсем неправда. Я широко использую их, чтобы декларировать соответствие протоколу и определения свойств в частном порядке, не раскрывая их общедоступному заголовку. Это сохраняет общедоступный заголовок чистым и кратким, не загрязняя его свойствами / протоколами, которые являются частными деталями реализации. - person WDUK; 14.10.2014

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

Правильный.

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

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

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

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

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

Когда хотите, просто делайте это постоянно. Всегда или никогда.

person Community    schedule 03.02.2013
comment
Поскольку mySortedArray объявлен в реализации и end, которые анализируются как Objective-C, а NSArray является объектом (C не является объектно-ориентированным), является ли mySortedArray глобальной переменной C? - person Global nomad; 03.02.2013
comment
@Globalnomad В примере 3 это не так. В примере 4 это так. - person ; 03.02.2013

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

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

person Global nomad    schedule 03.02.2013

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

person Smith    schedule 14.11.2013

Отличное объяснение расширений и категорий классов,

http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html

person Darshan    schedule 21.04.2013