谈谈Objective-C中的协议

协议简述

协议(protocol)是oc中的一个重要的语言特性,协议中定义了一些方法,若某个类想要实现这个协议中的一系列方法,则必须遵守这个协议,这个类对象被称为"委托对象" , 即为"代理"。这也说明这种模式是单向的,消息的发送方(委托方) 需要知道接收方(代理方)是谁,即只需要知道它的代理方是否遵守了协议( protocol)反过来是不需要的。

协议的两种模式

这两种模式分别为委托模式(delegate)和数据源模式(dataSource),区别在于信息的流向不同.

  • 委托模式:信息通过协议中的方法参数从委托方流向代理方,或者事件发生时
    委托者通知代理者 ,简单表述为:委托方传递信息或者事件到代理方。

  • 数据源模式:数据源模式的信息流向与委托模式正好相反,委托方需要从代理方拉取数据。 简单表述为:代理方传递信息到委托方。

    图示 :(箭头表示信息的流向)

QQ20170720-0@2x.png

协议的作用

  • 进行对象间的相互通信。委托模式时这个委托方可以给代理方回传一些信息,也可以在发生相关事件时通知委托对象.数据源模式时, 代理方可以给委托方回传一些信息,这个信息通常在代理方实现方法的返回值中。
  • 可将数据与业务逻辑解耦。在数据源模式中,委托方只需要构建如何处理这些数据的业务逻辑代码,而不用关心来源,来源由遵守协议的代理方提供。在委托模式中,委托方向代理方提供信息,代理方拿到信息后构建相关的业务逻辑。

协议的声明与使用

为了演示此模式,举一个UIWebView中的UIWebViewDelegate作为例子:

@protocol UIWebViewDelegate <NSObject>

@optional

// 将NSURLRequest对象传递给代理方,代理方由此判断将是否加载此网页,并将结果返回给委托方做处理,这个方法很好的说明了协议用于对象之间的相互通信。
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
// 通知代理方网页开始加载
- (void)webViewDidStartLoad:(UIWebView *)webView;
// 通知代理方网页加载完成
- (void)webViewDidFinishLoad:(UIWebView *)webView;
// 通知代理方网页加载失败,并将NSError 对象传递给代理方。
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error;

@end
  • 声明协议要用到@protocol 关键字,后面跟着协议名 ,协议如果是委托模式就在类名后面加上Delegate一词,如果是数据源模式就在类名后面加上DataSource一词。整个类名采用‘‘驼峰法’’来写。协议名后面的<>内是这个协议继承的另一个协议,遵守此协议的委托对象也可以实现该协议的方法。协议的多继承也很好的弥补了oc不支持多重继承的语言缺陷。

  • 协议中的方法名要写清楚,方法名应该能准确的传达出委托对象实现该方法的时机和作用。

  • 有了这个协议以后,那么就需要用一个属性来存放委托对象了。这个属性需定义成weak,而不是用strong,如果使用strong,委托方持有委托对象,委托对象也会持有委托方,两个对象之间都是强应用,形成你中有我,我中有你的关系,就会形成循环引用(retain circle) 造成这两个对象无法销毁。

  • 注意协议中的@optional (可选的),声明这个关键字的方法表示委托对象不需要必须实现协议中的所有方法,如UIWebViewDelegate中的webViewDidStartLoad: 协议方法,也许委托对象并不用在网页开始加载时做任何事情,所以可以不必实现这个方法。如果要在委托对象上调用可选方法,那么需要提前判断这个委托对象能否响应相关的选择器,需要使用类型信息查询方法respondsToSelector: 来判断:

    if ([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
        [self.delegate webViewDidStartLoad:self];
    }

这段代码的意思是来判断委托对象是否实现了相关方法。如果实现了就调用,如果没有实现就不执行任何操作。这样委托对象就可以选择性的实现相关的方法了。即使self.delegate = nil,即没有设置委托对象的时候,程序也能照常运行,因为给nil发送消息将使if语句的值成为false。

  • 在协议方法中,应该总是把委托实例及发起方也一并传入方法中,例如在UIWebViewDelegate协议中,协议方法中总是带有UIWebView实例。这样做的好处是委托对象在实现方法时可以区分不同的委托实例。
- (void)webViewDidStartLoad:(UIWebView *)webView{

    if(webView == self.webViewA){
        // do something;
    } else if (webView == self.webViewB){
       // do something;
    }
}
  • 我将用一个控制器来加载一个webView,如果控制器要实现UIWebViewDelegate的相关协议方法,控制器必须成为webView的委托对象,即代理。

@interface ViewController ()<UIWebViewDelegate>
@end

@implementation ViewController

- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    UIWebView *webView = [[UIWebView alloc] init];
    webView.frame = self.view.bounds;
    [webView loadRequest:request]
    // 成为webView的委托对象,即代理。
    webView.delegate = self;
    [self.view addSubview:webView];
    
}

#pragma mark -- 根据需求选择性的实现协议中的方法

- (void)webViewDidStartLoad:(UIWebView *)webView{
    
}

- (void)webViewDidFinishLoad:(UIWebView *)webView{
    
}

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{
    
}

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
    
    return YES;
}

总结

  • 委托模式为某个对象提供了一套接口,这套接口被称为协议,协议中的方法可将相关信息或相关事件告知其他对象,这个对象必须遵守这个协议,并成为这个对象的代理。
  • 协议的作用是进行对象间的相互通信及数据与业务逻辑解耦。

参考资料

*《Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法》中的第4章 第 23条:通过委托与数据源协议进行对象间通信。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,245评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,749评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,960评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,575评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,668评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,670评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,664评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,422评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,864评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,178评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,340评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,015评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,646评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,265评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,494评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,261评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,206评论 2 352

推荐阅读更多精彩内容