———————————————————————————————————————————

protocol(协议)



(1)引文:OC中的protocol和Java中的接口(interface)比较类似,Java中的接口(interface)就是一堆方法的声明(没有实现),而OC中的interface是一个类的头文件的声明,并不是真正意义上的接口,在OC中,接口是一个叫做 协议 的 protocol 来实现的。



和Java不同,protocol 可以声明一些必须实现的方法和一些选择实现的方法。(Java中如果要实现接口,就要必须实现接口中的所有方法,否则报错。         而protocol中声明的方法可以实现也可以不实现,这里其实默认也是全部都要实现的,只不过OC是弱语法语言,如果没有实现protocol中的方法,只会发出警告,而不会报错)



(2)OC中的协议(protocol):



①Protocol:就一个用途,用来声明一大堆的方法。(但是不能声明成员变量,也不能实现方法)

②只要某个类遵守了某个协议,就拥有了这个协议中的所有的  方法声明(实现还得自己去实现。如果是继承,则继承了父类的声明和实现,这和protocol是不同的)

③只要父类遵守了某个协议,那么子类也得遵守

④Protocol声明的方法可以让任何类去实现,Protocol就是协议

⑤OC不能继承多个类(遵守单继承原则),但是能够遵守多个协议。继承(:),遵守协议(< >)

⑥基协议:  <NSObject>  是基协议,是最根本最基本的协议,其中声明了很多最基本的方法。

⑦协议可以遵守协议,一个协议遵守了另一个协议,就可以拥有另一份协议中的方法声明。



(3)一般定义协议是在.h文件中,而谁采用这个协议就在谁的.m文件中实现方法。



①定义协议



@protocol 协议名称 <NSObject>

//方法声明列表

@end



注意:协议默认的要采纳NSObject的协议。



②采用协议



★★★采用协议的时候要引入协议的头文件,然后再让 类/协议 去遵守协议



★某个类遵守 某个协议 或者 某些协议,一个类可以遵守其他多个协议:



@interface 类名:父类 <协议名称1,协议名称2,协议名称3>

@end



★某个协议遵守 某个协议 或者 某些协议,一个协议可以遵守其他多个协议:(协议之间的继承关系)



@protocol 协议名称 <其他协议名称1,其他协议名称2,其他协议名称3>

@end



③实现协议中的方法



在类的.m文件中实现





接下来我们用一段代码来描述上述三个操作(①②③):



★main.m★



#import <Foundation/Foundation.h>

#import "Car.h"



int main(int argc, const char * argv[]) {

    @autoreleasepool {

        Car *car1=[[Car alloc]init];

        

        [car1 run];

        

        [car1 train];

    }

    return 0;

}



★runProtocol.h★



#import <Foundation/Foundation.h>



@protocol runProtocol <NSObject>

//runProtocol协议遵守NSObject(基协议)



-(void)run;

-(void)jump;

-(void)jump2;

@end



★toolProtocol.h★



#import <Foundation/Foundation.h>

#import "runProtocol.h"  //我们引入之间创建的协议runProtocol的头文件



//协议遵守其他协议

@protocol toolProtocol <NSObject,runProtocol>  //然后让toolProtocol协议去遵守NSObject和runProtocol两个协议(这里注意,NSObject是每个协议创建的时候都要遵守的)



-(void)plane;

-(void)train;

@end



★Car.h★



#import <Foundation/Foundation.h>



#import "toolProtocol.h"

//#import "runProtocol.h"  //因为我们让toolProtocol协议去遵守runProtocol协议,所以只导入toolProtocol协议的头文件即可

//我们要引入我们遵守的协议的头文件



//类遵守协议

@interface Car : NSObject <toolProtocol>  //引入头文件后才能第二步遵守协议。这里也是只遵守toolProtocol协议就行了,这相当于让Car类同时遵守了toolProtocol和runProtocol两个协议。



@end



★Car.m★



#import "Car.h"



@implementation Car

//第三步才是实现协议中的方法



-(void)run

{

    NSLog(@"run!");

}



-(void)jump

{

    NSLog(@"jump!");

}



-(void)jump2

{

    NSLog(@"jump2!");

}



-(void)plane

{

    NSLog(@"plane!");

}



-(void)train

{

    NSLog(@"train!");

}



@end



(4)如果父类遵守一个协议,那么他的子类也相应遵守这个协议。



(5)NSObject是一个基类,同时也有NSObject这个基协议。(这个在上面的代码中已经提到)

★而且,查看源码得知:基类也是遵守基协议的。

———————————————————————————————————————————

protocol中的@required和@optional



@required和@optional 是协议方法声明中的两个至关重要的关键字,他们的作用主要控制方法是否必须要实现!



@required —— 必须实现(编译器默认是@required,若不实现,会警告)

@option —— 可以选择实现



用途在于程序员之间的交流。OC是弱语法,一旦没有写方法实现,能提醒别人知道。警告一下但是不报错,别人用你的代码的时候可以很好的提示一下。

这段知识比较简单,我用截图给大家说明一下:

我们创建了一个foodProtocol的协议,里面有@required属性的方法和@optional属性的方法。

我们让Dog类遵守foodProtocol协议。

我们选择实现其中一个@required类型的方法(drink),而其他的两个方法不实现,然后我们发现了一个警告。

警告显示eat方法在foodProtocol中声明了但是没有实现,但是却没有提示bark方法,显然原因大家已经知道了。



而这就是@required 和 @optional 关键字的用法。





———————————————————————————————————————————

protocol类型限制



(1)使用id存储对象时,对象的类型限制



格式:id <协议名称> 变量名;



如: id <Myprotocol> obj1;



(2)对象创建时类型限制



格式:类名 <协议名称> *变量名



如:Person <houseHold> *p= [ [ Student alloc ] init ];



(3)对象关联关系下,对象的类型限制



如:

@property (nonatomic,strong) id<girlFriend> girlfriend;

//创建一个girl的成员变量,表示创建出来的Person的实例对象应该拥有一个女友,而且女友需要遵守girlFriend的协议





代码:



★girlFriend★



#import <Foundation/Foundation.h>



@protocol girlFriend <NSObject>

//girlFriend必须遵守的(会做饭洗衣)

@required

-(void)cook;

-(void)washClothes;



//允许girlFriend不遵守的(有国企工作的优先)

@optional

-(void)goodJob;

@end



★Person.h★



#import <Foundation/Foundation.h>

#import "girlFriend.h"



@interface Person : NSObject



//创建一个girl的成员变量,表示创建出来的Person的实例对象应该拥有一个女友,而且女友需要遵守girlFriend的协议

//增加限制id<girlFriend>

//表示,id存储的对象必须实现了girlFriend协议

//找的女朋友,必须会洗衣做饭

@property (nonatomic,strong) id<girlFriend> girlfriend;



@end



★Person.m★



#import "Person.h"



@implementation Person



@end



★Girl.h★



#import <Foundation/Foundation.h>

#import "girlFriend.h"



@interface Girl : NSObject <girlFriend> //这里写上Girl类遵守girlFriend协议



@end



★Girl.m★



#import "Girl.h"



@implementation Girl

-(void)cook

{

    NSLog(@"cook dinner~");

}

-(void)washClothes

{

    NSLog(@"wash clothes~");

}

@end



★mian.m★



#import <Foundation/Foundation.h>

#import "Person.h"

#import "Girl.h"

int main(int argc, const char * argv[]) {

    @autoreleasepool {

        Girl *girl1=[Girl new];

        

        Person *p1=[Person new];

        Person *p2=[Person new];

        

        p1.girlfriend=girl1;  //这里不会报错,因为girl1是Girl类型的变量,所以遵守girlFriend协议,可以赋值

        

        [p1.girlfriend cook];

        [p1.girlfriend washClothes];

p1.girlfriend=p2;   //这里会报错,因为p2是Person类型的,而Person并不遵守这个协议,所以无法赋值





//        [p1.girlfriend cook];  //随便用一个p2来赋给p1,做p1的女朋友是不行的



    }

    return 0;

}





———————————————————————————————————————————

protocol的代理模式引入



MVC(三层框架)



m - model



v - view



c - controller



★代理模式概念:

传入的对象,代替当前类完成了某个功能,称为代理模式



代理模式应用场合:



①当对象A发生了一些行为,想告知对象B(让对象B成为对象A的代理对象)



②对象B想监听对象A的一些行为(让对象B成为对象A的代理对象)



③当对象A无法处理某些行为的时候(让对象B成为对象A的代理对象)



★我们可以看出,在上面的三个场合中,B需要满足协议要求的,才能帮助/代替A干某些事情。这就建立了一个代理模式应用场合。当然满足代理模式应用的场合还有许多。



下面是一个这样的程序:baby有吃东西和睡觉的方法,如果baby睡觉或者是吃饭都要去让一个人来帮助他完成(在吃东西和睡觉方法中调用另外一个对象的方法),而保姆就是那个具备照顾baby要求的人选(遵守了协议)。现在我们要求一个老师去照顾baby,帮助baby去完成吃饭睡觉的工作,但老师是不遵守协议的,然后我们要让老师也遵循这个协议去照顾baby。



形容的实在太啰嗦了,原谅我的口才不是太好。



问题的关键先建立模型,将方法写好之后再考虑协议的问题。一步一步的添加上述要求。



代码:



//  babysitProtocol.h



#import <Foundation/Foundation.h>

@class Baby;

@protocol babysitProtocol <NSObject>

-(void)feedBaby:(Baby *)baby;

-(void)hongBabyToSleep:(Baby *)baby;

@end



//  Baby.h



@interface Baby : NSObject

@property (nonatomic) id <babysitProtocol> bm;

@property (nonatomic) float weight;

@property (nonatomic) float height;



-(void)wantEat;

-(void)wantSleep;

@end



//  Baby.m



#import "Baby.h"

#import "Baomu.h"

@implementation Baby

-(void)wantEat

{

    NSLog(@"baby want eat!");

    [self.bm feedBaby:self];

}

-(void)wantSleep

{

    NSLog(@"baby want sleep!");

    [self.bm hongBabyToSleep:self];

}

@end



//  Baomu.h



#import <Foundation/Foundation.h>

#import "babysitProtocol.h"

@class Baby;

@interface Baomu : NSObject <babysitProtocol>

-(void)feedBaby:(Baby *)baby;

-(void)hongBabyToSleep:(Baby *)baby;

@end



//  Baomu.m



#import "Baomu.h"

#import "Baby.h"

@implementation Baomu

-(void)feedBaby:(Baby *)baby

{

    NSLog(@"Baomu feed baby!");

    baby.weight+=1;

}

-(void)hongBabyToSleep:(Baby *)baby

{

    NSLog(@"Baomu baby sleep!");

    baby.height+=0.5;

}

@end



//  Teacher.h



#import <Foundation/Foundation.h>

#import "babysitProtocol.h"



@interface Teacher : NSObject <babysitProtocol>



@end



//  Teacher.m



#import "Teacher.h"

#import "Baby.h"

@implementation Teacher

-(void)feedBaby:(Baby *)baby

{

    NSLog(@"Teacher feed baby!");

    baby.weight+=1;

}

-(void)hongBabyToSleep:(Baby *)baby

{

    NSLog(@"Teacher baby sleep!");

    baby.height+=0.5;

}

@end



//  main.m



//一般而言什么 类/协议 遵守另外的协议,后面的协议尖括号是紧跟着 类/协议 去写的,不要将协议的位置写错

#import <Foundation/Foundation.h>

#import "Baby.h"

#import "Baomu.h"

#import "Teacher.h"

int main(int argc, const char * argv[]) {

    @autoreleasepool {

        Baby *baby1=[Baby new];

        Baomu *baomu1=[Baomu new];

        

        baby1.bm=baomu1;

        

        [baby1 wantEat];

        //以上四句话是非常合理的,因为baomu1是Baomu的实例对象,baomu1遵守babysitProtocol协议,所以说baby1可以拥有他,并且调用。

        

        //但是如果写下面两句显然就有错了,因为我们并没有让Teacher类去遵守babysitProtocol这个协议。

//        Teacher *teacher1=[Teacher new];

//        baby1.bm=teacher1;

        //那么我们应该怎么改进呢?

//        显然,我们应该让Teacher类也遵守babysitProtocol协议,然后将Baby中的bm属性设置为id类型,这样Teacher也能feedBaby和hongBabyToSleep了~

//        具体代码在各个文件中已经改变~

        

        Baby *baby2=[Baby new];

        Teacher *teacher2=[Teacher new];

        

        baby2.bm=teacher2;

        

        [baby2 wantSleep];

    }

    return 0;

}





———————————————————————————————————————————

版权声明:本文为博主原创文章,未经博主允许不得转载。

Objective-C 【protocol-协议 的了解使用】的更多相关文章

  1. Objective中的协议(Protocol)

    Objective中的协议(Protocol) 作用: 专门用来声明一大堆方法. (不能声明属性,也不能实现方法,只能用来写方法的声明). 只要某个类遵守了这个协议.就相当于拥有这个协议中的所有的方法 ...

  2. Objective-C( protocol协议)

    protocol 协议 protocol:用来声明方法 1.协议的定义 @protocol 协议名称 <NSObject> // 方法声明列表.... @end 2.如何遵守协议 1> ...

  3. ISO 基础之 (十三) protocol 协议

    一 简绍 protocol,简单来说就是一系列不属于任何类的方法列表,其中声明的方法可以被任何类实现.这种模式一般称为代理(delegation)模式.通过Protocol定义各种行为,在不同的场景采 ...

  4. 【转】iOS开发-Protocol协议及委托代理(Delegate)传值

    原文网址:http://www.cnblogs.com/GarveyCalvin/p/4210828.html 前言:因为Object-C是不支持多继承的,所以很多时候都是用Protocol(协议)来 ...

  5. protocol(协议)

      可以用来声明一大堆方法(不能声明成员变量) 只要某个类遵守了这个协议,就相当于拥有这个协议中的所有方法声明 只要父类遵守了某个协议,就相当于子类也遵守了   //定义一个名叫MyProtocol的 ...

  6. OC语法10——@protocol协议,

    参考资料:博客 @protocol,协议: OC中protocol的含义和Java中接口的含义是一样的,它们的作用都是为了定义一组方法规范. 实现此协议的类里的方法,必须按照此协议里定义的方法规范来. ...

  7. iOS开发-Protocol协议及委托代理(Delegate)传值

    前言:因为Object-C是不支持多继承的,所以很多时候都是用Protocol(协议)来代替.Protocol(协议)只能定义公用的一套接口,但不能提供具体的实现方法.也就是说,它只告诉你要做什么,但 ...

  8. Tabular DataStream protocol 协议

    Tabular DataStream protocol 协议 Freetds 创建过程 https://wenku.baidu.com/view/2076cbfaaef8941ea76e0576.ht ...

  9. DHCP (Dynamic Host Configuration Protocol )协议的探讨与分析

    DHCP (Dynamic Host Configuration Protocol )协议的探讨与分析 问题背景 最近在工作中遇到了连接外网的交换机在IPv6地址条件下从运营商自动获取的DNS地址与本 ...

  10. SIP (Session Initiation Protocol) 协议

    Session Initiation Protocol 介绍 SIP是VoIP技术最常使用的协议,它是一种应用程序层协议,可与其他应用程序层协议配合使用,以控制Internet上的多媒体通信会话. V ...

随机推荐

  1. Java多线程:线程死锁

    发生死锁的原因通常是两个对象的锁相互等待造成的. 以下用一个实例来构造这样的情况: package basic.e_deadlock; import org.apache.log4j.Logger; ...

  2. js 获取cookie

      <!DOCTYPE html>   <html xmlns="http://www.w3.org/1999/xhtml">       <head ...

  3. 【JavaScript】关于JS中的constructor与prototype

    最初对js中 object.constructor 的认识: 在学习JS的面向对象过程中,一直对constructor与prototype感到很迷惑,看了一些博客与书籍,觉得自己弄明白了,现在记录如下 ...

  4. 跟大家分享下今天所学到的PHP,虽然很基础,但是感觉也很重要

    PHP:Hypertext PreProcessor(超文本预处理语言) PHP是一种服务器端语言(server-side language),服务器只发送脚本的输出,通常是HTML,PHP也可以用于 ...

  5. Bash脚本编程基础

    为实现某个任务,将许多命令组合后,写入一个可执行的文本文件的方法,称为Shell脚本编程. 按照应用的Shell环境不同,可以将Shell脚本分为多种类型.其中最常见的是应用于Bash和Tcsh的脚本 ...

  6. js本地图片预览代码兼容所有浏览器

    html代码 <div id="divPreview" style="width: 160px; height: 170px"><img id ...

  7. oracle视图总结

    视图简介: 视图是基于一个表或多个表或视图的逻辑表,本身不包含数据,通过它可以对表里面的数据进行查询和修改.视图基于的表称为基表.视图是存储在数据字典里的一条select语句. 通过创建视图可以提取数 ...

  8. C#求所有可能的排列组合

    static System.Collections.Specialized.StringCollection MakeStrings(string[] characters, int finalStr ...

  9. solr查询在solrconfig.xml中的配置

    <requestHandler name="/select" class="solr.SearchHandler"> <lst name=&q ...

  10. PostgreSQL异步客户端(并模拟redis 数据结构)

    以前为了不在游戏逻辑(对象属性)变更时修改数据库,就弄了个varchar字段来表示json,由服务器逻辑(读取到内存)去操作它. 但这对运维相当不友好,也不能做一些此Json数据里查询. 所以后面就用 ...