- 可以用@property語法來定義物件中所封裝的資料
- 通過“特質”來指定儲存資料所需的正確語義
- 在設定屬性所對應的例項變數時,一定要遵從改屬性所宣告的語義。
- 開發iOS程式是應該使用nonatomic屬性,因為atomic屬性會嚴重影響效能。
成員變數
@interface EOCPersion: NSObject {
@public
NSString *_firstName;
NSString *_lastName;
@private
NSString *_someInternalData;
}
複製程式碼
定義例項變數的作用域。OC中很少這樣做。這寫法的問題:
物件佈局在編譯器就固定,碰到例項變數,把例項變數替換為“偏移量”。偏移量為該變數距離存放物件的記憶體區域的起始地址有多遠。
如果重新增加例項變數,會改變記憶體佈局,需要重新編譯。 OC解決此問題的方法是:把例項變數單做一種儲存偏移量所用的“特殊變數”,交由類物件保管。
屬性
屬性 = 成員變數 + set方法 + get方法
@interface EOCPerson: NSObject
@property NSString *firstName;
@end
複製程式碼
編譯器會為屬性自動新增成員變數和set方法與get方法。
如果不需要編譯器,新增@dynamic
@interface EOCPerson: NSObject
@dynamic firstName, lastName;
@end
複製程式碼
屬性特質
原子性
編譯器預設所合成的方法會通過鎖定機制確保其原子性(atomicity)。如果屬性具備nonatomic特質,則不使用同步鎖。
@property (nonatomic, copy) NSString *firstName;
複製程式碼
讀寫許可權
- readwrite(讀寫許可權),同時獲得setter和getter方法。預設
- readonly(只讀),只有get方法。
//.h檔案
@interface ViewController : UIViewController
@property (nonatomic, strong, readonly) NSString *firstString;
@end
//.m檔案
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_firstString = @"內部任意修改";
}
/// 函式返回值置為NO,即不允許直接訪問例項變數。禁止KVC來修改
+(BOOL)accessInstanceVariablesDirectly {
return NO;
}
@end
複製程式碼
記憶體管理語義
- assign: 純量型別(CGFloat、NSInterger等)的簡單賦值操作
atomic與nonatomic區別:具備atomic特質的獲取方法會通過鎖定機制來確保其操作的原子性。如果兩個執行緒讀寫同一屬性,不論何時總能看到有效的屬性值。如果不加鎖,一個執行緒更改屬性,一個讀,會出現執行緒讀到的屬性值不對。iOS開發中使用同步鎖開銷較大,帶來效能問題,所以一般不要求屬性必須是原子的。不是絕對安全,就算是atomic,也可能會讀到不同的屬性值。
- strong: 擁有關係。先保留新值,並釋放舊值,然後將新值設定上去
- weak:非擁有關係,既不保留新值,也不釋放舊值。同assign,屬性所指物件遭到摧毀是,屬性值會清空
- unsafe_unretained: 同assign,適用物件型別,非擁有關係。屬性所指物件遭到摧毀是,屬性值不會自動清空
- copy: 擁有關係。設定方法並不保留新值,而是將其拷貝。常用來保護NSString的封裝性,因為傳遞給設定方法的新值可能指向一個NSMutableString類的例項。
方法名
- getter=:指定獲取方法的方法名。
@property (nonatomic, getter=isOn) BOOL on;
- setter=:指定設定方法的方法名。