【OC】协议与委托

规范、协议与接口

  类是一种具体实现体,而协议则是定义了一种规范,定义了某一批类所需要遵守的规范。
  协议不提供任何实现,它体现的是规范和实现分离的设计哲学。
  让规范和实现分离正是协议的好处,是一种松耦合的设计。

tips:OC中协议的作用就相当于其他语言中接口的作用。

  协议定义的是多个类共同的公共行为规范,协议里通常定义的是一组公用方法,但不会为这些方法提供实现,方法的实现则交给类去实现。

使用类别实现非正式协议

  在上一篇博客中,我们提到过,使用类别实现非正式协议是类别的作用之一
  当某个类实现NSObject的该类别时,就需要实现该类别下所有方法,这种基于NSObject定义的类别即可认为是非正式协议。

下面是使用类别实现非正式协议的代码示例:

#import <Foundation/Foundation.h>
 
NS_ASSUME_NONNULL_BEGIN

//以NSObject为基础定义EaTable类别
@interface NSObject (EaTable) 
- (void) taste;
 
@end
 
NS_ASSUME_NONNULL_END

上面我们给NSObject提供了一个Eatable类别,该类别可以看作一个非正式协议,相当于定义了一个规范,接下来所有继承NSObject类的子类都会自动继承Eatable中的taste:方法,我们可以根据我们的子类是否需要来决定是否要实现这个方法(一般都会实现)。

下来为NSObject(Eatable)派生一个子类。

接口部分:

#import <Foundation/Foundation.h>
#import "NSObject+EaTable.h"

NS_ASSUME_NONNULL_BEGIN

//定义类的接口部分
@interface FKApple : NSObject

@end

NS_ASSUME_NONNULL_END

这个子类虽然只是一个空类,但并不影响它的功能,因为它继承了NSObject(EaTable),只要在FKApple类的实现部分实现taste方法即可。

实现部分:

#import "FKApple.h"

//为FKApple提供实现部分
@implementation FKApple
- (void) taste {
    NSLog(@"我讨厌吃苹果");
}
@end

在上面代码中可以看出来,我们在FKApple的实现部分对taste方法进行了实现,这就相当于FKApple类遵守了Eatable协议,然后就可以把FKApple类当作Eatable对象来调用。

主函数:

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

int main(int argc, const char * argv[]) 
{
    @autoreleasepool {
        FKApple* apple = [[FKApple alloc] init];
        [apple taste];
    }
    return 0;
}

运行结果:

在这里插入图片描述

正式协议的定义

  定义正式协议的时候,不再使用@interface和@implementation关键字了,而是使用@protocol关键字,定义正式协议的语法如下:

@protocol 协议名 <父协议1, 父协议2> 
{
    零到多个方法定义......
}

对于上述语法,做出以下详细说明:

  1. 协议名应与类名采取相同的命名规则。
  2. 一个协议可以有多个直接父协议,但协议只能继承协议,不能继承类。
  3. 协议中定义的方法只有方法签名,没有方法实现。
  4. 协议中包含的方法可以是类方法,也可以是实例方法。

tips:因为协议定义的是多个类共同的公共行为规范,所以,协议里所有的方法都是公开的访问权限

下面对定义正式协议的相关内容进行代码实现:

#import <Foundation/Foundation.h>
 
NS_ASSUME_NONNULL_BEGIN
 
//定义协议
@protocol FKOutput
//定义协议的方法
- (void)output;
- (void)addData(String msg);
 
@end
 
NS_ASSUME_NONNULL_END

上面定义了一个FKOutput协议,这个协议定义了两个方法:添加数据和输出数据。这就定义了FKOutput协议的规范:只要某个类能添加数据,并可以将数据输出,那它就是一个输出设备。

#import <Foundation/Foundation.h>
 
NS_ASSUME_NONNULL_BEGIN
 
//定义协议
@protocol FKProoductable
//定义协议方法
- (NSData *)getProductTime;
 
@end
 
NS_ASSUME_NONNULL_END

上面定义了一个FKProductable协议,该协议代表了所有的产品都需要遵守的规范。其中定义了一个getProductTime方法,用来返回产品的生产时间。

#import <Foundation/Foundation.h>
#import "FKOutput.h"
#import "FKProductable.h"
 
NS_ASSUME_NONNULL_BEGIN
 
//定义协议,继承了FKutput、FKProductable两个协议
@protocol FKPrintable <FKOutput, FKProductable>
//定义协议的方法
- (NSString*) printColor;
 
@end
 
NS_ASSUME_NONNULL_END

上面定义了一个打印机协议,该协议同时继承以上两个协议。

tips:协议的继承和类的继承不一样,协议完全支持多继承,即一个协议可以有多个直接的父协议。和类继承相似,子协议继承某个父协议,将会获得父协议中的所有方法。一个协议继承多个父协议时,多个父协议排在<>中间,多个协议口见以(,)隔开

遵守(实现)协议

  在类定义的接口部分可以指定该类继承的父类,以及遵守的协议,一个类可以同时遵守多个协议,语法如下:

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

在这里插入图片描述
如果程序需要使用协议来定义变量,有如下两种语法:

 - NSObject<协议1,协议2...>* 变量;
 - id<协议1,协议2...>* 变量;

这两个编译类型仅仅只是所遵循的协议类型,因此只能调用该协议中所定义的方法。

正式协议与非正式协议的差异

  • 非正式协议通过为NSObject创建类别来实现,而正式协议直接使用@protocol创建;
  • 遵守非正式协议通过继承带特定类别的NSObject来实现,而遵守正式协议则有专门的OC语法来实现;
  • 遵守非正式协议不要求实现协议中定义的所有方法;而遵守正式协议则必须实现协议中定义的所有方法。

  为了弥补遵守正式协议必须实现协议的所有方法造成灵活性不足,在OC还有两个关键字:

  1. @optional:位于该关键字只后、@required或@end之前声明的方法是可选的实现类可选择是否实现这些方法
  2. @required:位于该关键字之后、@optional或@end之前声明的方法是必需的实现类必需实现这些方法

通过在正式协议中使用以上两个关键字,正式协议完全可以代替非正式协议的功能。

协议与委托

  协议体现的是一种规范,定义协议的类可以把协议定义的方法委托给实现协议的类,这样可以让类定义具有更好的通用性,因为具体的动作将由该协议的实现类去完成。无论是基于Mac的Cococa应用开发还是iOS开发,各种应用程序大量依赖委托这个概念。

  • 17
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值