《Effective Objective-C 2.0》—(第6-10條)—對象、屬性、equalToString、關聯對象

來源:互聯網
上載者:User

標籤:對象屬性equaltostring

    用OC等物件導向語言編程時,“對象”(object)就是“基本構造單元”(building block),開發人員可以通過對象來儲存並傳遞資料。在對象之間傳遞資料並執行任務的過程就叫做“訊息傳遞”(Messaing)。

    當應用程式運行起來以後,為其提供相關支援的代碼叫做“Objective-C運行期環境”(Objevtive-C runtime),它提供了一些使得對象之間能夠傳遞訊息的重要函數,並且包含建立類執行個體所用的全部邏輯。在理解了運行期環境各個部分協同工作的原理之後,你的開發水平會進一步提升。

第6條:理解“屬性”這一概念

    “屬性”(property)是OC的一項特性,用於封裝對象中的資料。OC對象通常會把其所需要的資料儲存為各種執行個體變數。屬性還有一些存取方法setter和getter。這一概念已經定型,開發人員可以令編譯器自動編寫與屬性相關的存取方法。

    在描述個人資訊的類中,也許會存放人名、生日、地址等內容。可以在類介面的public區段中聲明一些執行個體變數:

@interface EOCPerson : NSObject{@public    NSString* _firstName;    NSString* _lastName;@private    NSString* _someInternalData;}@end;

    原來用過Java和C++的人比較熟悉這種寫法,可以定義變數的範圍。OC很少這麼做。該寫法的變數記憶體布局在編譯期已經固定了。:


詳細見《深度探索C++物件模型》http://blog.csdn.net/hherima/article/details/8888539

    如果EOCPerson類中添加了一個屬性NSString* _dateOfBirth,那麼代碼需要重新編譯,否則就會出錯。例如,某個程式碼程式庫中的代碼使用了一份舊的類定義。如果和其相連結的代碼使用了新的類定義,那麼運行時就會出現不相容現象。各種程式設計語言都有應對此問題的方法。Objetive-C的做法是,把執行個體變數當做一種儲存位移量所有的“特殊變數”(special variable),交由“類對象”保管。位移量會在運行期尋找,如果類的定義變了,那麼儲存的位移量也就變了,這樣的話,無論何時訪問執行個體變數,總能使用正確的位移量。甚至可以在運行期向類中新增執行個體變數,這就是穩固的“應用程式二進位介面”(Application Binary Interface,ABI)

    @property文法,能夠訪問封裝在對象裡的資料。因此,也可以把屬性當做一種簡稱,其意思是說:編譯器會自動產生一套存取方法,用以訪問給定類型中具有給定名稱的變數。例如:

@interface EOCPerson : NSObject@proterty NSString* firstName;@proterty NSString* lastName;@end

對於類的使用者來說,上述代碼寫出來的類與下面這種寫法等效:

@interface EOCPerson : NSObject-(NSString*)firstName;-(void)setFirstName:(NSString*)firstName;-(NSString*)lastName;-(void)setLastName:(NSString*)lastName;@end

訪問屬性使用點文法,屬性另外一個好處是可以使用自動合成@synthesize,另外@dynamic關鍵字可以告訴編譯器不要自動產生屬性存取方法,這裡不再累贅。

屬性特質

屬性有四種特質:原子性、讀/寫入權限、記憶體管理語義和方法名:

1. 原子性 預設情況下是atomic特質(儘管沒有atomic這個特質),nonatmic告訴編譯器不使用同步鎖。

2. 讀/寫入權限  具備read/write(讀寫)特質的屬性擁有存取方法。若屬性由@synthesize實現,則編譯器會自動產生這兩個方法。具備readonly(唯讀)特質的屬性僅擁有getter方法。

3. 記憶體管理語義

● assign 只會針對純類型簡單賦值操作

● strong 擁有關係,為這種屬性設定新值的時候,保留新值,釋放舊值。

● weak 同assign,但是對象銷毀的時候,屬性值也會清空

● unsafe_unretained 同assign,它適用於“物件類型”這也是跟assign的唯一區別

● copy 跟strong的特質類似。然而設定setter不會保留新值,而是將其“拷貝”(copy)。當屬性類型是NSMutableString*時,需要copy特質,目的是為了防止自己的屬性被無意修改。參考《Effective Objective-C 2.0》—(三)—、介面與API設計、深拷貝、淺拷貝 》最後部分http://blog.csdn.net/hherima/article/details/38403277

4. 方法名

● getter=<name>指定擷取方法名

● setter=<name>指定“設定方法”名

本節要點

● 使用@property 文法來定義對象中封裝的資料

● 通過“特質”來指定儲存資料所需的正確語義。

● 在設定屬性對應的執行個體變數時,一定要遵從該屬性聲明的語義

● 開發iOS程式時候應該使用nonatomic特質,因為atomic會嚴重印象效能。

第7條:在對象內部盡量直接存取執行個體變數

    在對象之外訪問執行個體變數時,總是應該通過屬性來做,那麼在對象內部?筆者強烈建議大家在讀取執行個體變數的時候採用直接存取的形式,而在設定執行個體變數的時候通過屬性來做。之所以要通過“設定方法”來寫入執行個體變數,首要原因在於,這樣能夠確保相關屬性的“記憶體管理語義”得以貫徹。

第8條:理解“對象等同性”這一概念

    NSObject協議中有兩個判斷等同性的關鍵方法:

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

    NSObject類對這兩個方法的預設實現是:若且唯若“指標值”(pointer value,可理解為記憶體位址)完全相等時,這兩個對象才相等。如果"isEqual:"方法判定兩個對象相等,那麼其hash方法必須返回同一個值。但是,如果兩個對象的hash方法返回同一個值,那麼“isEqual:”方法未必會認為兩者相等。

先看看"isEqual:"介面,如果一個類中有A,B,C三個欄位,那麼isEqual就要對三個地段逐個對比,然後都相同的時候就返回ture。

再看看hash方法,一般的做法是,將A,B,C三個欄位分別hash,最後再異或一下。

-(NSUInteger)hash{NSUInteger firstNameHash = [_firstName hash];NSUInteger lastNameHash = [_lastName hash];NSUInteger ageHash = _age;return firstNameHash ^ lastNameHash ^ ageHash}

這種做法既能保持高效率,又能使產生的雜湊碼至少位於一定範圍之內,而不會過於頻繁的重複。

特定類型所具有的等同性判定方法

    除了剛才提到的NSString之外,NSArray與NSDictionary類也有判定方法,前者是“isEqualToArray”後者是“isEqualToDictionary”。

除了剛才

等同性判定的執行深度

    建立等同性判斷方法時,需要決定是根據整個對象來判斷,還是僅根據其中幾個欄位來判斷。NSArray的檢測方式為先看兩個數組所含有對象個數是否相等,若相同,則在每個對應位置的兩個對象身上調用其“isEqual”方法,如果對應位置上的對象均相等,那麼這兩個數組就相等,這叫做“深度等同判定”

容器中可變類的等同性

直接舉例NSSet就好。

第一步:在NSSet中添加一個可變數組A[@1,@2];那麼set中就有了一個對象,{[@1,@2]}

第二步:再向NSSet中添加一個可變數組B[@1,@2],由於數組A和B是一樣的,所以set中仍是一個對象,這也負責set的特性。

第三步:向NSSet中添加一個可變數組C[@1],那麼set中就有了兩個對象,{[@1],[@1,@2]}.

第四步:我們改變數組C的值為[@1,@2],那麼set居然包含了兩個相同的對象,{[@1,@2],[@1,@2]}.這不符合set的特性。

第五步:複製一份set。新的set的內容又變成{[@1,@2]}了。看上去set好像是由一個空set開始,通過逐個向其中添加新對象而建立出來的。

這是因為像set這樣的collect,把某個對象放入collect之後,就不應該改變其雜湊碼了。

本節要點:

● 若想檢測對象的等同性,請提供“isEqual:”與hash方法。

● 相同的對象必須具有相同的雜湊碼,但是兩個雜湊碼相同的對象未必相同。

● 不要盲目的逐個檢測每個屬性,而是應該依照具體需求來定製檢測方案

● 編寫hash方法時,應該使用計算速度快而且雜湊碼碰撞幾率低的演算法。

第9條:以“類族模式”隱藏實現細節

    “類族”(class cluster)模式是一種很有用的模式(pattern),可以隱藏“抽象基類”(abstract base class)背後的實現細節。Objective-C的系統架構中普遍使用此模式。比如,iOS的使用者介面架構UIKit中就有一個名為UIButton類。

第10條:在既有類中使用關聯對象存放自訂資料

    直接列舉開發中常見的例子吧:一個UIAlertView的使用,通常的做法是這樣的:

-(void) askUserAQuestion{    UIAlterView *alert = [[UIAlterView alloc] initWithTitle:@"Question" message:@"what do you want to do?" delegate:self cancelButtonTitle:@"cancel" otherButtonTitle:@"cancel",nil];    [alert show];}//UIAlertViewDelegate protocol method-(void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{    if(buttonIndex == 0){        [self doCancel];    } else {        [self doContinue];    }}

alertView的建立和處理,不在一個地方。開發過程中,經常來回滑動代碼查看。那麼“關聯對象”就起到作用了,將操作跟UIAlertView關聯起來。例如:

static void* EOCMyAlertKey = "EOCMyAlertViewKey";-(void) askUserAQuestion{    UIAlterView *alert = [[UIAlterView alloc] initWithTitle:@"Question" message:@"what do you want to do?" delegate:self cancelButtonTitle:@"cancel" otherButtonTitle:@"cancel",nil];    void (^block)(NSInteger) = ^(NSInteger buttonIndex){            if(buttonIndex == 0){            [self doCancel];        } else {            [self doContinue];        }        };    objc_setAssociatedObject(alert,EOCMyAlertViewKey,block,OBJC_ASSOCIATION_COPY);    [alert show];}//UIAlertViewDelegate protocol method-(void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{    if(buttonIndex == 0){        [self doCancel];    } else {        [self doContinue];    }}-(void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{    void (^block)(NSInteger) = objc_getAssociatedObject(alertView,EOCMyAlertViewkey);    block(buttonIndex);}

介紹一下改進代碼中的技術

● void objc_setAssociatedObject(id object, void*key ,id value,objc_AssociatedPolicy policy) 

此方法以給定的鍵和策略為某對象設定關聯對象值

● id objc_getAssociatedObject(id object,void* key)

此方法根據給定的鍵從某對象中擷取對應的關聯對象值

● void objc_removeAssociatedObjects(id object);

是對象關聯類別型


但是,這個方法應該慎用,在使用block的時候小心循環參考(參考bloc的介紹)。所以一般的做法還是:從中繼承子類,把block儲存為子類中的屬性。


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.