【IOS學習基礎】NSObject.h學習

1、<NSObject>協議和代理模式

  1.在NSObject.h頭文件中,咱們能夠看到ios

// NSObject類是默認遵照<NSObject>協議的
@interface NSObject <NSObject> { Class isa OBJC_ISA_AVAILABILITY; }

// 往上翻看到NSObject協議的聲明
@protocol NSObject
/*
  中間一大堆方法的聲明
*/
@end

  而後我就產生疑問了,爲何咱們本身定義的協議是這樣,後面加上了<NSObject>。爲何咱們本身聲明的協議須要遵照<NSObject>協議?函數

  咱們都知道,遵照一個協議以後就擁有的該協議中的全部方法的聲明。學習

@protocol MyProtocol <NSObject>
/*   中間一大堆方法的聲明 */
@end

  2.代理模式測試

  1> 代理模式:其實就是把本身的事情交給本身的代理去辦。A去作一件事,可是他作不到或者他不想作,那麼A就去請一個代理B,而且A還要定義一份協議(協議中聲明要作的事),只要B遵照了這份協議(表示B有能力幫A完成這些事),就按照這份協議把事情交給B去作。atom

  有一句話:誰想作什麼事,誰就定義協議,並設置一個代理;誰想幫作什麼事,誰就遵照協議並實現方法。spa

  2> 下面以一個例子來講明:debug

  有一個boss類代理

//
// Boss.h // 代理模式 //
// Created by Silence on 16/1/26. // Copyright © 2016年 Silence. All rights reserved. // 
#import <Foundation/Foundation.h>

// boss有一份協議<ZhuLiDelegate>
@protocol ZhuLiDelegate <NSObject>

// 助理掃地的方法
-(void)zhuLiSaoDi; @end

@interface Boss : NSObject // 老闆有一個助理Deegate,而且這個助理是遵照了ZhuLiDelegate協議的 // 注意:這裏我用的strong修飾的這個delegate(即Boss擁有一個助理的屬性Delegate,而且是強引用),可是我並無在Proxy類中聲明一個Boss的屬性(即助理有一個老闆的屬性),老闆與助理之間並無形成循環引用的問題。
@property (nonatomic,strong)id<ZhuLiDelegate> delegate; // 老闆想要掃地
-(void)saoDi; @end

//
// Boss.m // 代理模式 //
// Created by Silence on 16/1/26. // Copyright © 2016年 Silence. All rights reserved. // 
#import "Boss.h"

@implementation Boss // 老闆想要掃地(實現)
-(void)saoDi { // 老闆想要掃地,可是不想本身掃,因此他先查看本身的助理會不會掃地
    if ([self.delegate respondsToSelector:@selector(zhuLiSaoDi)]) { // 若是助理會掃地,那麼老闆就叫助理去掃地(調用助理的zhuLiSaoDi方法)
        [self.delegate zhuLiSaoDi]; } } // 說明:respondsToSelector方法,判斷某一個對象是否可以響應該方法

@end

有一個助理類Proxy指針

//
// Proxy.h // 代理模式 //
// Created by Silence on 16/1/26. // Copyright © 2016年 Silence. All rights reserved. // 
#import <Foundation/Foundation.h>
#import "Boss.h"

// 助理類遵照Boss類定義的協議ZhuLiDelegate

@interface Proxy : NSObject<ZhuLiDelegate>

// 那麼就表示Proxy有了該協議下的方法聲明

@end

//
// Proxy.m // 代理模式 //
// Created by Silence on 16/1/26. // Copyright © 2016年 Silence. All rights reserved. // 
#import "Proxy.h"

@implementation Proxy // 實現協議中的方法
-(void)zhuLiSaoDi { NSLog(@"助理去掃地!!!"); } @end

主函數中code

#import <Foundation/Foundation.h>
#import "Proxy.h"
int main(int argc, const char * argv[]) { @autoreleasepool { Proxy *proxy = [[Proxy alloc] init]; Boss *boss = [[Boss alloc] init]; // 老闆找一個助理對象做爲本身的代理
        boss.delegate = proxy; // 老闆想掃地(調用的本身掃地方法,實際是在裏面調用的助理掃地的方法)
 [boss saoDi]; } return 0; } // 打印
2016-01-26 14:47:33.817 代理模式[1348:73812] 助理去掃地!!!

  以上就是整個代理模式的實現了。

  3.繼續回到 1.中的那個問題,爲何本身定義的協議要遵照<NSObject>協議?

  而後我嘗試把上面的<zhuLiDelegate>協議聲明處的<NSObject>刪掉,編譯以後出現錯誤,以下;

  注意:respondsToSelector方法是在<NSObject>協議中聲明的方法。

  這裏咱們發現self.delegate對象不識別這個方法了,回到delegate聲明處:

@property (nonatomic,strong)id<ZhuLiDelegate> delegate; 
// 這個delegate遵照了<ZhuLiDlegate>協議,可是咱們把
<ZhuLiDlegate>協議遵照<NSObject>協議的地方刪除了,也就表示self.delegate失去了<NSObject>協議中的全部方法聲明,因此就致使方法不可識別了
// 另外,還需明白協議是能夠繼承了,既然全部NSObject類默認遵照了<NSObject>協議,那麼就表示全部繼承自NSObject的對象都擁有<NSObject>協議中的方法。除非你像上面同樣遵照本身的協議,而且本身的協議並不遵照基協議<NSObject>,這樣你的對象就沒法調用了<NSObject>中的方法了。

 2、<NSObject>協議的方法

  1.咱們都知道,協議中只能聲明一大堆方法,可是咱們能夠看到<NSObject>中有這麼幾個「屬性」

@property (readonly) NSUInteger hash; @property (readonly) Class superclass; @property (readonly, copy) NSString *description; @optional @property (readonly, copy) NSString *debugDescription;

  實際上這些和在分類中增長屬性同樣,這裏只會爲你生成相應的set、get方法,並不會生成相應的成員變量(實例變量)

  拿上面的代理模式作測試,我在<zhuLiDelegate>協議,我在其中加了一個name的「屬性」(始終記住:生成set、get方法)

  而後在遵照該協議的Proxy類中實現了該set、get方法(具體參考個人上一篇文章」【ios學習基礎】OC類的相關」中的在分類實現添加屬性),在這裏仍是貼上代碼

// 假如沒有實現相應set、get方法,用.屬性訪問會崩潰。
#import
"Proxy.h" #import <objc/runtime.h> static void *strKey = &strKey; @implementation Proxy -(void)setName:(NSString *)name { objc_setAssociatedObject(self, &strKey, name, OBJC_ASSOCIATION_COPY); } -(NSString *)name { return objc_getAssociatedObject(self, &strKey); } // 實現協議中的方法 -(void)zhuLiSaoDi { NSLog(@"助理去掃地!!!"); } @end

主函數中

#import <Foundation/Foundation.h>
#import "Proxy.h"
int main(int argc, const char * argv[]) { @autoreleasepool { NSObject *obj = [[NSObject alloc] init]; Proxy *proxy = [[Proxy alloc] init]; Boss *boss = [[Boss alloc] init]; // 老闆找一個助理對象做爲本身的代理
        boss.delegate = proxy; proxy.name = @"協議:name屬性"; NSLog(@"%@",proxy.name); // 老闆想掃地(調用的本身掃地方法,實際是在裏面調用的助理掃地的方法)
 [boss saoDi]; } return 0; } // 打印
2016-01-26 15:33:03.625 代理模式[1456:93614] 協議:name屬性 2016-01-26 15:33:03.627 代理模式[1456:93614] 助理去掃地!!!

  2.方法介紹

  1> - (BOOL)isEqual:(id)object;  比較兩個對象的地址是否相等

 

   2> - (id)performSelector:(SEL)aSelector;  調用sSelectopr方法

    - (id)performSelector:(SEL)aSelector withObject:(id)object; 調用sSelectopr方法,傳一個參數

    - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2; 調用sSelectopr方法,傳兩個參數

  這裏簡單介紹一下SEL類型:

  咱們都知道,每個繼承自NSObject對象都有一個isa指針,指向「類的方法列表」(類也有存儲空間,既也有地址,一個類在存儲空間中僅此一份)

@interface NSObject <NSObject> { Class isa OBJC_ISA_AVAILABILITY; }

 

  SEL就是對方法的一種包裝。包裝的SEL類型數據它對應相應的方法地址,找到方法地址就能夠調用方法。在內存中每一個類的方法都存儲在類對象中,每一個方法都有一個與之對應的SEL類型的數據,根據一個SEL數據就能夠找到對應的方法地址,進而調用方法。

  SEL類型的定義:  typedef struct objc_selector *SEL

  SEL的使用:SEL S1 = @selector(test);   將test方法包裝成SEL對象(無參)

         SEL S2= @selector(test:);   將test方法包裝成SEL對象(有參)

         SEL S3 = NSSelectorFromString(@"test");   將一個字符串方法轉換成爲SEL對象 

  3> - (BOOL)isProxy; 判斷一個實例是否繼承自NSObject,若是返回NO就是繼承自NSObject,反之返回YES

  4> - (BOOL)isKindOfClass:(Class)aClass;  判斷對象是否屬於aClass及其子類

    - (BOOL)isMemberOfClass:(Class)aClass;  判斷對象是否屬於aClass類

    - (BOOL)conformsToProtocol:(Protocol *)aProtocol;   檢查某個對象是否遵照了aProtocol協議

    - (BOOL)respondsToSelector:(SEL)aSelector;  判斷對象是否能響應aSelector方法

 

  5> 內存管理相關

    - (instancetype)retain OBJC_ARC_UNAVAILABLE;

    - (oneway void)release OBJC_ARC_UNAVAILABLE;

    - (instancetype)autorelease OBJC_ARC_UNAVAILABLE;

    - (NSUInteger)retainCount OBJC_ARC_UNAVAILABLE;

3、NSObject的方法

  1.初始化相關

  + (void)load;  類的頭文件被引入就會調用

  + (void)initialize;  類或其子類的第一個方法被調用以前調用

  - (instancetype)init  初始化

  + (instancetype)new OBJC_SWIFT_UNAVAILABLE("use object initializers instead");  建立一個對象

  + (instancetype)allocWithZone:(struct _NSZone *)zone OBJC_SWIFT_UNAVAILABLE("use object initializers instead");  alloc方法內部調用該方法,返回分配的存儲空間zone

  + (instancetype)alloc OBJC_SWIFT_UNAVAILABLE("use object initializers instead");  分配存儲空間

  - (void)dealloc OBJC_SWIFT_UNAVAILABLE("use 'deinit' to define a de-initializer");  對象銷燬時調用

  2.方法相關

  + (BOOL)instancesRespondToSelector:(SEL)aSelector;  判斷類是否有aSelector方法

  + (BOOL)conformsToProtocol:(Protocol *)protocol;  判斷類是否遵照此協議

  - (IMP)methodForSelector:(SEL)aSelector;  根據一個SEL,獲得該方法的IMP(函數指針)

  + (IMP)instanceMethodForSelector:(SEL)aSelector;  類方法,返回的是類方法的真正的函數地址

  - (void)doesNotRecognizeSelector:(SEL)aSelector;  處理接收者沒法識別的消息

  - (id)forwardingTargetForSelector:(SEL)aSelector;  當某個對象不能接受某個selector時,將對該selector的調用轉發給另外一個對象

  3.+ (BOOL)isSubclassOfClass:(Class)aClass;  判斷一個類是不是其子類

     + (NSUInteger)hash; 若是isEqual判斷兩個對象相等,那麼兩個對象的hash返回值也必定相等。反之hsah值相等,isEqual未必認爲二者同樣。

     + (Class)superclass; 得到父類類對象

     + (Class)class OBJC_SWIFT_UNAVAILABLE("use 'aClass.self' instead"); 得到本類類對象

     + (NSString *)description;  NSLog打印格式。

     + (NSString *)debugDescription;  打斷點時看到的格式。

相關文章
相關標籤/搜索