Очень сложно найти полный список директив компилятора Objective-C в одном месте. Всем конечно известны @interface, @implementation, но есть и такие, как @dynamic и @encode которые встречают гораздо реже, и зачастую понимаются неправильно.
Вот их полный список, разъяснения приводятся под катом:
- @class
- @protocol @required @optional @end
- @interface @public @package @protected @private @property @end
- @implementation @synthesize @dynamic @end
- @throw @try @catch @finally
- @synchronized @autoreleasepool
- @selector @encode
- @compatibility_alias
- @”string”
@class
Используется для предварительного объявления класса. При использовании этой директивы класс помечается как известный, даже без загрузки заголовочного файла.
1
@class ClassName
Однако, в отличии от @protocol и @selector вы не можете написать следующее для получения класса по имени
1
2
// ОШИБКА: это работать не будет!
Class c = @class(ClassName);
используйте вместо этого
1
Class c = [ClassName class];
@protocol @required @optional @end
Директивы используются для объявления протокола. Кроме того, протокол может адаптировать другие протоколы.
1
2
3
4
5
6
@protocol ProtocolName<aProtocol, anotherProtocol>
@required
// объявление сообщений
@optional
// объявление сообщений
@end
Также как и в случае с @selector вы можете использовать @protocol для получения объекта по имени:
1
2
3
4
-(void)aMethod
{
Protocol* aProtocol = @protocol(ProtocolName);
}
Зависимые директивы
- @requred (используется по-умолчанию) - Определяет методы, которые следуют после @required как обязательные.
- @optional - Определяет методы, которые следуют после @optional как необязательные. Классы, которые адаптируют протокол, могут сами решать - реализовывать эти методы или нет. Классы, которые используют необязательные методы протокола, должны делать проверку на существование. Например:
1
[object respondsToSelector: @selector(optionalProtocolMethod)];
- @end - определяет завершение объявления протокола
@interface @public @package @protected @private @property @end
@interface - определяет начало объявления класса или категории.
Объявление класса
Класс предок может не объявляться, однако, все классы Objective-C должны напрямую или косвенно наследоваться от NSObject. Директива @interface может определять также, что класс адаптирует определенные протоколы:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@interface ClassName : SuperClassName<aProtocol, anotherProtocol>
{
@public
// переменные экземпляра
@package
// переменные экземпляра
@protected
// переменные экземпляра
@private
// переменные экземпляра
}
// объявление свойств
@property(atomic, readwrite, assign) id aProperty;
// публичные методы класса и экземпляров
@end
Объявление категории
Директива @interface для категорий не может добавлять переменных экземпляра. Однако, она может определять, что категория адаптирует дополнительные протоколы. Имя категории может быть опущено (остаются только круглые скобки), если категория добавляется в файл реализации для добавления частных методов класса.
1
2
3
4
5
6
7
@interface ClassName(CategoryName)<aProtocol, anotherProtocol>
// объявление свойств
@property(nonatomic, retain) NSString* stringProperty;
// объявление методов
@end
Зависимые директивы
- @public - Определяет, что переменные экземпляра, следующие за директивой будут доступны публично. Публичные переменные могут быть прочтены и изменены с помощью следующей конструкции:
1
someObject->aPublicVariable = 10;
- @package - Определяет, что переменные экземпляра, следующие за директивой будут публично доступны в библиотеке, которая определяет класс, но закрытыми за пределами этой библиотеки. Важное замечание, это справедливо только для 64-разрядных систем. На 32-разрядных системах имеет то же значение, что и @public
- @protected (по умолчанию) - Определяет, что переменные экземпляра, следующие за директивой, будут доступны только для класса и его потомков.
- @private - Определяет, что переменные экземпляра, следующие за директивой, будут доступны только в пределах данного класса
@property - Определяет свойство, которое может быть использовано с помощью точечной нотации. За директивой @property могут следовать необязательные круглые скобки, которые содержат дополнительные ключевые слова, которые определяют поведение свойства. Вот они:
- readwrite (по-умолчанию) и readonly - генерируются одновременно сеттеры и геттеры (setters/getters) или только геттеры
- assign (по-умолчанию) и retain, copy - применяются только для свойств, которые могут быть безопасно приведены к id. Assign - просто присваивает переданное значение. Retain - посылает release текущему значению переменной экземпляра, потом посылает retain новому объекту, и присваивает новое значение переменной экземпляра. Copy - посылает release текущему значению переменной экземпляра, затем copy новому объекту и присваивает новый объект переменной экземпляра. В последних двух случаях, вы должны послать release (или присвоить nil) свойству при dealloc.
- atomic, (по-умолчанию) и nonatomic - свойства с ключевым словом atmoic - потокобезопасны, с nonatomic - могут быть проблемы при многопоточном доступе. Доступ к nonatomic свойствам обычно быстрее чем к atomic, поэтому они часто используются в однопоточных приложениях.
weak (по-умолчанию) и strong - доступны, если включен автоматический подсчет ссылок (Automatic Reference Counting - ARC). В этом случае strong - это синоним для retain, в то время как weak - assign, с одним лишь исключением, что свойство с weak автоматически устанавливается в nil когда объект уничтожается. Также следует учитывать, что ключ weak доступен только начиная с iOS 5 и Mac OS X 10.7 (Lion).
- @end - Определяет завершение объявления класса или категории
@implementation @synthesize @dynamic @end
Директива @implementation определяет начало определения (реализации) класса или категории.
Определение класса
1
2
3
4
5
6
7
8
9
@implementation ClassName
@synthesize aProperty, bProperty;
@synthesize cProperty = instanceVariableName;
@dynamic anotherProperty;
// определение методов
@end
Определение категории
1
2
3
4
5
6
7
8
9
@implementation ClassName ( CategoryName )
@synthesize aProperty, bProperty;
@synthesize cProperty = instanceVariableName;
@dynamic anotherProperty, bnotherProperty;
// определение методов
@end
Зависимые директивы
- @synthesize - дает указание компилятору, что необходимо автоматически сгенерировать сеттеры и геттеры для данных (разделенных запятой) свойств. Сеттеры и геттеры автоматически создаются согласно указанным в объявлении свойства директивам. Если переменные экземпляра называются не так, как указано после директивы @property, вы можете соединить их с помощью знака равенства
- @dynamic - сообщает компилятору, что требуемые сеттеры и геттеры для данных свойств будут реализованы вручную или динамически во время выполнения. При доступе к таким свойствам, компилятор не будет выдавать предупреждений, даже если требуемые сеттеры и геттеры не реализованы. Вы можете использовать такие свойства, когда хотите, чтобы сеттеры и геттеры выполняли какой-то специфичный для вас код.
- @end - указывает на завершение определения класса или категории
@throw @try @catch @finally
Директивы используются для обработки исключений
Посылка и обработка исключений
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@try
{
// код, который может кинуть исключение ... как например
NSException* exception = [NSException exceptionWithName: @"ExampleException"
reason: @"In your face!"
userInfo: nil];
@throw exception;
}
@catch (CustomException* ce)
{
// код обработки определенного исключения
}
@catch (NSException* ne)
{
// код обработки всех остальных исключений
// чтобы просто пробросить исключение дальше
@throw;
}
@finally
{
// код, который выполнится всегда после обработки, несмотря на то
// было исключение или нет
}
@synchronized
Заключает блок кода в мьютекс. Обеспечивает гарантию того, что блок кода и объект блокировки будут доступны только из одного потока в момент времени.
1
2
3
4
5
6
7
-(void)aMethodWithObject:(id)object
{
@synchronized(object)
{
// код, который работает с объектом блокировки
}
}
@autoreleasepool
В тех приложения, в которых вы используете автоматический подсчет ссылок (ARC), вы должны использовать @autoreleasepool как замену для NSAutoreleasePool. И вообще, @autoreleasepool примерно в 6 раз быстрее, чем NSAutoreleasePool, поэтому Apple рекомендует использовать его даже для не-ARC приложений.
Кроме того, вы не должны определять переменную внутри блока @autoreleasepool и затем продолжать использовать ее после. Подобный код должен быть исключен.
Пример использования:
1
2
3
4
5
6
7
-(void)aMethod
{
@autoreleasepool
{
// код, который создает большое количество временных объектов
}
}
@selector
Возвращает специальный тип селекторов SEL выбранного метода Objective-C. Генерирует предупреждение компилятора, если метода не объявлен или не существует.
1
2
3
4
5
-(void)aMethod
{
SEL aMethodSelector = @selector(aMethod);
[self performSelector: aMethodSelector];
}
@encode
Возвращает кодировку типа.
1
2
3
4
5
6
7
8
9
10
-(void)aMethod
{
char* enc1 = @encode(int); // enc1 = "i"
char* enc2 = @encode(id); // enc2 = "@"
char* enc3 = @encode(@selector(aMethod)); // enc3 = ":"
// практический пример
CGRect rect = CGRectMake(0, 0, 100, 100);
NSValue* v = [NSValue value: &rect withObjCType: @encode(CGRect)];
}
@compatibility_alias
Позволяет вам задать псевдоним для существующего класса. Первый параметр - имя псевдонима для имени класса, класса с таким именем не должно существовать. Второй параметр - имя существующего класса, для которого создается псевдоним.
1
@compatibility_alias AliasClassName ExistingClassName
После этого, вы можете использовать AliasClassName вместо ExistingClassName. Это может быть полезно после переименования класса без изменения его поведения. Вы можете использовать @compatibility_alias для того, чтобы не делать много изменений в существующем коде.
@”string”
Объявляет константный объект класса NSString. Для таких строк не требуется вызывать retain или release.
1
2
3
4
5
-(void)aMethod
{
NSString* str = @"This is a constant string.";
NSUInteger strLength = [@"This is legal!" length];
}
Заключение
Я надеюсь, что вам понравился этот список, и он будет полезен вам. Если есть какие-то директивы, которых нет в списке, пожалуйста опишите их в комментариях к статье. Буду очень благодарен.
По мотивам тут.