Accessing object state in Objective-C through dot notation offers a streamlined syntax that the compiler translates into standard mesage sends. When encountering an assignment like staff.identifier = 4021, the compiler converts this too [staff setIdentifier:4021]. For value retrieval such as int currentId = staff.identifier, the expression becomes int currentId = [staff identifier]. This notation requires that the class implements or synthesizes the appropriate accessor methods.
The @property declaration serves as a compiler instruction to generate these accessor method prototypes automatically. In contemporary development, this directive performs more than mere declaration—it triggers automatic synthesis of both the accessor implementations and the underlying instance variable.
Historical context illustrates this evolution: Before Xcode 4.4, developers manually declared properties in the interface, then synthesized them in the implementation file to generate the backing variable. Modern compilers handle this implicitly:
@interface Task : NSObject
@property int priority;
@property (copy) NSString *taskName;
@end
@implementation Task
// Compiler automatically creates _priority and _taskName instance variables
// along with complete getter and setter implementations
@end
When no explicit instance variable exists, the compiler synthesizes a private variable prefixed with an underscore. This generated storage remains internal to the implementation unit and cannot be accessed by subclasses or external code, maintaining strict encapsulation.
Property behavior is customized through attributes grouped into three functional categories:
Concurrency Control
atomic: Implements locking to guarantee thread-safe access. This default setting ensures data integrity across threads but introduces synchronization overhead.nonatomic: Eliminates locking mechanisms for improved access speed. Preferred for most application-layer code where the calling context manages concurrency.
Access Control
readwrite: Generates both getter and setter methods, allowing external modification. This is the default configuration.readonly: Generates only the getter method, creating immutable properties from external interfaces while allowing internal modification.
Memory Semantics (Manual Reference Counting)
assign: Performs direct value assignment without ownership implications. Appropriate for scalar types and weak references.retain: Releases the existing object reference and retains the new assignment, establishing ownership in manual memory management environments.copy: Releases the current value and stores a duplicate of the new assignment. Critical for mutable subclasses and value semantics.
@interface Project : NSObject
@property (nonatomic, assign) int projectCode;
@property (nonatomic, retain) Task *currentTask;
@property (nonatomic, copy) NSString *projectTitle;
@end
@implementation Project
// Custom implementation overrides auto-synthesis when specific logic is required
- (void)setCurrentTask:(Task *)newTask {
if (_currentTask != newTask) {
[_currentTask release];
_currentTask = [newTask retain];
}
}
@end
Accessor methods can be renamed to conform to specific API conventions or Boolean naming patterns:
@property (nonatomic, getter=isComplete, setter=markAsComplete:) BOOL completed;
This declaration produces isComplete for value retrieval and markAsComplete: for modification, deviating from the standard completed and setCompleted: naming.