iOS开发总结——协议代理的认识

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 @280me @tinyfool ,我的美女leader @七了个六 。加油加油我可以做的更好!

原文地址:https://www.cnblogs.com/nycoder/p/4669614.html