06@理解“屬性”這一概念

Zack_Go發表於2019-01-05
  • 可以用@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=:指定設定方法的方法名。

相關文章