手寫存取器的痛苦
// 傳統手寫
- (int)myNumber { return myNumber; }
- (void)setMyNumber:(int)num { myNumber = num; }
// 屬性多時極其繁瑣、易出錯
現代語法:@property + @synthesize
聲明
@interface Person : NSObject {
int myNumber; // 可選:實例變量,現代編譯器自動合成
}
@property (nonatomic) int myNumber; // 生成 setter/getter 聲明
- (void)print;
@end
實現
#import "Person.h"
@implementation Person
@synthesize myNumber; // 自動生成實現
- (void)print {
NSLog(@"myNumber = %d", myNumber);
}
@end
@property 屬性修飾符完整表
| 分類 | 關鍵字 | 含義 | 默認值 |
| 讀寫權限 | readwrite | 生成 setter + getter | ✓ |
readonly | 僅生成 getter | |
| 內存語義 | assign | 直接賦值,不改變引用計數 | ✓ (基本類型) |
retain | retain 新值,release 舊值 (MRC) | |
copy | copy 新值,release 舊值 | |
strong | 強引用 (ARC 默認) | ✓ (對象類型 ARC) |
weak | 弱引用,對象釋放自動置 nil (ARC) | |
| 原子性 | atomic | 線程安全 getter/setter(加鎖) | ✓ |
nonatomic | 非原子,高性能,非線程安全 | 推薦 |
關鍵區別解析
assign vs retain vs copy (MRC 時代)
assign:基本類型、delegate 弱引用
retain:對象類型,聲明所有權
copy:NSString、NSArray 等可變對象,防止外部修改
strong vs weak (ARC 時代)
strong:擁有關系,引用計數 +1
weak:非擁有,打破循環引用,對象銷毀自動置 nil
atomic vs nonatomic
atomic:getter/setter 內部加鎖,保證線程安全讀寫單個屬性,不保證複合操作原子性
nonatomic:無鎖,速度快 10-20 倍,iOS 開發默認選擇
只讀屬性模式
@property (nonatomic, readonly) NSString *name;
// 僅生成 - (NSString *)name;
// 內部可通過 _name 直接賦值,或在 class extension 中重聲明 readwrite
現代編譯器自動合成(Xcode 4.4+ / LLVM 4.0+)
- 無需手寫
@synthesize
- 實例變量自動命名為
_propertyName
- 可在
@implementation 中用 @synthesize prop = _customName 自定義
完整示例:現代寫法
// Person.h
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
@property (nonatomic, readonly) NSString *description; // 只讀
@end
// Person.m
@implementation Person
// 無需 @synthesize,自動生成 _name, _age, _description
- (NSString *)description {
return [NSString stringWithFormat:@"Person: %@, %d", _name, _age];
}
@end
總結建議
- 默認用
nonatomic,除非確定需要線程安全單屬性訪問
- 對象類型用
strong (ARC) / retain (MRC);不可變類型(NSString 等)用 copy
- 委托、塊回調用
weak 打破循環引用
- 只讀屬性暴露內部狀態但禁止外部修改
- 信任編譯器自動合成,減少樣板代碼