Свойство - это просто объявление, которое позволяет использовать методы установки, получения и средства доступа с точечным синтаксисом (скрытие переменных интерфейса).
Сам по себе он абсолютно ничего не делает, но позволяет вам использовать -[myInstance myProperty]
для получения переменной или использовать -[myInstance setMyProperty:]
для ее установки (да, имя метода автоматически присваивается -setProperty:
и -property
).
При объявлении свойства у вас есть три категории - блокировка потоков, контроль доступа и управление памятью. Вы можете выбрать только один из модификаторов для каждой категории, и если вы не выберете один, он автоматически присваивается одному из них.
@property (<thread locking>, <access control>, <memory management>) id property;
Первая категория может быть atomic
или nonatomic
. Модификатор atomic
устанавливает блокировку @synchronized (myInstance) для переменной, чтобы обеспечить безопасность потоков. nonatomic
не использует синхронизированный блок и НЕ является потокобезопасным. Если вы их не используете, автоматически устанавливается значение atomic
.
Вторая категория может быть readonly
или readwrite
. Модификатор readwrite
также позволяет изменять свойство и позволяет автоматически создавать метод -setProperty :. Когда используется модификатор readonly
, нельзя использовать метод -setProperty:
. Вы должны использовать внутреннюю переменную внутри объекта, чтобы установить переменную напрямую.
Третья категория может быть assign
, retain
и copy
. Модификатор assign
означает, что внутренний указатель объекта установлен на указатель, переданный в сообщение -setProperty:
. Модификатор retain
назначает переданный указатель и передает объекту -retain
.
Модификатор copy
выполняет прямую копию объекта - новый указатель на новый объект по новому адресу в памяти. Это устанавливает внутренний указатель объекта на копию переданного объекта, вызывая -copy
для переданного объекта. Модификатор по умолчанию - assign
, и компилятор предупредит вас, если вы не установите модификатор категории управления памятью для объекта, потому что модификатор assign
для объекта не одобряется (если явно не объявлен).
Для примера на -copy, посмотрите на это:
- (void)setProperty:(GXMyObject *)property {
// This points to the original passed object.
GXMyObject *original = property;
// This points to a copy of the passed object.
CGMyObject *copied = [property copy];
// This points to yet another copy of the passed object-
// Independent of the other copies and original.
_property = [property copy];
// The anotherProperty is now different on this copy
// than on the original and the other copies.
_property.anotherProperty = 4;
// This will prove that they are all individual objects.
NSLog(@"%p, %p, %p", original, copied, _property);
}
Существует необязательный модификатор объявления имени метода, который используется следующим образом: getter = myCustomPropertyGetter
и setter = myCustomPropertySetter:
(двоеточие :
в конце имени метода установки является обязательным, потому что оно означает, что аргумент должен быть передан).
Вторая половина - это синтезатор или динамизатор свойств. После объявления свойства (например, myView
) следующим образом:
@property (nonatomic, retain) NSView *myView;
Вы бы либо: сами определили установщик и получатель; @synthesize
установщик и получатель; @dynamic
свойство, указывающее, что оно существует в категории или основном классе или может быть добавлено во время выполнения (заметьте, это не забавная идея и может вызвать недопустимые исключения во время выполнения).
Первый пример, написание методов самостоятельно, будет выглядеть так:
// In Apple's LLVM 3.1 Compiler, instance variables can be added
// within {} below the @implementation as well as the @interface,
// and in private categories (@interface GXMyClass ()) like before.
@implementation GXMyClass {
// The internal object pointer is prefixed with an _ to avoid name confusions.
NSView *_myView;
}
- (NSView *)myView {
return _myView;
}
- (void)setMyView:(NSView *)myView {
_myView = [myView retain];
}
@end
Второй пример - автосинтезировать его с помощью директивы @synthesize
:
@implementation GXMyClass
// In the new Apple LLVM 3.1 Clang compiler, the = operator when used
// next to the @synthesize directive declares an internal private
// variable and automatically sets to that variable.
@synthesize myView = _myView;
// The internal variable name is now myOtherView, because we did not use the
// = operator to assign an internal variable name to the property.
@synthesize myOtherView;
@end
В последнем примере, возможно, наиболее запутанном, поскольку он требует использования директивы @dynamic, вам потребуется что-то вроде добавления категории или метода времени выполнения:
@interface GXMyClass (InternalMethods)
@end
@implementation GXMyClass
// The = assignment operator does not work here.
@dynamic myView;
@end
@implementation GXMyClass (InternalMethods)
- (NSView *)myView {
return [self methodThatReturnsAnNSView];
}
- (void)setMyView:(NSView *)myView {
[self methodThatAcceptsAnNSViewArgument:myView];
}
@end
Объявление @property
требует наличия одного из трех вышеупомянутых объявлений - оно ничего не делает само по себе. Однако он позволяет использовать средства доступа с точечным синтаксисом (средства доступа, подобные Java, для установки и получения свойств).
Например, к @property (copy) NSString *myName;
можно получить доступ с помощью -[myObject myName]
и установить с помощью -[myObject setMyName:]
.
Теперь его можно установить с помощью myObjectInstance.myName = @"Bob";
и получить с помощью myObjectInstance.myName
. Используя все вышеперечисленные концепции, можно создать такой объект, как этот:
// The GXBufferQueue is a queue which buffers all requests, till they are read
// asynchronously later. The backing store is an NSMutableArray to which all
// buffer writes are appended to, and from which the first object is pulled and
// returned when the buffer is read to.
@interface GXBufferQueue
@property (nonatomic, readwrite, copy, setter = write:, getter = read) id buffer;
+ (GXBufferQueue *)queue;
@end
@implementation GXBufferQueue {
// This queue is an internal array and is 'tacked on' to the @implementation
// so no others can see it, and it can be marked @private so subclasses cannot
// use it. It is also good code practice to have @interfaces composed of only
// @properties, setters, and getters, rather than expose internal variables.
NSMutableArray *_internalQueue;
}
+ (GXBufferQueue *)queue {
return [[[GXBufferQueue alloc] init] autorelease];
}
- (id)init {
if((self = [super init])) {
_internalQueue = [[NSMutableArray alloc] init];
}
}
- (void)write:(id)buffer {
[_internalQueue addObject:buffer];
}
- (id)read {
if(!(_internalQueue.count > 0)) return nil;
id buffer = [_internalQueue objectAtIndex:0];
[_internalQueue removeObjectAtIndex:0];
return buffer;
}
@end
Примечание: этот код никоим образом не тестировался. Теперь, когда у вас есть GXBufferQueue, все следующее работает:
GXBufferQueue *queue = [GXBufferQueue queue];
// Option One: using the traditional message syntax:
[queue write:@"This will be now added to the buffer."];
NSLog(@"Now the string written to the queue will be read \
and removed from the queue, like a stack pop. ", [queue read]);
// Option Two: using the new dot-syntax accessors:
queue.buffer = @"As clunky as this looks, it works the same as above.";
NSLog(@"These lines work just the same as the ones above: ", queue.buffer);
Как видите, со свойствами можно многое сделать, и с ними можно сделать гораздо больше, чем просто объявление переменных. Если есть какие-либо вопросы или что-то, что сообщество хочет, чтобы я добавил / исправил / в публикации, пожалуйста, оставьте комментарий! : D
person
Aditya Vaidyam
schedule
09.05.2012
&_b
- это адрес переменной _b, а не адрес объекта; таким образом,&_b
и&_a
будут разными независимо друг от друга и, довольно легко, могут отличаться при последующих запусках одного и того же метода в зависимости от стека вызовов. - person bbum   schedule 10.05.2012&
. Вы не регистрируете то, что думаете о себе. - person Ken Thomases   schedule 10.05.2012NSLog(@"%p", object);
, который будет печатать местоположение указателя вместо метода описания объекта. - person Aditya Vaidyam   schedule 10.05.2012