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>中的方法了。
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;
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; 打斷點時看到的格式。