Objective-C中的类目(Category),延展(Extension),协议(Protocol)这些名词看起来挺牛的,瞬间感觉OC好高大上。在其他OOP语言中就没见过这些名词,刚看到这三个名词的时候,有种感觉这是不是学习的坎?这东西难不难?能不能学会?经过本人亲自验证,这三个东西理解起来还是蛮简单的,学过C++或者Java的小伙伴对比理解还是蛮轻松的。类目(Category)就是给已有的类扩充相应的方法,扩充的方法是公有的,类目还可以起到分模块的功能,下面会详细说到。 延展(Extension)这个名词就是是匿名类目的别称,匿名类目就叫做延展,延展可以实现类方法的私有化,具体如何实现,下面有源码。协议我个人感觉和Java中的接口极为相似,在定义对象时使用协议,个人感觉和Java中得泛型有着异曲同工之妙,看下文的详细介绍吧。(本文为笔者个人总结,欢迎批评指正)。
一.Objective-C中的类目(Category)
在Objective-C比其他OOP的编程语言多了个类目,在OC中除了用继承来扩充类的功能函数外我们还可以用类目来实现。学过C++的小伙伴们是否还记得友元这个概念呢?友元就是非本类的方法可以使用本类中得变量,这也是对类方法的一个扩充,个人感觉在OC中得类目和C++中的友元有着异曲同工之妙(仅代表个人观点,欢迎批评指正),下面我们就来详细的学习一下OC中得类目吧。
提到类目呢,首先我们会问我们具体能拿类目做些什么事情呢下面做一下总结:
1.可以用类目给已有的类扩充方法
2.可以用类目把类的实现按功能模块分为不同的文件
3.可以用来扩展NSObject类的方法,也叫做非正式协议
编译环境说明: iMac OS X 10.9 (13A603) 编译器:XCode 5.0.2版本
1.给已有的类扩充方法
在Xcode中新建CategoryTest类,在新建类中声明两个实例变量,在实现类中重写description方法,打印输出两个实例变量的值
代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
新建一个CategoryTest的类目,来进行对类方法的扩充,
代码如下:
1 2 3 4 5 6 7 8 9 |
|
实现文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
测试运行结果:
1 |
|
2.对把类中不同的功能模块分成不同的文件
1.给上面的类创建两个类目,类目中分别存放实例变量的getter和setter方法,为了节省篇幅下面给出其中一个类目的事例;
接口的声明:
1 2 3 4 5 6 7 8 9 10 11 |
|
类目的实现文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
对代码测试的结果:
1 |
|
3.非正式协议
非正式协议就是给NSObject类创建的类目又叫做非正式协议, 非正式协议一般不需要进行实现,一般在子类中进行方法的重写。代码在这就不赘述啦!
类目的优缺点分析(下面有些是个人观点,不对之处请批评指正)
优点:上面的功能也是类目存在的重要原因之所在,在这就不重复了
局限性: 在类目中只可以为类添加方法,不能添加实例变量; 类目中得方法的优先级要高。
二.Objective-C中的延展(Extension)
简单的说匿名类目就是延展,在延展中定义的方法是类私有的方法只能在类的内部调用,定义延展的方式就是把类目中括号中得名字省略掉,括号保留这就是延展。其实在延展中定义的方法不是真正的私有方法和C++, Java中得方法还有所区别,在类初始化的文件中引入相应延展的头文件,其延展对应的方法也是可以访问的。是通过隐藏延展的头文件来达到方法私有 的。
定义私有方法有以下三种方式:
1.通过延展来实现方法的私有,延展的头文件独立。这种方法不能实现真正的方法私有,当在别的文件中引入延展的头文件,那么在这个文件中定义的类的对象就可以直接调用在延展中定义所谓私有的方法。demo如下:
代码如下:
延展相应的头文件,延展方法的实现在类对应的.m中给出实现方法:
1 2 3 4 5 6 |
|
2.第二种实现延展的方式是延展没有独立的头文件,在类的实现文件.m中声明和实现延展,这种方法可以很好的实现方法的私有,因为在OC中是不能引入.m的文件的
3.第三种实现方法私有的方式是在.m文件中得@implementation中直接实现在@interface中没有声明的方法,这样也可以很好的实现方法的私有。
Extension.m中的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|
在main函数里进行测试,如果在main函数里引入#import "ExtensionTest_Extension1.h"也可以调用其里面声明的相应的方法
? ?测试代码如下:
1 2 3 4 |
|
? ?运行结果:
1 2 3 4 5 |
|
三、Objective中得协议Protocol
? ? ?协议(protocol)提到OC中得协议个人感觉和JAVA中的接口的用法极为相似。把类中常用的方法抽象成OC中得协议,协议中只有方法的声明没有方法的实现,在protocol中可以把方法定义成@required(必须的):在使用协议的类中如果不实现@required的方法,编译器不会报错但会给出警告。还可以把protocol中的方法定义成@optional(可选的)如果在使用协议的类中不实现@optional方法,则不会警告。协议的关键字用@protocol来定义。
? ? ?下面是协议的一个简单demo;
? ? ?1.在Xcode中新建一个Protocol,命名为FirstProtocol,文件名为FirstProtocol.h . 在FirstProtocol协议中声明了两个方法,一个是@required一个是@optional的
1 2 3 4 5 6 7 8 9 10 11 12 |
|
? ? ?2.新建一个类命名为ProtocolClass, 在ProtocolClass.h中使用FirstProtocol协议,在ProtocolClass.m文件中实现协议中得方法
? ? ? ?ProtocolClass.h的代码如下:
1 2 3 4 5 |
|
? ? ?ProtocolClass.m的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
? ? 测试的运行结果为:
1 2 |
|
? ?在声明对象的时候引入协议可以类比这Java中得泛型来学习, 例如声明一个遵守FirstProtocol协议的对象: id<FirstProtocol> obj;下面我们将用一个事例来介绍具体的用法
? ? ?1.创建一个CalculatorProtocol的协议,在协议中声明一个calculatorFunction的方法来进行两个数的计算,文件名为:calculatorProtocol.h
? ? ? ?代码如下: ? ?
1 2 3 4 5 |
|
? ?
? 2.在CalculatorClass类中添加新的方法,在这个类中有一个计算方法,需要对两个数的计算,有一个参数是对象类型的必须遵循协议CalculatorProtocol,主要代码如下:
1 2 3 4 5 6 7 |
|
? ? 3.定义遵循协议calculatorProtocol的类AddClass,在AddClass中实现calculatorFunction方法,实现两个数相加的功能代码如下
1 2 3 4 5 6 7 8 9 10 11 |
|
? 4.新建一个DecClass类,同样遵循calculatorProtocol协议,实现两个数相减的功能,主要代码如下:
1 2 3 4 5 6 7 8 9 10 |
|
?测试代码:
1 2 3 4 5 6 7 |
|
?运行结果如下:
1 2 |
|
?
再举一个理解协议更好理解协议的例子吧,我们声明一个文件协议,协议的内容是对文件的读和写。我们在声明一个文件管理系统的类,只要是文件能读和写就能放进我们的文件管理系统进行管理。
1.指定可放入文件管理系统文件需要遵循的协议,协议中规定文件必须有读写的功能
代码如下
#import <Foundation/Foundation.h> @protocol FileManagerProtocol <NSObject> //读方法 -(void) read; //写方法 -(void) writer; @end
2.编写文件管理系统,来对所有遵守协议的文件来进行的统一的管理
代码如下:
声明:
#import <Foundation/Foundation.h> #import "FileManagerProtocol.h" @interface FileManagerSystem : NSObject -(void) insertFileSystem: (id<FileManagerProtocol>) file; @end
实现:
#import "FileManagerSystem.h" @implementation FileManagerSystem -(void)insertFileSystem:(id<FileManagerProtocol>)file { [file read]; [file writer]; } @end
3.定义新的文件类来遵守我们的文件读写协议,之后就可以放入到我们的管理系统中进行管理
文件类1
#import <Foundation/Foundation.h> #import "FileManagerProtocol.h" @interface File : NSObject<FileManagerProtocol> @property (nonatomic,strong) NSString *fileName; @end #import "File.h" @implementation File //实现协议中的方法 -(void)read { NSLog(@"我是文件%@,你可以对我进行阅读",_fileName); } -(void)writer { NSLog(@"我是文件%@,你可以对我进行修改",_fileName); } @end
在定义一个简历文件,同样遵守我们的文件协议
#import <Foundation/Foundation.h> #import "FileManagerProtocol.h" @interface JianLi : NSObject<FileManagerProtocol> @property (nonatomic, strong) NSString *fileName; @end #import "JianLi.h" @implementation JianLi -(void)read { NSLog(@"对简历%@的读", _fileName); } -(void)writer { NSLog(@"对简历%@的写", _fileName); } @end
然后我们可以把各种不同文件但都遵循我们文件协议的文件放入到我们的文件管理系统进行管理
1 //声明文件,然后放入文件管理系统 2 File *file = [File new]; 3 file.fileName = @"浪潮之巅"; 4 5 //实例化文件二,只要符合文件协议即可 6 File *file1 = [File new]; 7 file1.fileName = @"file1"; 8 9 JianLi *jianLi = [JianLi new]; 10 jianLi.fileName = @"lusashi的简历"; 11 12 //实例化文件管理系统 13 FileManagerSystem *fileSystem = [FileManagerSystem new]; 14 15 16 17 //把书加入到管理系统中 18 [fileSystem insertFileSystem:file]; 19 [fileSystem insertFileSystem:file1]; 20 [fileSystem insertFileSystem:jianLi];
运行结果:
1 2014-08-14 12:05:47.956 Memory[985:303] 我是文件浪潮之巅,你可以对我进行阅读 2 2014-08-14 12:05:47.958 Memory[985:303] 我是文件浪潮之巅,你可以对我进行修改 3 2014-08-14 12:05:47.958 Memory[985:303] 我是文件file1,你可以对我进行阅读 4 2014-08-14 12:05:47.959 Memory[985:303] 我是文件file1,你可以对我进行修改 5 2014-08-14 12:05:47.959 Memory[985:303] 对简历lusashi的简历的读 6 2014-08-14 12:05:47.959 Memory[985:303] 对简历lusashi的简历的写