第六七八條:屬性相關

在Java或C++中,對象佈局在編譯器(compile time)已經固定了,對象的關於成員變量的代碼被編譯器替換爲“偏移量(offset)”,這個偏移量是“硬編碼(hardcode)”,表示這個變量距離存放對象的內存區域的起始地址有多遠。這種情況下,如果修改類定義之後就必須重新編譯,否則就會出錯。

OC在這方面的優化是,把實例變量當做是一種存儲偏移量所用的“特殊變量(special variable)”,交由類對象(class object)保管。偏移量會在運行期查找,如果類的定義變了,那麼存儲的偏移量也就變了,這樣的情況下,無論何時訪問實例變量總能夠使用到正確的偏移量。還可以在運行期向類中添加新的實例變量。

使用@property語法定義屬性 編譯器會自動寫出一套存取方法,用以訪問給定類型中具有給定名稱的變量。在此之外,編譯器還會向類中添加適當類型的實例變量,並且在屬性前添加下劃線,以此作爲實例變量的名字。

編譯器會把“.”點語法轉化爲對存取方法的調用。

屬性的修飾關鍵字:

1.原子性: nonatomic/atomic 

由編譯器所合成的方法會通過鎖定機制確保其原子性atomic,如果自己定義存取方法,注意些和屬性的原子性相符的代碼。

但是我們一般把屬性都聲明爲nonnatomic,因爲在iOS開發中,使用同步鎖的開銷比較大,會帶來性能的問題,如果要實現“線程安全”的操作,還需要採取更爲深層的鎖定機制纔行。

2.讀寫權限:readwrite(讀寫)/readonly(只讀)

readwrite的屬性擁有getter、setter方法;readonly的屬性只有getter方法;

3.內存管理:assign / strong / weak / unsafe_unretained / copy

assign:只會對基本純量類型CGFloat,NSInteger等進行簡單的賦值;

strong:定義了一種擁有關係,設置新值時,會保留新值,釋放舊值,然後將新值設置上去;

weak:定義了一種非擁有關係,設置新值時,不保留新值,也不保留舊值,在屬性所指的對象釋放時,屬性值會清空;

unsafe_unretained:相當於是對象類型的assign,在屬性所指的對象釋放時,屬性值不會清空;

copy:定義了一種擁有關係,但是設置新值時,不會保留新值,而是將其拷貝。

4.方法名:getter=<name>  setter=<name>

 getter=<name> 指定設置方法的方法名

setter=<name>  指定獲取方法的方法名

在對象內部讀取實例變量的時候,用直接訪問的形式;設置實例變量的時候通過屬性來做。

直接訪問實例變量,編譯器會直接訪問保存對象實例變量的那塊內存;並且不會調用其設置方法(setter),這樣就繞過了屬性定義的“內存管理語句”;也不會觸發“鍵值觀察KVO”。

但是在初始化方法中應該直接訪問實例變量;在懶加載中應該使用屬性,來通過setter方法訪問實例變量。

 

對象的等同性:

當比較兩個對象是否相等的時候,如果我們使用"=="來比較的話,比較的將是兩個對象的指針,如果這兩個指針指向同一個地址才相等,否則是不相等的。這顯然和我們所想的不符合,我們就可以通過重寫NSObject的"isEqual:",來書寫我們自己的判斷邏輯。比如說NSString類實現了自己的對比方法"isEqualToString"。

NSObject類中有兩個可以判定兩個對象是否具有等同的關鍵方法:

-(BOOL)isEqual:(id)Object;
-(NSUInteger)hash;

如果兩個對象通過isEqual判定相等,那麼兩個對象返回的hash值必須是同一個值;

相反,如果兩個對象的hash返回值是同一個值,isEqual判斷可以不相等。

當我們寫對象的同等性判斷時,應該重寫isEqual方法,如果被檢測參數和接受該消息的對象都屬於同一個類的話,就調用自己編寫的判定方法,否則就交由超類來判斷。

舉個例子:

//假設類名爲 myclass  有兩個NSString屬性 name  age 
- (BOOL)isEqualToMyclass:(myclass)cls{
    if(self == cls) return YES;
    if(![_name isEqualToString:cls.name]){
        return NO;
}
    if(![_age isEqualToString:cls.age]){
        return NO;
}
    return YES;
}


- (BOOL)isEqual:(id)object{
    if([self class] == [object class]){
        return [self isEqualToMyclass:(mycalss*)object];
}else
    return [super isEqual:object];
}
//推薦計算hash的方法
//如果屬性過多 不要盲目的去檢測每一個屬性 要根據實際情況來區分
//編寫hash方法時,應該使用計算速度快且碰撞機率低的算法
- (NSUInteger)hash{
    NSUInteger nameHash = [_name hash];
    NSUInteger ageHash= [_age hash];
    return nameHash^ageHash;

}

有一點要注意的是,如果放對象放入數組、字典、集合中後,又改變了該對象,可能會出現問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章