標籤:
1.前言
自今年5月底正式轉iOS之後,天天get新技能,很多技能在腦子裡迴旋不吐不快,所以,寫點東西整理一下。先從協議代理開始。
2.協議方法的聲明
@protocol EventMenuBarDelegate <NSObject>- (void)delegateShouldDoWhenMenuButtonTapped:(UIButton *)button;@end
以上代碼意思是,利用@protocol 指令聲明協議名EventMenuBarDelegate,並遵從NSObject協議,在協議中聲明了一個方法
- (void)delegateShouldDoWhenMenuButtonTapped:(UIButton *)button,由於沒有用@option 指令聲明,所以服從該EventMenuBarDelegate的對象必須實現delegateShouldDoWhenMenuButtonTapped: 這個方法。
3.協議代理的認識
協議中聲明的方法,其實就是C++等物件導向的程式設計語言的抽象方法,不需要具體實現過程,但是必須要聲明方法介面,以用於繼承該類的子類進行適配,這就是設計模式中的適配器模式。在Objective-C中,子類通過遵從協議和繼承超類以達到C++的多繼承的效果。我認為這樣的好處就是,多態。
4.情景類比與代碼實現
委託代理其實就是某個對象需要完成某個方法所找的另外一個對象。比如,我是個懶人,我不喜歡洗衣服,我找洗衣助理幫我洗,此時,助理就是我洗衣服的委託代理,並且必須遵從洗衣協議並實現洗衣服的過程。在助理洗完之後,我再作為洗衣助理的委託代理表示感謝,向助理說謝謝並付錢。(有點繞,需要腦洞大開)如果用程式實現就可以像下面一樣寫。其實,這個情景中,代碼類比了兩個委託代理,一個是洗衣服的協議代理,另外一個是整個商務邏輯的協議代理。
1)洗衣服的協議方法
#import <Foundation/Foundation.h>#import "APPBLLDelegate.h" @protocol WashClothes <NSObject>- (void)washClothes:(int)num complete:(id<APPBLLDelegate>)delegate;@end
代碼聲明了洗衣服的協議,遵從該協議的所有對象必須完成一件事根據傳入的衣服數量洗衣服,洗完之後代理我(代理)再做出響應的處理。
2)商務邏輯協議
@protocol APPBLLDelegate <NSObject>- (void)didWashClothesSuccess:(BOOL)finished leftNum:(int)left;- (void)didWashClotheFailed:(NSString *)errorMsg;@end
商務邏輯的協議中,聲明了兩個方法,一個是洗衣成功後我需要做的,另一個是洗衣未成功我需要做的。其實,這裡完全可以抽象成任何事件的協議方法,換個名字就成。比如,一次網路請求響應,一次資料庫的讀庫寫庫。
而作為該商務邏輯的我(代理)而言,當洗衣助理把我當代理參數傳入的時候,並不確定我的類型,僅作為一個id類型的對象指標傳入,但是我必須遵循APPBLLDelegate協議,即
(id<APPBLLDelegate>)delegate
3)我(使用者)的類代碼實現
標頭檔
#import <Foundation/Foundation.h>#import "WashClothes.h"#import "APPBLLDelegate.h"@interface User : NSObject <APPBLLDelegate>@property int clothesNum;@property (weak, nonatomic) id<WashClothes> delegate;- (void)askAssistantForWashingClothes;@end
我洗衣服的代理是助理,助理的類不一定是什麼類,我不確定,所以用id類型來指代其類型(當然,如果確定的話就指定這個類名就好),但是助理必須遵循洗衣協議,即,
id<WashClothes> delegate
而我作為整個商務邏輯的代理,我也必須遵循商務邏輯的協議(腦洞再大點)。即,
User : NSObject <APPBLLDelegate>
實現檔案
#import "User.h"@implementation User- (void)askAssistantForWashingClothes { [self.delegate washClothes:self.clothesNum complete:self];}- (void)didWashClothesSuccess:(BOOL)finished leftNum:(int)left { if (finished) { NSLog(@"助理已洗完衣服,很感謝,支付洗衣費用"); } else { NSLog(@"助理未能洗完衣服,剩餘%d件", left); }}- (void)didWashClotheFailed:(NSString *)errorMsg { if (errorMsg != nil) { NSLog(@"報錯:%@", errorMsg); }}@end
我不洗衣服,我請求助理洗衣服,那麼助理必須遵循洗衣協議,並且實現其具體過程,但我不需要實現,我的工作僅是向代理髮送洗衣訊息。當我的助理洗完衣服之後,我作為商務邏輯的代理,我必須做出反應,比如我要說謝謝給錢,或者沒洗完不給錢,再或者出現問題我要報錯。
這裡,商務邏輯可以抽象為一個網路請求,比如,網路狀況良好,我請求成功,正確傳參,正確返回。或者,網路狀況良好,錯誤傳參,錯誤返回。再或者,網路狀況渣渣,就報錯吧。。
4)洗衣助理要做的
標頭檔
#import <Foundation/Foundation.h>#import "WashClothes.h"@interface Assistant : NSObject <WashClothes>@property int totalNum;- (instancetype)init;@end
洗衣助理必須遵循洗衣協議,即,
Assistant : NSObject <WashClothes>
實現洗衣方法,即,
- (void)washClothes:(int)num complete:(id<APPBLLDelegate>)delegate;
實現檔案
#import "Assistant.h"@implementation Assistant- (instancetype)init { self = [super init]; if (self) { self.totalNum = 10; } return self;}- (void)washClothes:(int)num complete:(id<APPBLLDelegate>)delegate { int left = self.totalNum - num; if (left > 0) { [delegate didWashClothesSuccess:YES leftNum:left]; } else { [delegate didWashClothesSuccess:NO leftNum:abs(left)]; [delegate didWashClotheFailed:@"未能洗完衣服!"]; }}@end
洗衣助理在初始化對象時,預設洗衣服最大數目是10件,並實現洗衣服的具體過程,洗完衣服之後給我(商務邏輯的代理)發送訊息。也就是說,洗衣助理只需要洗衣服,不需要管洗完衣服做什麼,剩下的將結果回傳給我,讓我來進行訊息反饋。
5)程式單一入口
#import <Foundation/Foundation.h>#import "User.h"#import "Assistant.h"int main(int argc, const char * argv[]) { @autoreleasepool { User *user = [[User alloc] init]; user.clothesNum = 20; Assistant *assistance = [[Assistant alloc] init]; user.delegate = assistance; [user askAssistantForWashingClothes]; } return 0;}
主程式建立了執行個體我,設定我的洗衣數量20,建立助理執行個體,設定我的洗衣委託代理為助理,最後向助理髮送訊息,助理執行洗衣服這個方法。
6)運行結果
2015-07-23 11:34:07.869 NYDelegateTest[1313:68830] 助理未能洗完衣服,剩餘10件
2015-07-23 11:34:07.870 NYDelegateTest[1313:68830] 報錯:未能洗完衣服!
5.小結
1)Objective-C的協議可以實現適配器模式,通過繼承和遵循協議,達到C++的多繼承效果。通過該機制可以實現多子類的適配,使不同子類擁有各自獨特的方法,匹配自身需求。
2)運用協議代理代碼實現時,必須要設定執行個體的代理,比如,
user.delegate = assistance;
這一句必不可少,否則,代理是nil,發送訊息就失效,方法不能執行,不會有任何輸出。
3)這個類比情景中,代碼實現了兩個協議代理。
一個是,我找助理作為我的洗衣代理。
另一個是,助理洗完衣服後,將處理結果回傳給我(商務邏輯代理)。
4)在自學之初,我始終搞不清楚,table view的data source和delegate。現在才明白,其實兩者都是協議代理,只不過名字不同罷了。data source的方法主要針對table view的一些UI資料來源載入顯示。而delegate更多的是對table view的一些操作作出響應(但是也有什麼height之類的協議方法,我也是醉了,強迫症傷不起)。總之,如果單獨建立table view 而不是用table view controller,data source和delegate都必須設定,且實現其協議方法。
5)文章如有理解錯誤,請留言交流,我會及時訂正,感謝~
6)來上海之後,我兩個月內成長了很多,學到很多,很感恩。我希望把我所學到明白的東西熟練應用,並能深入理解其原理,所以要學的很多很多。但是現在淡定多了。終生學習,快樂學習。謝謝協助我的所有人 @不知霜舞哀傷udspj @tinyfool ,我的美女leader @七了個六 。加油加油我可以做的更好!
iOS開發總結——協議代理的認識