[0005]iOS基础知识ios移动开发

iOS编程之协议(procotol)

2016-03-29  本文已影响5017人  DeanYan

需要了解ios协议, 首先看一个代码示例:

    #import <Foundation/Foundation.h>
    /**流氓协议*/
    @protocol BadManDelegate <NSObject>
    @required // 必须实现的方法
    /**吃*/
    - (void) eat;
    /**骗*/
    - (void) lie;
    @optional // 可选实现的方法
    - (void) drink;
    @end
    /**君子协议*/
    @protocol GentlemanDelegate <NSObject>
    // 协议内容只能有方法不能有属性
    // 协议方法
    /**动口不动手*/
    - (void) fight;
    /**爱钱取之有道*/
    - (void) loveMoney;
    @end
    #import <Foundation/Foundation.h>
    #import "BadManDelegate.h"
    #import "GentlemanDelegate.h"

    // 遵守协议的类就是代理类; 如果一个类遵守了协议, 就要去实现协议方法;
    /**遵守流氓协议的代理*/
    // 一个类可以同时遵守多个协议, 在一个<>中多个协议名用逗号隔开
    @interface YHPerson : NSObject <BadManDelegate, GentlemanDelegate>

    @end

    @interface YHStudent : NSObject <BadManDelegate>

    - (void) study;

    @end
    #import "YHPerson.h"

    @implementation YHPerson
    - (void) eat {
        NSLog(@"正在吃霸王餐!!");
    }
    - (void) lie {
        NSLog(@"在撒谎!!");
    }
    - (void) fight {
        NSLog(@"动口不动手!!");
    }
    - (void) loveMoney {
        NSLog(@"爱钱取之有道!!");
    }
    @end
    @implementation YHStudent
    // 实现学生相关的方法
    - (void) study {
        NSLog(@"Good Good Study, Day Day Up.");
    }
    // 实现流氓协议的方法
    - (void) eat {
        NSLog(@"吃完带抢");
    }
    - (void) lie {
        NSLog(@"处处留情!!");
    }
    @end

这里说明几点:

  1. 一个协议可以扩展自另一个协议,例如上面BadManDelegate就扩展自NSObject,如果需要扩展多个协议中间使用逗号分隔;
  2. 和其他高级语言中接口不同的是协议中定义的方法不一定是必须实现的,我们可以通过关键字进行@required和@optional进行设置,如果不设置则默认是@required(注意ObjC是弱语法,即使不实现必选方法编译运行也不会报错);
  3. 协议通过<>进行实现,一个类可以同时实现多个协议,中间通过逗号分隔;
  4. 协议的实现只能在类的声明上,不能放到类的实现上(也就是说必须写成@interface YHPerson:NSObject <AnimalDelegate>而不能写成@implementation YHPerson<AnimalDelegate>);
  5. 协议中不能定义属性、成员变量等,只能定义方法;

由上例可以看出,iOS中的协议其实和生活中的协议基本上是一样的,比如生活中签订的就业协议、保密协议以及一些合同等等。而协议本身就是一系列的条款及规定(在OC中的协议主要看的是甲方对乙方指定的规定)。

使用协议代理解决问题: (如果一个对象想要做一件事情(完成一个功能), 但是自己做不到, 需要一个可以做到的对象来帮他完成, 考虑使用协议代理)
  场景: 老板想要做一个iOS项目
  分析: 老板想做iOS项目, 但是自己不会做, 找一个会iOS开发的人来帮他做

    #import <Foundation/Foundation.h>
    //2.协议
    /**声明协议*/
    @protocol StaffDelegate <NSObject>
    /**会IOS开发(做开发)*/
    - (void) codeIOS;
    @end
    // 1. 委托
    // 委托需要一个遵守协议的对象来帮他做事情 (委托需要一个代理)
    /**委托类(制定协议)*/
    @interface YHBoss : NSObject
    // 任何遵守协议的类创建的对象都可以作为老板的代理
    // 注意: delegate要用weak修饰(防止循环引用造成对象不能销毁)
    /**代理*/
    @property (nonatomic, weak) id <StaffDelegate> delegate;
    // 告诉代理何时去做事情
    /**告诉代理*/
    - (void) askStaffWorking;
    @end
    #import "YHBoss.h"

    @implementation YHBoss
    //委托告诉代理做事
    - (void) askStaffWorking {
        NSLog(@"老板告诉员工开工");
        // 代理开始做事情
        [self.delegate codeIOS];
    }
    @end
    #import <Foundation/Foundation.h>
    #import "YHBoss.h"

    // 3.代理(遵守协议, 实现协议方法)
    /**代理*/
    @interface YHPerson : NSObject <StaffDelegate>
    @end
    #import "YHPerson.h"
    #import "YHBoss.h"

    @implementation YHPerson
    // 判断一个对象是否实现了某个方法
    // (这里判断self.delegate是否实现了buyPhone方法)
    if ([self.delegate respondsToSelector:@selector(codeIOS)]) {
        // 代理开始做事情
        [self.delegate codeIOS];
    }
    @end
    #import <Foundation/Foundation.h>
    #import "YHPerson.h"

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            // 1.首先需要一个boss
            YHBoss *boss = [[YHBoss alloc] init];
            // 2.需要一个员工
            YHPerson *person = [[YHPerson alloc] init];
            // 3.让员工成为老板的代理
            boss.delegate = person;
            // 4.老板喊开工
            [boss askStaffWorking];
        }
        return 0;
    }
  1. id可以表示任何一个ObjC对象类型,类型后面的”<协议名>“用于约束作为这个属性的对象必须实现该协议(注意:使用id定义的对象类型不需要加“*”);
  2. YHPerson作为事件触发者,它实现了YHBoss代理(在ObjC中没有命名空间和包的概念,通常通过前缀进行类的划分,“YH”是我们自定义的前缀);
  3. 在.h文件中如果使用了另一个文件的类或协议我们可以通过@class或者@protocol进行声明,而不必导入这个文件,这样可以提高编译效率(注意有些情况必须使用@class或@protocol),但是在.m文件中则必须导入对应的类声明文件或协议文件(如果不导入虽然语法检查可以通过但是编译链接会报错);
  4. 使用respondsToSelector方法可以判断一个对象是否实现了某个方法(如果方法后面需要参数,需要注意方法名不是”codeIOS”而是“codeIOS:”,冒号也是方法名的一部分);

反向传值###

    #import <Foundation/Foundation.h>

    @protocol GreenInterfaceDelegate <NSObject>
    // 让协议方法带参传值
    /**传递的值*/
    - (void) showAppointValue:(NSString *) value;
    @end
    /**绿色界面*/
    @interface YHGreenView : NSObject
    /**需要的代理*/
    @property (nonatomic, weak) id <GreenInterfaceDelegate> delegate;
    /**传递需要显示的数据*/
    - (void) deliverValue:(NSString *) value;
    @end
    #import "YHGreenView.h"

    @implementation YHGreenView
    - (void) deliverValue:(NSString *) value {
        if ([self.delegate respondsToSelector:@selector(showAppointValue:)]) {
            [self.delegate showAppointValue:value];
        }
        else {
            NSLog(@"无法传值");
        }
    }
    @end
    #import <Foundation/Foundation.h>
    #import "YHGreenView.h"

    // 遵守协议, 实现协议方法
    /**黄色界面*/
    @interface YHYellowView : NSObject <GreenInterfaceDelegate>
    @end
    #import "YHYellowView.h"

    @implementation YHYellowView
    // 实现协议方法, 打印指定内容
    - (void) showAppointValue:(NSString *) value {
        printf("显示: %s", [value UTF8String]);
    }
    @end
    #import <Foundation/Foundation.h>
    #import "YHYellowView.h"

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            // 绿色界面委托
            YHGreenView *GreenView = [[YHGreenView alloc] init];
            // 黄色界面代理
            YHYellowView *YellowView = [[YHYellowView alloc] init];
            //将黄色界面设置为绿色界面的代理
            GreenView.delegate = YellowView;
            // 显示输入的内容
            printf("输入要显示的值:");
            char a[100];
            fgets(a, 101, stdin);
            // 传值
            [GreenView deliverValue:[NSString stringWithUTF8String:]];
        }
        return 0;
    }

回调###

- 协议代理回调作用: 通过协议方法的返回值, 将数据从代理传给委托
场景: 显示类想要得到从网上下载的数据
分析: 显示类不能去下载数据(不是因为没能力, 而是不想去做), 需要一个下载类去下载数据, 然后把数据给显示类
三要素
委托: 显示类(想要下载数据)
协议: 下载数据
代理: 下载类
    #import <Foundation/Foundation.h>

    @protocol downloadDelegate <NSObject>
    /**下载指定路径下的数据*/
    - (NSData *) downloadDataWithURL:(NSString *) urlStr;
    @end
    // 1. 委托
    /**委托*/
    @interface YHShow : NSObject
    /**代理对象*/
    @property (nonatomic, weak) id <downloadDelegate> delegate;
    /**要求代理下载数据*/
    - (void) needShow;
    @end
    #import "YHShow.h"

    @implementation YHShow
    - (void) needShow {
        if ([self.delegate respondsToSelector:@selector(downloadDataWithURL:)]) {
            NSData *data = [self.delegate downloadDataWithURL:@"http://blog.csdn.net/jingling/article/details/47753189"];
            NSLog(@"显示下载的数据%@", data);
        }
    }
    @end
    #import <Foundation/Foundation.h>
    #import "YHShow.h"

    /**代理*/
    @interface YHDownload : NSObject <downloadDelegate>
    @end
    #import "YHDownload.h"

    @implementation YHDownload
    - (NSData *) downloadDataWithURL:(NSString *) urlStr {
        // 获取指定网络路径中的数据
        // 创建统一资源定位符对象
        NSURL *url = [NSURL URLWithString:urlStr];
        NSData *data = [NSData dataWithContentsOfURL:url];
        return data;
    }
    @end
    #import <Foundation/Foundation.h>
    #import "YHDownload.h"

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            // 1.创建一个显示对象
            YHShow *show = [[YHShow alloc] init];
            // 2.创建一个下载对象
            YHDownload *download = [[YHDownload alloc] init];
            // 3.设置代理
            show.delegate = download;
            // 4.开始下载
            [show needShow];
        }
        return 0;
    }
上一篇下一篇

猜你喜欢

热点阅读