个性化阅读
专注于IT技术分析

Objective-C协议(Protocol)用法解析 – Objective-C开发教程

上一章Objective-C开发教程请查看:Objective-C扩展(Extension)用法解析

这一章我们讨论Objective-C中的协议,协议是个什么东西呢?在说协议之前我们先总结一下之前讨论的继承、类别和扩展:

  • OC中的继承和一般OOP中的继承类似,子类继承父类的属性和方法,属于对类的纵向扩展,但是同时又具备多态功用,也就是也支持横向扩展。
  • 类别也类似于继承,但是类别更像是向原有类嵌入一系列功能,目标类有没有源码都可以使用。
  • 扩展是一个匿名类名,既然是匿名,那就是即时用的了,用完即止。只能在所用的源文件中使用,在其它地方它不起作用。

类别可用于当API接口不可控的时候,对一些类进行扩展;扩展可用于为类设计私有方法的时候,针对的是自定义类,原有定义类和扩展声明的方法,都是一同在implementation中实现的(参考iOS项目默认生成的controller),特别要注意扩展中增加的任何方法和属性在外部都是不能用的(但是可以通过公有方法使用或调用)。

那么和继承、类别和扩展相比,协议是个什么东西呢?其实也是一个类,但是就像上面说明的,继承提供横向扩展(一般来说横向扩展由接口提供),但是使用类继承进行横向扩展是比较麻烦的。协议就相当于Java中的接口了,其功能和类多态类似,但是会更加简洁。

为什么称为协议呢?通俗的说就是约定,更符合编程的说就是协议,比如HTTP协议,规定web数据的传输规范,这个协议是官方标准规定的,具体内容由提供商实现。或者直接理解为接口也是没问题的。

协议的定义

协议的定义和类和类别的定义类似,以关键字@protocol开始,以@end结束,中间是方法声明。方法声明有两种:@required和@optional,前者表示实现者必须实现的方法,后者表示实现是可选的,可实现可不实现,如果不使用这两个关键字,则默认为@required必须实现的。

协议的定义语法如下:

@protocol ProtocolName <OtherProtocol1, OtherProtocol2>
@required
// 必须实现的属性/方法列表
@optional
// 可选实现的属性/方法列表
@end

注意,协议中声明一般都是方法,但是也可以声明属性。推荐的写法是:必须实现的方法或必须使用的属性可以不用@required说明,只有遇到可选的属性和方法时再使用@optional。

协议也可以继承另一个协议,另外继承的协议在协议名后面的尖括号中添加,多个协议使用逗号隔开。

下面是声明协议的一个具体例子:

#import <Foundation/Foundation.h>

@protocol MyProtocol

// 必须实现的属性和方法
@property(nonatomic, copy)NSString *name;
-(void)run;

// 必须实现
@required
@property(nonatomic, assign)int size;
-(void)print;

// 可选实现
@optional
@property(nonatomic, copy)NSArray *desc;
-(void)printDesc;

@end

实现协议

实现协议在OC中又称为遵循协议,在iOS开发中实现者又称为代理Delegate。实现协议就是新建一个类,让这个类实现指定的协议,协议的名称在尖括号后面添加,多个协议使用逗号隔开,但是别忘了新建的类还是要继承一个类的。

实现协议的语法如下:

@interface myClass  <myProtocol>
@interface myClass :NSObject<myProtocol>
@interface myClass :NSObject<myProtocol, NSCoding>

其它就是在@implementation中实现即可,建议还是按照标准的方式,该实现还是实现,可选实现留空也没问题,不要搞的有的没的。

下面是实现协议的具体例子:

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

@interface MyProtoclImp : NSObject <MyProtocol>

@end

以下是详细的实现细节,下面的方式不是标准的编程写法,仅供示范:

//
//  MyProtoclImp.m
//  basic
//
//  Created by cococ on 2020/1/4.
//  Copyright © 2020年 cococ. All rights reserved.
//

#import "MyProtoclImp.h"

@implementation MyProtoclImp
@synthesize name = _name;
@synthesize size = _size;
@synthesize desc = _desc;

-(void)run{
    _name = @"Running";
    NSLog(@"name: %@", _name);
}

-(void)print{
    _size = 13;
    NSLog(@"size: %d", _size);
}

-(void)printDesc{
    NSArray *array = [[NSArray alloc]initWithObjects:@5, @2, @8, nil];
    _desc = array;
    for (id obj in array) {
        NSLog(@"%@", obj);
    }
}

@end

要注意的是,在协议中声明的属性,一般在实现文件中下划线属性是不可用的,不会自动合成属性下划线,要有下划线属性,需要手动使用@synthesize指定合成的属性,否则不手动指定也是可以的,直接使用无下划线的属性即可。

协议的使用

和其它OOP语言不同,OC不能使用协议的指针指向实现者的实例,有两种方式可以定义一个实现了协议的对象:一种和普通的类对象创建一样,如下:

MyProtocolImp<MyProtocol> *imp = [MyProtocolImp new];

尖括号中是实现的协议名称,表示创建的对象是实现了该协议的,而且按照规范只能调用协议中声明的方法和属性,不指定协议名称也是可以的,但是还是建议指定为好。

另一种是使用万能指针id,务必注意id是一个指针,相当于C中的void*,这个在iOS开发中使用代理Delegate尤为常见。那么使用id指针也就变成了以下的形式:

id<MyProtocol> *imp = [MyProtocolImp new];

下面是协议的测试用例:

void testProtocol(void){
    // MyProtoclImp<MyProtocol> *imp = [MyProtoclImp new];
    id<MyProtocol> imp = [MyProtoclImp new];
    [imp run];
    [imp print];
    [imp printDesc];
}

int main(int argc, const char * argv[]) {
    testProtocol();
    return 0;
}

协议小结

协议相当于接口,其中可以声明属性和方法,但是要注意下滑属性需要手动使用@synthesize关键字指定。协议中的属性和方法分为@required和@optional两种,不使用这两个关键字说明的默认为@required。

在使用协议的建议使用尖括号<>指定类所实现的协议,这样可以让代码更为清晰。在Java中类似协议的称为接口,所以一般接口名称后面为Interface,实现类后面为Imp。在OC开发中,协议的名称可以以Protocol结尾,实现类以Delegate结尾,虽然无强制要求,但是最好有一个好的约定。

对于协议的应用场景,特别说一下,虽然协议相当于接口,但是不能使用协议的指针指向实例对象,所以它不能用于多态,不能用于多态!

协议的一个常见的应用场景就是提供给程序员自定义功能实现,也就是在已经实现了的一个功能系统A里面,额外地使用一个协议,当使用A的时候,程序员就可以自定义实现这个协议,达到自定义功能的目的。例如UIKit中的UITableViewDelegate和UITableViewDataSource,其它如实现函数回调也可以使用协议。

赞(0)
未经允许不得转载:srcmini » Objective-C协议(Protocol)用法解析 – Objective-C开发教程

评论 抢沙发

评论前必须登录!