@property 和 @synthesize 是 Objective-C 封裝實例變量、自動生成存取方法的核心機制。Xcode 4.5+ (LLVM 4.0+) 引入**自動合成**,大幅簡化代碼。
// Person.h
@interface Person : NSObject {
int _age; // 實例變量 (默認 @protected)
int _no; // 編譯器自動生成同名 ivar
}
@property int age;
@property int no; // 未顯式聲明 ivar,編譯器生成私有 _no
- (id)initWithAge:(int)age andNo:(int)no;
@end
// Person.m
@implementation Person
@synthesize age = _age; // 手動綁定 property 到 ivar
@synthesize no = _no; // 省略則綁定同名 ivar (age->age, no->_no)
- (id)initWithAge:(int)age andNo:(int)no {
if (self = [super init]) {
_age = age; // 直接訪問 ivar
_no = no;
}
return self;
}
- (NSString*)description {
return [NSString stringWithFormat:@"age=%d, no=%d", _age, _no];
}
@end
編譯器**自動**執行:
_propertyName (下劃線前綴)。@synthesize propertyName = _propertyName;。// Person.h (極簡)
@interface Person : NSObject
@property int age;
@property int no;
@end
// Person.m (極簡)
@implementation Person
// @synthesize 可省略!編譯器自動完成
@end
// main.m
int main() {
@autoreleasepool {
Person *p = [Person new]; // new = alloc + init
p.age = 20; // 調用 setter
p.no = 3;
NSLog(@"%@", p); // 調用 description
}
return 0;
}
| 場景 | 行為 | 注意 |
|---|---|---|
| 顯式聲明 ivar | 使用該 ivar 存儲 | ivar 名建議加 _ 前綴區分 |
| 未聲明 ivar | 自動生成 _propertyName | 私有 (非 @protected),子類不可直接訪問 |
| 自定義 getter/setter | 編譯器**不再**自動合成該屬性 | 需自行實現存取邏輯及 ivar 管理 |
| readonly 屬性 | 只生成 getter | @property (readonly) int age; |
| @dynamic | 告訴編譯器:運行時動態提供存取方法 | Core Data / 代理轉發常用 |
@property (nonatomic, strong) NSString *name; // ARC 環境默認 strong @property (nonatomic, copy) NSString *title; // 字符串/集合常用 copy 防止外部修改 @property (nonatomic, assign) int age; // 基本類型、非對象指針 @property (nonatomic, weak) id delegate; // 避免循環引用 @property (nonatomic, getter=isEnabled) BOOL enabled; // 自定義 getter 名
@synthesize 代碼**可繼續使用**,與自動合成兼容。@synthesize**,享受零樣板碼優勢。自動合成是 Objective-C 現代化的重要一步,讓開發者專注於業務邏輯而非樣板代碼。