Главная » iPhone, Objective-C, Программирование для iOS и MacOS » Свойства Objective-C

0

В предыдущей главе мы создали класс Appliance, который содержал два свойства:

productName и vоltage. Давайте разберемся, как работают эти свойства.

В файле Appliance.h объявляются две переменные экземпляров для хранения данных:

{

NSString *productName; int voltage;

}

Также  для  них  были  объявлены  методы  доступа.  Объявления  могли  бы выглядеть так:

-­‐    (void)setProductName:(NSString   *)s;

-­‐   (NSString  *)productName;

-­‐       (void)setVoltage:(int)x;

-­‐    (int)voltage;

Но мы вместо этого воспользовались конструкцией @ргорегtу:

@property (copy) NSString *productName;

@property int voltage;

В файле Appliance.m методы доступа можно было реализовать явно:

-­‐    (void)setProductName:(NSString   *)s

{

productName = [s copy];

}

-­‐   (NSString  *)productName

{

return productName;

}

-­‐       (void)setVoltage:(int)x

{

voltage = x; }

-­‐    (int)voltage

{

return voltage;

}

Однако мы использовали для их реализации конструкцию @synthesize:

@synthesize productName, voltage;

Любопытный факт о компиляторе Objective-C: при компилировании приложения для iOS или 64-разрядной платформы Мас OS Х объявлять переменные экземпляров не нужно. Вызовов @рrореrtу/@sуnthеsizе достаточно для того, чтобы память для данных была зарезервирована.

Закомментируйте переменные экземпляров в файле Appliance.h: {

{

// NSString *productName;

// int voltage;

}

Заново постройте и запустите программу.

В этой книге мы всегда объявляем переменные экземпляров. Объявление может рассматриваться как дополнительная форма документированная и позволяет использовать код в 32-разрядных программах для Мас OS Х. Раскомментируйте переменные  экземпляров.

Атрибуты свойств

А теперь поближе познакомимся с различными атрибутами, управляющими созданием методов доступа для свойств.

Изменяемость

Свойство можно объявить доступным для чтения/записи (readwrite) или только для чтения (readonly). По умолчанию используется значение readwrite, при котором создается как set-, так и gеt-метод. Если вы не хотите, чтобы для свойства создавался sеt-метод, пометьте свойство атрибутом readonly:

@property (readonly) int voltage;

Срок жизни

Свойство также может быть объявлено с атрибутом unsаfе_unrеtаinеd, strong, weak или сору. Это значение определяет тем, как sеt-метод организует управление памятью,

Значение unsаfе_unrеtаinеd используется по умолчанию; это самый простой

вариант – свойству просто присваивается переданное значение. Для примера возьмем следующее объявление и определение:

@property (unsafe_unretained) int averageScore;

// "@property int averageScore" would also work here

@synthesize averageScore;

Сгенерированный sет-метод будет практически эквивалентен следующему:

-­‐        (void)setAverageScore:(int)d

{

averageScore = d;

}

В Appliance свойство voltage не изменяет счетчик ссылок. Атрибут unsafe_unretained всегда используется для свойств, содержащих не-объектные значения.

Атрибут strong, как упоминалось в главе 20, обеспечивает сохранение сильной

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

Атрибут weak не подразумевает владения объектом. Он синтезирует set-метод, который присваивает свойству переданный объект. В случае уничтожения объекта свойству задается значение nil. (Обратите внимание: если указатель имеет атрибут unsаfе_unrеtаinеd, то при уничтожении объекта, на который он ссылается, в программе появляется «висячий указатель». Отправка сообщения такому указателю обычно приводит к сбою программы.)

Атрибут сору создает сильную ссылку на копию переданного объекта. Но здесь имеется одна тонкость, которую многие разработчики понимают неправильно…

сору

Атрибут  сору  создает  копию  объекта  и  пере  водит  на  нее  указатель.  Допустим, объявление и определение свойства выглядят следующим образом:

@property (copy) NSString *lastName;

@synthesize lastName;

Сгенерированный sеt-метод выглядит примерно так:

-­‐   (void)setLastName:(NSString   *)d

{

lastName = [d copy];

}

Атрибут  сору  чаще  всего  используется  с  объектными  типами,  имеющими изменяемые    субклассы.    Например,    NSString  имеет    субкласс    с    именем

NSMutаblеString.    Как    нетрудно    представить,    методу    setLastName:    может передаваться изменяемая строка:

// создание изменяемой строки

NSMutableString *x = [[NSMutableString alloc] initWithString:@"Ono"];

// передача ее setLastName: [myObj setLastName:x];

// ‘copy’ запрещает this изменять lastName [x appendString:@" Lennon"];

А если передаваемый объект не является изменяемым? Создавать копию неизменяемого объекта было бы неэффективно. Метод сору просто вызывает copyWithZone: и передает аргумент nil. Например, в NSString метод соруWithZone: переопределятся следующим образом:

-­‐    (id)copyWithZone:(NSZone  *)z

{

return self;

}

Таким образом, копия вообще не создается. (Учтите, что NSZone и зонирование памяти вообще – устаревшие, рудиментарные возможности программирования Сосоа, поэтому здесь они подробно не рассматриваются. Впрочем, метод copyWithZone: еще находит практическое применение и не считается полностью вытесненным.)

Для объектов, существующих в изменяемой и неизменяемой версиях, метод

сору возвращает неизменяемую копию. Например, NSМutаblеStгing содержит метод сору, который возвращает экземпляр NSString. Если вы хотите, чтобы копия была изменяемым объектом, используйте метод mutаblеСору.

Атрибута срока жизни свойств с именем mutаblеСору не существует. Если бы хотите, чтобы sеt-метод назначал свойству изменяемую копию объекта, вы должны реализовать его самостоятельно, с вызовом метода mutаblеСору для входного объекта. Например, в классе OwnedAppliance можно создать метод setOwnerNames: :

-­‐     (void)setOwnerNames:(NSSet   *)newNames

{

ownerNames = [newNames mutableCopy];

}

Источник: Аарон Хилегас, «Objective-C. Программирование для iOS и MacOS», 2012 г.

По теме:

  • Комментарии