zoukankan      html  css  js  c++  java
  • Objective-C 【protocol-协议 的了解使用】

    ———————————————————————————————————————————
    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;
    }


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

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

  • 相关阅读:
    Ubuntu下建立Android开发环境
    c#值类型和引用类型
    Jude Begin
    Eclipse C/C++ development environment creation
    C# var usage from MSDN
    SubSonic应用_Collection
    C#2.0中委托与匿名委托引
    sql语句的执行步骤——zhuan
    图˙谱˙马尔科夫过程·聚类结构 (转载,原始出处不详)
    Hadoop集群新增节点实现方案
  • 原文地址:https://www.cnblogs.com/wzy294250051/p/4787876.html
Copyright © 2011-2022 走看看