Домашняя страница Полный список директив компилятора Objective-C 2.0
Публикация
Отменить

Полный список директив компилятора Objective-C 2.0

Очень сложно найти полный список директив компилятора 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];
}

Заключение

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

По мотивам тут.

Публикация защищена лицензией CC BY 4.0 .