Objective-C的category与protocol

下面带来比较复杂但是重要的概念,协议。但是说协议之前,还有需要做一下铺垫,先来介绍介绍分类与类扩展。

1、分类(类别)

分类在有的资料中又叫类别。但是我认为分类可能更合适一点。
有时候我们会在.h文件中声明很多接口,于是就会有一个很大的很长的实现文件.m。虽然类的使用者不在乎实现的细节,但是对于想知道实现的人来说,这样的文件,一打开就没有阅读的欲望了。不仅仅是这样,对于维护代码的人,也是一种折磨。
于是有了分类,分类就是按照逻辑,将类划分为几个分区,每个分区对应一个.h和.m,这样对于开发和调试,还有阅读都很好。(即使分区了,每一个类页游自己的主实现文件)
先来以一个例子进行描述吧。首先建立一个人类(实现忽略)。

//.h
@interface People : NSObject
@property(nonatomic, copy)NSString* name_;
@property(nonatomic, assign)NSInteger age_;

-(id)initWithName:(NSString*)name withAge:(NSInteger)age;
//后续说到这个方法
-(void)Print;
@end

然后根据身份创建学生分类。

//.h
@interface People(Student)
-(void)showIAmStudent;
-(void)Print;
@end

//.m
@implementation People(Student)
-(void)showIAmStudent
{
    NSLog(@"我是一名%zd岁的学生,%@",self.age_, self.name_);
}
-(void)Print
{
    [self showIAmStudent];
}
@end

在使用的时候,还是创建原本的人类,只是为人类添加了一个方法而已。

People* person = [[People alloc]initWithName:@"小明" withAge:10];
[person showIAmStudent];//我是一名10岁的学生,小明

于是得出使用方法。

.h文件中
@interface(分类名)
/*TODO
声明要添加的方法
*/
@end.m文件中
@implementation(分类名)
/*TODO
实现在.h文件中添加的方法
*/
@end

当然也可以为不知道源码的类添加一些方法,这些都是可以的。但是这样需要注意,分类中的方法的优先级是大于主实现文件中方法的优先级,意思就是如果你在一个类的分类中添加的方法与原本类中的一个方法重名了,那么会将原来的那个方法覆盖点。因此在为NS系类中添加方法时要格外注意。

下面还是举一个例子。在上述的例子中有一个Print,我在分类中也进行了声明和实现,于是进行调用。

[person Print];//我是一名10岁的学生,小明

//编译器还会给如下的警告
//Category is implementing a method which will also be implemented by its primary class
//Category正在实现一个方法,该方法也将由其主类实现

因此在为第三方类中添加分类或者方法时需要添加自己特有的前缀。
在分类中还不能添加成员变量,如果尝试添加,会有如下错误:

Instance variables may not be placed in categories
实例变量不能放在类别中

如果进行添加属性的操作,也仅仅是声明了属性,setter和getter,并没有进行实现。但是自己可以凭借一些手段进行实现。但是官方都不让声明,所以这里我也没有详细去深究,感兴趣的同学可以尝试。

2、类扩展

在分类中添加不了成员变量,但是可以在累扩展中添加。类扩展通常是添加在实现文件.m中的。并且在类扩展中的成员都是私有的,当然如果有同学知道在implementation中的{}的定义的成员也是私有,那么可能有疑问,没有类扩展,也可以实现这个效果,为什么要类扩展。个人认识在实现块implementation中,只要在意实现就好,声明放在其他的地方。

@interface 类名()
{}
@end

注意:类扩展要放在实现块的前面,类扩展中的声明都是私有的

3、协议

协议分为正式协议和非正式协议,非正式协议已经介绍完了,没错,就是上述的分类和类扩展。如下是苹果官方文档的介绍:

Formal and Informal Protocols
There are two varieties of protocol, formal and informal:
A formal protocol declares a list of methods that client classes are expected to implement. Formal protocols have their own declaration, adoption, and type-checking syntax. You can designate methods whose implementation is required or optional with the @required and @optional keywords. Subclasses inherit formal protocols adopted by their ancestors. A formal protocol can also adopt other protocols.
Formal protocols are an extension to the Objective-C language.
An informal protocol is a category on NSObject, which implicitly makes almost all objects adopters of the protocol. (A category is a language feature that enables you to add methods to a class without subclassing it.) Implementation of the methods in an informal protocol is optional. Before invoking a method, the calling object checks to see whether the target object implements it. Until optional protocol methods were introduced in Objective-C 2.0, informal protocols were essential to the way Foundation and AppKit classes implemented delegation.

下面介绍正式协议。从文档中可以知道,一个正式的协议声明了一个方法列表,这些方法是客户机类要实现的。正式协议有自己的声明、采用和类型检查语法。您可以使用@required和@optional关键字指定其实现是必需的或可选的方法。子类继承其祖先采用的形式化协议。因此协议可以理解为一个方法的标准,只要某个类遵守这个协议,那么就必须要实现@required中的方法,而@optional中的方法,可选的实现。
语法如下:

@protocol 协议名
/*TODO
@required//这是遵守协议的类必须实现的方法列表
方法列表
@optional/这是可选实现的方法列表
方法列表
*/
@end


@interface 类名 : 继承的类<协议名>

@end

@implementation 类名
/*TODO
除了自身声明的方法,还需要实现协议中@required列表中的方法。
*/
@end

下面举一个例子。
在一个.h文件中,做如下事情:

//吃的协议
@protocol Eat
@required
-(void)eatSomething:(NSString*)foodname;
@optional
-(void)goToEat;
@end
//声明一个遵守吃的协议的类
@interface I : NSObject<Eat>
-(void)introduceSelf;//自己声明的方法
@end

在.m文件中进行实现。

@implementation I
-(void)introduceSelf
{
    NSLog(@"我是自己声明的方法");
}
-(void)eatSomething:(NSString*)foodname
{
    NSLog(@"我去买%@", foodname);
}
@end

@optional的方法列表可以不用实现,但是@required的方法列表中的所有方法必须实现,如果不实现,编译器会爆出警告

Class '类名' does not conform to protocol '协议名'
4、代理(委托)

在协议的基础上,实现代理。代理我们知道就是把自己的某些工作交给别人来做,或者说是委托给别人来做。因此代理也可一觉委托,通常我就叫代理。
实现的过程就是,在某个类中,会有一个委托对象,这个委托对象遵守某一个协议,而这个协议中的方法正式我们这个类中所需要的。
用一个简单的例子,来说明:
当然上面吃的协议和I这个类是不变的。也就是说现在协议又了,遵守这个协议的类也有了。现在创建一个舍友类。

//.h
@interface Roommate : NSObject

@property(nonatomic, copy) NSString* name_;
@property(nonatomic, assign) id<Eat> somebd_;//委托对象

-(id)initWithName:(NSString*)name;
-(void)eatFood:(NSString *)foodname;
@end


//.m
@implementation Roommate
-(id)initWithName:(NSString*)name
{
    
    if(self = [super init])
    {
        _name_ = name;
    }
    return self;
}

-(void)eatFood:(NSString *)foodname
{
    NSLog(@"%@想吃%@",_name_, foodname);
    [_somebd_ eatSomething:foodname];
}

在mian函数中

//main.m
    Roommate* r = [[Roommate alloc] initWithName:@"大锤"];
    I* me = [[I alloc] init];
    [r setSomebd_:me];//赋值委托对象
    [r eatFood:@"龙须凤尾"];

运行。
在这里插入图片描述
这就是委托,可以简单的理解为,你去吃饭的时候,舍友委托你带饭。

5、后记

又到了最后总结的时间。个人而言,这一整章博客讲述的内容,对比C++的话,有点像友元类。当然在分类中还涉及代码管理的功能。在UIKit中,到处都是代理。现在,Objective-C的一些复杂的东西,记录完了,后面都是学习其他语言见过的内容。下一站block。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值