A property is just a declaration that allows you to use configuration devices, getters and dot-syntax (interface conjugation).
It does absolutely nothing on its own, but allows you to use -[myInstance myProperty]
to get the variable or use -[myInstance setMyProperty:]
to set it (yes, the method name is automatically assigned to -setProperty:
and -property
).
When declaring a property, you have three categories: thread blocking, access control, and memory management. You can select only one of the modifiers for each category, and if you have not selected one, it is automatically assigned to one automatically.
@property (<thread locking>, <access control>, <memory management>) id property;
The first category may be atomic
or nonatomic
. The atomic
modifier causes @synchronized (myInstance) to lock the variable to ensure thread safety. nonatomic
does not use a synchronized block and is not thread safe. If you do not use it, it is automatically installed on atomic
.
The second category can be either readonly
or readwrite
. The readwrite
modifier also allows you to modify the property and allows you to automatically generate the -setProperty: method. When the readonly
modifier is used, you cannot use the -setProperty:
method. You must use the internal variable from the object to set the variable directly.
The third category may be assign
, retain
and copy
. The assign
modifier means that the objectโs internal pointer is set to the pointer passed to the -setProperty:
message. The retain
modifier assigns the passed pointer and passes the -retain
object to the object.
The copy
modifier makes a straightforward clone of an object - a new pointer to a new object at a new address in memory. This sets the internal pointer of the object to a copy of the passed object, calling -copy
on the passed object. The default modifier is assign
, and the compiler will warn you if you do not install the memory management category modifier for the object - because the assign
modifier on the object is not approved (unless explicitly declared).
In the -copy example, look at this:
- (void)setProperty:(GXMyObject *)property {
There is an optional method name declaration modifier and is used as follows: getter = myCustomPropertyGetter
and setter = myCustomPropertySetter:
(colon :
at the end of the setter method name is required because it means that an argument must be passed).
The second half is a property synthesizer or dynamics. Once a property is declared (e.g. myView
) as follows:
@property (nonatomic, retain) NSView *myView;
You either: define the setter and getter yourself; @synthesize
setter and getter; @dynamic
property is to say that it exists in a category or in the main class or can be added at runtime (this is not a fun idea, mind you, and may lead to incorrect runtime exceptions).
In the first example, writing the methods themselves, will look like this:
// In Apple 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
The second example is to auto-synthesize it using the @synthesize
directive:
@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
The last example is perhaps the most confusing because it requires using the @dynamic directive, you need something like adding a class or runtime:
@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
An @property
ad requires one of the three ads above to be present - it does nothing by itself. What it resolves, however, is point syntax assemblers (Java-like accessors for setting and getting properties).
For example, @property (copy) NSString *myName;
can be obtained using -[myObject myName]
and set using -[myObject setMyName:]
.
Now it can be set using myObjectInstance.myName = @"Bob";
and get using myObjectInstance.myName
. Using all of the above concepts, you can create an object such as this:
// 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
Note. This code has not been tested. Now that you have the GXBufferQueue, all of the following works:
GXBufferQueue *queue = [GXBufferQueue queue];
As you can see, there are many possibilities with properties and much more that can be done with them than just declaring a variable. If you have any questions or anything, the community will want me to add / fix in / in the message, please leave a comment !: D