彻底理解Objective-C:协议(protocol),代理(delegate)

许多同学在第一次接触Objective-C里面的代理,协议,代理协议这些概念,很容易被搞晕.
再加上初次接触 Objective-C 类的property等写法看着比较陌生,更加剧了理解难度.
本文的目的就是,让你彻底理解协议,代理,以及他们的使用场景.
我将要用一个大家都熟悉的场景来讲解.

导演可以拍电影,调教演员,也可以进入到后期制作.导演也可以招聘"助理",帮他干后期制作的事情.

我们先写看协议.(protocol)协议=protocol

协议是什么? 协议就是一纸协议,听着好像废话,你可以从许多角度来看协议:

  • 协议是某种约定(或许多约定的组合)
  • 协议是双方要遵守的东西.
  • 协议是许多小项的组合.
  • 协议是双方的约定.
  • 协议有个协议名字
    那Objective-C里面呢, 协议就是”功能的集合”===>”方法的集合” ,也就是”能力清单”.

协议就是带名字的能力清单

我们先抛开Objective-C里面那些ViewController, DataSource, View那些概念,看上面说的具体的协议例子:

 # 影视行政助理协议(协议的名字) # 

功能列表:

  1:能寻找合适的胶片冲洗厂,进行胶片的冲洗(必须).

  2:后期音频合成,可以将录制好的音频合成到胶片里面(必须).

  3:需找海报制作商(必须).

  4:负责片场治安秩序(非必须)


所以,这个协议名字叫

”影视行政助理协议”

这是一纸清单.这个清单有4个项目(功能/方法),其中前3个是必须的.
协议有协议名字,有清单(方法列表,或者说功能列表)

协议就是”协议就是带名字的能力清单”.

下面再说代理(人).(delegate)

上面提到”协议是双方的约定”,否则单单只存在一份协议是没有意义的(但是没有错),我们来看看协议涉及到的双方.

  • 导演(Director):导演很忙,(实际上,那份协议就是导演自己编写的),因为他要把主要精力放到”艺术创作”上,把重要的琐事”代理”出去(这里的代理是动词),或者说把重要的琐事让”代理”去干(这里的代理是名词),为了便于理解,我们用名词这种方式.
    我们再看看实际情况下,影视圈的情况:
  • oldStreet:(老街)男,一个长期混迹影视圈的能人,行政能力很强,快50了,
    做事老派,不上网,没有微信,喜欢通过人脉干事,上面那4个活他都能干,尤其负责片场治安那个.
  • newSchool:(新校)女,刚刚毕业的电影学院学生,20出头,新潮人类,离开微信不能活那种,需要找工作.上面那个协议里面的事,她能干3个,负责片场治安秩序?还是算了吧.

现在,这两人都来应聘,都符合条件(就是说这两人都可以干协议里面规定必须能干的事情),在Objective-C里面,我们说”这两人都实现了这个协议”.

而导演这边呢,以前是孤家寡人,累的要死,现在有了助理了,对吧? ,以前导演可以这么自我介绍(导演的属性):

”XX导演,男,35岁,恐怖片导演,只做恐怖片,不是北京人,未婚”.

但是现在你要这么介绍了:

”XX导演,男,35岁,恐怖片导演,只做恐怖片,不是北京人,未婚,我的影视后期制助理是谁谁谁”.

如果导演太忙了,他可能还需要其他的人帮他干活,比如剧本医生,那就要这么介绍:

”XX导演,男,35岁,恐怖片导演,只做恐怖片,不是北京人,未婚,我的行政助理是谁谁谁,我的剧本医生是谁谁谁”.

这段意思是说,导演可以超过一个代理.我们把情况搞简单,先只给他一个代理(影视后期制作).
导演的影视后期制作是”某某某”,这句话的复杂版本是:

某某某可以干"影视行政助理协议"这个协议里面规定的必须干的事情,导演的"导演的影视后期制作代理"被设置成"某某某",<br/>
导演可以安排助理干"影视行政助理协议"里面的任何事情了.

我们可以看到, 是 协议 将本来没有关系的两方(导演,某某某)联系了起来.
下面是filmAssistantProtocol.h 文件,就是协议文件.

@protocol 开头,
以@end结尾.
//filmAssistantProtocol.h
@protocol filmAssistantProtocol   //协议名字

@required
/*
 1:能寻找合适的胶片冲洗厂,进行胶片的冲洗(必须).
 2:后期音频合成,可以将录制好的音频合成到胶片里面(必须).
 3:需找海报制作商(必须).
 4:负责片场治安秩序(非必须)
 */

+(void) filmDeveloped;  //冲洗照片
+(void) audioProcess;   //音频合成
+(void) posterMake ;   //海报制造

@optional
-(void) siteSecurity; //现成安保

@end

我们可以很清楚的看到,协议(protocol)就是一个协议名字+功能列表(实际就是方法列表)

然后看看导演这里的写法(Director.h)

//
//  Director.h

#import <Foundation/Foundation.h>
#import "filmAssistantProtocol.h"

//#import "剧本医生协议.h"

@interface Director : NSObject

@property (strong, nonatomic) NSString   *directorName;  //定义导演的名字

//

/*定义一个后期制作的代理 backAssistant,这个代理遵守 filmAssistantProtocol 这个
协议,即:这个后期制作的代理 应该能干filmAssistantProtocol 这个协议里面定义的
功能集合
 
与通常我们见到的 
 @property(nonatomic, retain)  id <someProtocol>        delegate; 写法其实是一回事.
                                      |                   |
                                      |                   |
                                      V                   V
 @property(nonatomic, retain)  id<filmAssistantProtocol> backAssistant;

*/

@property(nonatomic, retain) id<filmAssistantProtocol> backAssistant;

/*我们目前只有一个代理,如果需要其他代理(比如剧本医生),将会是下面的写法*/

//@property(nonatomic, retain) id<剧本医生协议> 剧本代理人;

-(void) posterMake;  //印刷海报,导演自己也可以印刷海报
-(void) introMyself; // 导演自我介绍的方法.

@end

注意:与导演名字directorName并列的另外一个属性是backAssistant,
backAssistant/后期制做代理

再看看一个newSchool的情况:



//
//  newSchool.h
//  Film
//
//  Created by Alex on 4/9/16.
//  Copyright © 2016 Alex. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "filmAssistantProtocol.h"
@interface newSchool : NSObject<filmAssistantProtocol>  //实现了filmAssistantProtocol这个协议
@property (strong, nonatomic) NSString   *girlname;
//冲洗照片
-(void) filmDeveloped;
//音频合成
-(void) audioProcess;
//海报制造
-(void) posterMake;
@end

我们看到, filmAssistantProtocol 出现了两次,

  • Director.h ,可以理解成:[导演说,我要有个助理,能干后期制作那些事]
  • newSchool.h ,可以理解成:[一个毕业新手说,干后期制作那些事,我都能干]

最后的组合

 

//
//  ViewController.m
//

#import "ViewController.h"
#import "Director.h"
#import "newSchool.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSLog(@"程序开始了");
    Director* oneDirector = [[Director alloc] init]; //初始化一个导演
    
    oneDirector.directorName = @"PeterJ";    // PeterJ ,彼得杰克逊,指环王导演,这样让你们读代码好记.

    [oneDirector introMyself];   //导演介绍自己,虽然有"assistant"这个属性,但是还么有指定具体人.
    
    [oneDirector posterMake];   //导演自己也可以posterMake,因为他有这个方法.
    
    newSchool* oneGirl = [[newSchool alloc] init];  //定义一个新派的女学生,因为这个newSchool实现了那个协议,所以她就有那些能力.
    oneGirl.girlname = @"小花蝴蝶";
    
    //设置代理,把导演的后期制作代理设置成这个'小花蝴蝶',以后印海报那些事就交给小花蝴蝶干.
    /*
     我们在代码里面常见的那种写法
      XXX.delegate=self;
    或  
     
     XXX.delegate=yyy;
     与下面其实是一个意思.
     
     */
    
    oneDirector.backAssistant = oneGirl;    //把这个女孩指定为导演的那些干杂事的代理.
    
    [oneDirector introMyself];          //导演再次描述自己,backAssistant已经有人了.
    
    [oneDirector.backAssistant posterMake]; //导演可以让自己的backAssistant 去弄海报这事了.
    
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

运行时候注意看Xcode的日志. 希望对你有帮助.

协议/代理的使用场景

从上面的描述可以看到, 协议和代理基本是一起使用的,是为了降低复杂度,
即:把某些功能”聚合”到一个协议里面去, 然后请代理干活.
你基本可以理解成一种设计模式,或者是一种架构方法.

这种模式的常用做法,

  • 定义某一类的功能集合(协议),然后
  • 新的类实现协议里面的功能
  • 其他类,指定自己的代理是别人,让别人干功能集合里面的某些事情

示范工程在:
https://github.com/tangyongjin/Film

    原文作者:杂食
    原文地址: https://www.jianshu.com/p/06c791809ab4
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞