Objective-C—— @Property詳解

實例變量:
屬性其實說直白點就是 ivar + setter + getter(實例變量+存取方法),不過在OC中屬性多了字面量這一系列特殊關鍵字使得OC屬性有些不一樣。數據庫

成員屬性咱們應該都使用過,好比如今定義一個Car類有name和speed成員變量:atom

#import <Foundation/Foundation.h>

@interface Car : NSObject
{
    @public
    NSString *name;
    NSInteger speed;
}
@end

在OC類的內部有一個偏移量,專門標記成員變量在內存中的所在位置。若是如今在添加一個新的成員變量在name的前面,那麼就會出現偏移量總體便宜的問題,如今添加一個price實例:spa

#import <Foundation/Foundation.h>

@interface Car : NSObject
{
    @public
    NSInteger price;
    NSString *name;
    NSInteger speed;
}
@end

此時偏移量在內存中顯示以下:代理

Car Car
name price
speed name
  speed

 

 

 

 

能夠看到實例偏移量發生了改變,可是OC將實例變量做爲一種存儲偏移量所用的「特殊變量」,交個類對象(class object)保管,偏移量會在運行時查找,因此總能正確的找到偏移量。調試

 

@Propertycode

使用屬性相比成員變量更加抽象,可以使用setter和getter對變量作更多的處理。對象

說一下屬性的特性blog

 

@synthesize關鍵字內存

該關鍵字指定了屬性的實例變量名稱,而且根據存儲語義(readwrite、readonly)系統自動合成setter和getter方法,固然也能夠手寫來覆蓋系統提供的。get

@dynamic

該關鍵字告訴編譯器不要爲我合成setter和getter方法,這些方法將由我本身實現。固然咱們能夠不實現這在編譯階段不會出現問題,直到運行時纔會檢查是否實現了setter和getter,若是沒有實現就會拋出異常。

例如在CoreData中NSManagedObject子類的全部屬性所有都是dynamic標記的,這是由於子類的某些屬性不是真正的實例變量,而是對應背後的數據庫,對NSManagedObject對象經過是屬性訪問時會自動使用KVC。

 

屬性特性(語義)

屬性的特質分爲四類:

1.原子性:

  原子性就是指該屬性是否爲同步的,OC中大部分屬性都是nonatomic(非原子性)的,若是不寫nonatomic那麼就會是原子性的。理論上來講原子性屬性的讀寫都將會是同步的,可是OC中atomic並不能必定肯定屬性爲同步的,若是真要進行同步操做,還要用更加深層次的同步鎖API。並且atomic會很影響效率,因此通常都會寫nonatomic。

2.讀/寫權限:

  讀寫爲readonly和readwrite兩種,前一種在系統只會合成getter方法,然後一種則會同時生成setter和getter。若是屬性設置爲了readonly屬性,那麼該屬性是不能夠修改的。

3.內存管理語義:

  assign:該方法只會針對「純量類型」(CGFloat或NSInteger等)的簡單賦值操做,id類型也要用assign,因此通常iOS中的代理delegate屬性都會用assign來標示,如:

@property (nonatomic, assign)   id <UITableViewDataSource> dataSource;
@property (nonatomic, assign)   id <UITableViewDelegate>   delegate;

  strong: 使用該特性實例變量在賦值時,會釋放舊值同時設置新值,對對象產生一個強引用,用MRC來講就是引用計數+1。

  weak: 屬性代表了一種」非擁有關係「,既不釋放舊值,也不保留新值。用MRC就是引用計數不變,當指向的對象被釋放時,該屬性自動被設置爲nil。這裏多說一點,weak的runtime實現是經過hash表完成的,用變量名作鍵,一旦發現屬性所指的對象被釋放了,馬上設置爲nil。

  unsafe_unretained:和weak同樣,惟一的區別就是當對象被釋放後,該屬性不會被設置爲nil。因此是unsafe的。

  copy:和strong相似,不過該屬性會被複制一個新的副本。不少時使用copy是爲了方式Mutable(可變類型)在咱們不知道的狀況下修改了屬性值,而用copy能夠生成一個不可變的副本防止被修改。若是咱們本身實現setter方法的話,須要手動copy。

4.方法名:

  getter = <name>

  setter = <name>

  方法名能夠修改成咱們合成的方法名,可使存取方法語義更加符合應用場景。

  若是要在其它屬性裏面設置屬性的話,仍是要符合屬性特性,好比copy的話咱們仍是要手動copy一下屬性。這裏說一下構造方法裏須要直接操做實例變量,而不該該調用setter和getter。

 

對象內部儘可能直接訪問實例變量

首先說一下構造方法和析構方法中爲何不能使用setter和getter,由於setter和getter是通過咱們包裝過的方法,有可能增長一些判斷,而若是子類調用父類的構造方法同時實現了本身的setter和getter,那麼極可能就會出現問題。

經過屬性訪問實例變量會使用屬性的字面語義,會使用KVO因此在執行效率上確定比直接調用實例變量慢,可是經過屬性訪問能夠截獲屬性的獲取和設置更加方便調試和控制。

通常在類內部推薦設置用setter 獲取直接用實例變量。

這裏再說一下惰性加載,所謂惰性加載就是指,屬性會在第一次調用getter的時候初始化,以下:

-(NSString *)name
{
    if (!_name){
        _name = [[NSString alloc] init];
    }
    return _name;
}

那麼此時就只可以經過getter來調用實例變量了。

相關文章
相關標籤/搜索