Objective-C Language
свойства
Поиск…
Синтаксис
- Идентификатор типа @property ( optional_attributes, ... );
- @synthesize identifier = optional_backing_ivar ;
- @dynamic identifier ;
параметры
атрибут | Описание |
---|---|
atomic | Неявные. Включает синхронизацию в синтезированных методах доступа. |
nonatomic | Отключает синхронизацию в синтезированных методах доступа. |
readwrite | Неявные. Синтезирует геттер, сеттер и поддержку ivar. |
readonly | Синтезирует только метод геттера и поддержку ivar, которые могут быть назначены напрямую. |
getter= name | Указывает имя метода getter, неявное имя propertyName . |
setter= name | Задает имя метода setter, implicity is setPropertyName: Колон : должен быть частью имени. |
strong | Неявно для объектов в ARC . Поддерживающий ivar синтезируется с использованием __strong , что предотвращает освобождение ссылочного объекта. |
retain | Синоним strong . |
copy | То же, что и strong , но синтезированный сеттер также вызывает -copy для нового значения. |
unsafe_unretained | Неявно, за исключением объектов в ARC. Подкрепляющий ivar синтезируется с использованием __unsafe_unretained , который (для obejcts) приводит к зависанию указателя, когда ссылочный объект освобождается. |
assign | Синоним для unsafe_unretained . Подходит для не-объектов. |
weak | Обратный ivar синтезируется с использованием __weak , поэтому значение будет __weak после того, как ссылочный объект будет освобожден. |
class | Атрибуты доступа к ресурсам синтезируются как методы класса, а не методы экземпляра. Синтезировано хранилище резервных копий. |
nullable | Свойство принимает значения nil . В основном используется для моста Swift. |
nonnull | Свойство не принимает значения nil . В основном используется для моста Swift. |
null_resettable | Свойство принимает значения nil в setter, но никогда не возвращает значения nil из getter. Ваша пользовательская реализация getter или setter должна обеспечить такое поведение. В основном используется для моста Swift. |
null_unspecified | Неявные. Свойство не указывает обработку значений nil . В основном используется для моста Swift. |
Что такое свойства?
Вот примерный класс, который имеет пару переменных экземпляра без использования свойств:
@interface TestClass : NSObject {
NSString *_someString;
int _someInt;
}
-(NSString *)someString;
-(void)setSomeString:(NSString *)newString;
-(int)someInt;
-(void)setSomeInt:(NSString *)newInt;
@end
@implementation TestClass
-(NSString *)someString {
return _someString;
}
-(void)setSomeString:(NSString *)newString {
_someString = newString;
}
-(int)someInt {
return _someInt;
}
-(void)setSomeInt:(int)newInt {
_someInt = newInt;
}
@end
Это довольно много кода шаблона для создания простой переменной экземпляра. Вам нужно создать переменную экземпляра и создать методы доступа, которые ничего не делают, кроме набора или возврата переменной экземпляра. Итак, с Objective-C 2.0, Apple представила свойства, которые автоматически генерируют какой-либо или весь шаблонный код.
Ниже приведен класс, переписанный со свойствами:
@interface TestClass
@property NSString *someString;
@property int someInt;
@end
@implementation testClass
@end
Свойство - это переменная экземпляра, объединенная с автогенераторами и сеттерами. Для свойства, называемого someString
, getter и setter называются someString
и setSomeString:
соответственно. Имя переменной экземпляра, по умолчанию, имя свойства с префиксом подчеркивания (так что переменная экземпляра для someString
называется _someString
, но это может быть изменено с @synthesize
директивы в @implementation
разделе:
@synthesize someString=foo; //names the instance variable "foo"
@synthesize someString; //names it "someString"
@synthesize someString=_someString; //names it "_someString"; the default if
//there is no @synthesize directive
Доступ к свойствам можно получить, вызвав геттеры и сеттеры:
[testObject setSomeString:@"Foo"];
NSLog(@"someInt is %d", [testObject someInt]);
Их также можно получить с помощью точечной нотации:
testObject.someString = @"Foo";
NSLog(@"someInt is %d", testObject.someInt);
Пользовательские геттеры и сеттеры
По умолчанию свойства getters и seters могут быть переопределены:
@interface TestClass
@property NSString *someString;
@end
@implementation TestClass
// override the setter to print a message
- (void)setSomeString:(NSString *)newString {
NSLog(@"Setting someString to %@", newString);
// Make sure to access the ivar (default is the property name with a _
// at the beginning) because calling self.someString would call the same
// method again leading to an infinite recursion
_someString = newString;
}
- (void)doSomething {
// The next line will call the setSomeString: method
self.someString = @"Test";
}
@end
Это может быть полезно для обеспечения, например, ленивой инициализации (путем переопределения геттера для установки начального значения, если оно еще не установлено):
- (NSString *)someString {
if (_someString == nil) {
_someString = [self getInitialValueForSomeString];
}
return _someString;
}
Вы также можете создать свойство, которое вычисляет его значение в getter:
@interface Circle : NSObject
@property CGPoint origin;
@property CGFloat radius;
@property (readonly) CGFloat area;
@end
@implementation Circle
- (CGFloat)area {
return M_PI * pow(self.radius, 2);
}
@end
Свойства, вызывающие обновления
Этот объект, Shape
имеет свойство image
, которое зависит от numberOfSides
и sideWidth
. Если установлена одна из них, то image
должно быть пересчитано. Но перерасчет предположительно длинный, и его нужно выполнить только один раз, если оба свойства установлены, поэтому Shape
предоставляет способ установить оба свойства и только пересчитать один раз. Это делается путем установки свойств ivars напрямую.
В Shape.h
@interface Shape {
NSUInteger numberOfSides;
CGFloat sideWidth;
UIImage * image;
}
// Initializer that takes initial values for the properties.
- (instancetype)initWithNumberOfSides:(NSUInteger)numberOfSides withWidth:(CGFloat)width;
// Method that allows to set both properties in once call.
// This is useful if setting these properties has expensive side-effects.
// Using a method to set both values at once allows you to have the side-
// effect executed only once.
- (void)setNumberOfSides:(NSUInteger)numberOfSides andWidth:(CGFloat)width;
// Properties using default attributes.
@property NSUInteger numberOfSides;
@property CGFloat sideWidth;
// Property using explicit attributes.
@property(strong, readonly) UIImage * image;
@end
В Shape.m
@implementation AnObject
// The variable name of a property that is auto-generated by the compiler
// defaults to being the property name prefixed with an underscore, for
// example "_propertyName". You can change this default variable name using
// the following statement:
// @synthesize propertyName = customVariableName;
- (id)initWithNumberOfSides:(NSUInteger)numberOfSides withWidth:(CGFloat)width {
if ((self = [self init])) {
[self setNumberOfSides:numberOfSides andWidth:width];
}
return self;
}
- (void)setNumberOfSides:(NSUInteger)numberOfSides {
_numberOfSides = numberOfSides;
[self updateImage];
}
- (void)setSideWidth:(CGFloat)sideWidth {
_sideWidth = sideWidth;
[self updateImage];
}
- (void)setNumberOfSides:(NSUInteger)numberOfSides andWidth:(CGFloat)sideWidth {
_numberOfSides = numberOfSides;
_sideWidth = sideWidth;
[self updateImage];
}
// Method that does some post-processing once either of the properties has
// been updated.
- (void)updateImage {
...
}
@end
Когда свойства назначаются ( с использованием object.property = value
), метод сеттер setProperty:
называется. Этот сеттер, даже если он предоставлен @synthesize
, может быть переопределен, как в этом случае для numberOfSides
и sideWidth
. Однако, если вы установите свойство ivar напрямую (через property
если объект является self или object->property
), он не вызывает getter или setter, позволяя вам делать такие вещи, как несколько наборов свойств, которые вызывают только одно обновление или побочные побочные эффекты, вызванные установщиком.