前面一章咱們整理了NSObject類,這一章咱們來看看NSObject協議的內容。html
NSObject協議提供了一組方法做爲Objective-C對象的基礎。其實咱們對照一個NSObject類和NSObject協議,能夠看到不少方法的方法名都是同樣的,只不過NSObject類提供的是類方法,是基於類級別的操做;而NSObject協議提供的是實例方法,是基於實例對象級別的操做。ios
若是一個對象若是採用了這個協議,則能夠被看做是一級對象。咱們能夠從這個對象獲取如下信息:git
實際上,Cocoa的根類NSObject就採用了這個類,因此全部繼承自NSObject類的對象都具有NSObject協議中描述的功能。接下來,咱們參照NSObject類,整理一下這些功能。github
相似於NSObject類,NSObject協議提供了一些方法來識別類。數組
若是想獲取對象的類對象,則可使用以下方法:app
- (Class)class
若是想獲取對象父類的類對象,則可使用如下只讀屬性:測試
@property(readonly) Class superclass
若是想查看某個對象是不是給定類的實例或者是給定類子類的實例,則可使用如下方法:線程
- (BOOL)isKindOfClass:(Class)aClass
這個方法應該是你們經常使用的方法。須要注意的是在類簇中使用這個方法。在類簇中,咱們獲取到的對象類型可能並非咱們指望的類型。若是咱們調用一個返回類簇的方法,則這個方法返回的實際類型會是最能標識這個類能作些什麼的類型。例如,若是一個方法返回一個指向NSArray對象的指針,則不能使用isKindOfClass:方法查看經是不是一個可變數組,如如下代碼:debug
if ([myArray isKindOfClass:[NSMutableArray class]]) { // Modify the object }
若是咱們使用這樣的代碼,咱們可能會認爲修改一個實際上不該該被修改的對象是沒問題的。這樣作可能會對那些指望對象保持不要變的代碼產生影響。指針
另外,查看對象是不是指定類的一個實例還可使用如下方法:
- (BOOL)isMemberOfClass:(Class)aClass
注意,這個方法沒法肯定對象是不是指定類子類的實例。另外,類對象多是編譯器建立的對象,但它仍然支持這一律念。
對於對象的測試,NSObject協議也定義了兩個方法,其中respondsToSelector:方法用於測試對象是否能響應指定的消息,這個方法能夠是類自定義的實例方法,也能夠是繼承而來的實例方法。其聲明以下:
- (BOOL)respondsToSelector:(SEL)aSelector
不過咱們不能使用super關鍵字來調用respondsToSelector:,以查看對象是不是從其父類繼承了某個方法。由於咱們能夠從super的定義可知,消息的最終實際接收者仍是self自己,所以測試的仍是對象的整個體系(包括對象所在類自己),而不只僅是父類。不過,咱們可使用父類來調用NSObject類的類方法instancesRespondToSelector:來達到這個目的,以下所示:
if( [MySuperclass instancesRespondToSelector:@selector(aMethod)] ) { // invoke the inherited method [super aMethod]; }
咱們不能簡單地使用[[self superclass] instancesRespondToSelector:@selector(aMethod)],由於若是由一個子類來調用,則可能致使方法的失敗。
還須要注意的是,若是對象可以轉發消息,則也能夠響應這個消息,不過這個方法會返回NO。
若是想查看對象是否實現了某個類,則可使用以下方法:
- (BOOL)conformsToProtocol:(Protocol *)aProtocol
這個方法與NSObject類的類方法conformsToProtocol:是同樣的。它只是提供了一個便捷方法,咱們不須要先去取對象的類,再調用類方法conformsToProtocol:。
若是咱們想獲取對象自己,則可使用如下方法:
- (instancetype)self
比較兩個對象是否相同,則可使用如下方法:
- (BOOL)isEqual:(id)anObject
這個方法定義了對象相同的意義。例如,一個容器對象可能會按照特定規則來定義兩個對象是否相等,如其全部元素的isEqual:請求都返回YES。咱們在自定義子類時,能夠重寫這個方法,以使用咱們本身的規則來評判兩個對象相等。
若是兩個對象相等,則它們必須擁有相同的hash值。在子類中定義isEqual:方法並打算把子類的實例放入集合中時,這一點很是重要。所以在子類中必須同時定義hash。
hash值是一個整數值,它能夠用於在hash表結構中做爲一個表地址。其聲明以下:
@property(readonly) NSUInteger hash
若是一個可變對象被添加到一個以hash值來肯定對象位置的集合中,則當對象還在集合中時,其由hash方法返回的值不能改變。所以,hash方法不能依賴於對象內部的任何狀態信息,或許咱們必須確保對象在集合中時,不能改變其內部狀態信息。好比,一個可變字典能夠放到一個hash表中,但當它還在表中時,不能改變它。
在NSObject類中,定義了一系列的發送消息的方法,用於在目標線程中執行方法。NSObject協議也定義了以下幾個方法,來執行發送消息的任務:
- (id)performSelector:(SEL)aSelector - (id)performSelector:(SEL)aSelector withObject:(id)anObject - (id)performSelector:(SEL)aSelector withObject:(id)anObject withObject:(id)anotherObject
這三個方法基本相同,只不事後面兩個方法能爲selector指定的方法攜帶參數。所以咱們以performSelector:爲例。
performSelector:方法的使用與直接將消息發送給對象的效果是同樣的,以下面幾個操做,作的事情是同樣的:
id myClone = [anObject copy]; id myClone = [anObject performSelector:@selector(copy)]; id myClone = [anObject performSelector:sel_getUid("copy")];
區別在於,performSelector:容許在運行時再去肯定對象是否能處理消息。而[anObject copy]中,若是anObject不能處理copy,編譯器就直接會報錯。
若是方法的參數過多,以致於上面幾個方法都沒法處理,則能夠考慮使用NSInvocation對象。
描述對象的方法與NSObject類中描述類的方法其方法名相同,都是description,其聲明以下:
@property(readonly, copy) NSString *description
這個方法用於建立一個對象的文本表達方式,例如:
ClassName *anObject = <#An object#>; NSString *string = [NSString stringWithFormat:@"anObject is %@", anObject];
爲了便於調試,NSObject協議還定義debugDescription方法,該方法聲明以下:
@property(readonly, copy) NSString *debugDescription
該方法返回一個在調試器中顯示的用於描述對象內容的字符串。在調試器中打印一個對象時,會調用這個方法。NSObject類實現這個方法時只是調用了description方法,因此默認狀況下,這兩個方法的輸出都是同樣的。咱們在子類中能夠重寫這個方法的實現。
NSObject協議的定義的不少方法都是咱們日常常用的。咱們在建立NSObject類的子類時,默認都繼承了NSObject類對於NSObject協議的實現。若是有特殊的需求,咱們能夠重寫這些方法。
固然,NSObject協議還定義了一些方法,如咱們很是熟悉的retain, release, autorelease, retainCount方法,不過這些方法在ARC時代已通過時了,咱們在此不過多說明。
http://southpeak.github.io/blog/2015/01/31/nsobjectzhi-er/