Для запроса на автоматический синтез методов доступа служит директива ^synthesize. Она указывается в любом месте раздела реализации класса сколько угодно раз и принимает разделяемый запятыми список имен свойств.

Поведение и имена синтезируемых методов доступа будут соответствовать описанным ранее атрибутам в объявлении свойств. В частности, используя синтаксис имяСвойства=имяПеременнойЭкземпляра в директиве ©synthesize, можно объявить, что синтезируемые методы должны иметь доступ к переменной экземпляра, имя которой отличается от имени свойства. В противном случае имя переменной экземпляра будет таким же, как и у свойства. Как упоминалось ранее, объявлять переменную экземпляра совсем не обязательно, поскольку она будет объявлена автоматически в процессе синтеза методов доступа.

 

Переменная экземпляра, автоматически объявляемая в процессе синтеза ме-. тодов доступа, является строго закрытой. Это означает, что она не наследуется ^ f подклассами того класса, где объявляется. Данное обстоятельство редко вызывает осложнения, но если они все же возникают, то переменную экземпляра следует просто объявить явным образом.

 

Таким образом, объявив свойство theData, можно сделать явный запрос на синтез методов доступа в разделе реализации класса следующим образом:

^synthesize theData;

В итоге любые методы доступа (theData и setTheData:, если только не изменить их имена в объявлении свойства) будут подспудно синтезированы автоматически. Если переменная экземпляра theData не была объявлена, то это будет также сделано автоматически. Имя автоматически объявляемой переменной экземпляра может, вероятнее всего, понадобиться, поскольку не исключено, что к ней потребуется прямой доступ, особенно в инициализаторе (и в методе dealloc, если механизм ARC не применяется), а также в любых создаваемых самостоятельно методах доступа.

Начиная с версии Xcode 4.2 компания Apple стала придерживаться в шаблонах приложений соглашения о том, что переменная экземпляра получает имя, отличающееся от имени свойства предшествующим знаком подчеркивания. Например, в разделе реализации класса AppDelegate можно обнаружить следующую строку кода:

 

@synthesize window = _window;

 

Очевидная польза от соблюдения этого соглашения об именовании состоит в том, что в прикладном коде можно обращаться к свойству явным образом: self. window. Если случайно обратиться к переменной экземпляра непосредственно по имени window, то будет получена ошибка компилятора, поскольку переменная экземпляра под таким именем отсутствует, но есть переменная, называемая _window. Следовательно, данное соглашение об именовании предотвращает случайный прямой доступ к переменной экземпляра без передачи через методы доступа. Оно также позволяет ясно отличать код, в котором имена обозначают переменные экземпляра, поскольку они начинаются со знака подчеркивания. Кроме того, подобная стратегия освобождает от необходимости использовать имя свойства (в данном случае — window) для обозначения локальной переменной в методе, не получая при этом предупреждение от компилятора о затенении имени переменной экземпляра.

Этой же стратегии именования следует и автоматический синтез. Так, если опустить директиву ©synthesize, автоматически объявляемая переменная экземпляра получит (также автоматически) имя свойства с предшествующим знаком подчеркивания. Например, объявление свойства theData автоматически приводит к объявлению переменной экземпляра theData. Если же это не устроит вас по какой-нибудь причине, воспользуйтесь непосредственно директивой ©synthesize. (Напомним, что если не указать в этом случае имя переменной экземпляра явным образом, то ее выбираемое по умолчанию имя будет таким же, как и у свойства, т.е. без знака подчеркивания.)

В примере 12.11 наглядно иллюстрируется полная реализация класса Dog с открытым свойством name, как утверждалось ранее в этой главе. Это свойство подлежит автоматическому синтезу, а следовательно, автоматически объявляется и соответствующая переменная экземпляра name. На нее приходится ссылаться непосредственно в инициализаторе.

 

Пример 12.11. Полный пример автоматического синтеза свойства

// Dog.h:

@interface Dog : NSObject - (id) initWithName: (NSString*) s;

@property (nonatomic, copy) NSString* name;

@end

// Dog.m:

@implementation Dog

 

- (id) initWithName: (NSString*) s {

self - [super init]; if (self) <

self->_name - [s copy];

t

return self;

}

- (id) init {

NSAssert(NO, @"Making a nameless dog is forbidden."); return nil;

@end

Независимо от того, включаете ли вы директиву @synthesize в прикладной код явным образом или выгодно используете в нем автоматический синтез, в любом случае вы не лишаетесь возможности написать один или оба метода доступа самостоятельно. Синтез означает, что любые не предоставляемые вами методы доступа будут предоставлены автоматически. Если же вы воспользуетесь автоматическим синтезом (но не директивой ©synthesize) и предоставите оба метода доступа, то не получите никакой автоматически объявляемой переменной. Это вполне благоразумная стратегия: вы берете на себя полный контроль над методами доступа, а значит, получаете ручной контроль над переменной экземпляра.

В качестве полезного приема можно выгодно воспользоваться синтаксисом имяСвойства= =имяПеременнойЭкземпляра в директиве ©synthesize, чтобы переопределить синтезируемый метод доступа, не теряя его функциональные возможности. Допустим, требуется, чтобы метод установки не только выполнял установку значения переменной экземпляра _mylvar, но и другие функции. Для этого можно, в частности, написать собственный метод установки, но создавать его сызнова — занятие трудоемкое и чреватое ошибками, тогда как синтезированный метод установки выполняет свои функции исправно и не требует написания ни единой строки кода.

В качестве выхода из этого положения можно объявить свойство mylvar наряду с соответствующим закрытым свойством (см. пример 12.10), назвав последнее, скажем, mylvarAlias, а затем синтезировать свойство mylvarAlias для доступа к переменной экземпляра _mylvar. Далее нужно написать вручную методы доступа к свойству mylvar, которые должны как минимум воспользоваться свойством mylvarAlias соответственно для установки и получения значения переменной _mylvar. Однако самое главное, что эти методы можно наделить и другими функциями (см. пример 12.12), которые будет выполнять тот метод, который получает или устанавливает значение свойства mylvar.

 

Пример 12.12. Переопределение синтезированных методов доступа

// в заголовочном файле:

Sinterface MyClass : NSObject

0property (nonatomic, strong) NSNumber* mylvar;

I? end

II в файле реализации: fiinterface MyClass ()

@property (nonatomic, strong) NSNumber* mylvarAlias;

Send

(^implementation MyClass @synthesize myIvarAlias-_myIvar;

- (void) setMylvar: (NSNumber*) num (

II выполнить здесь другие операции self.mylvarAlias - num;

)

- (NSNumber*) mylvar (

II выполнить здесь другие операции return self.mylvarAlias;

}

@end


 

 

 

Добавить комментарий