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.能够用类目把类的实现按功能模块分为不一样的文件ui
3.能够用来扩展NSObject类的方法,也叫作非正式协议atom
编译环境说明: iMac OS X 10.9 (13A603) 编译器:XCode 5.0.2版本spa
1.给已有的类扩充方法code
在Xcode中新建CategoryTest类,在新建类中声明两个实例变量,在实现类中重写description方法,打印输出两个实例变量的值orm
代码以下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
//CategoryTest.h
#import <Foundation/Foundation.h>
@interface CategoryTest : NSObject
//定义两个私有的属性
{
@
private
int
ludashi1;
int
ludashi2;
}
@end
//CategoryTest.m
#import "CategoryTest.h"
@implementation CategoryTest
//重写description方法
-(NSString *) description
{
return
[NSString stringWithFormat:@
"ludashi1 = %d, ludashi2 = %d"
, ludashi1,ludashi2];
}
@end
|
新建一个CategoryTest的类目,来进行对类方法的扩充,
代码以下:
1
2
3
4
5
6
7
8
9
|
// CategoryTest+CategoryExtendFunction.h
// Memory
// Created by ludashi on 14-8-4.
// Copyright (c) 2014年 Mr.li. All rights reserved.
#import "CategoryTest.h"
@interface CategoryTest (CategoryExtendFunction)
//利用类目扩展新的方法
-(
void
) extendFunction;
@end
|
实现文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
//
// CategoryTest+CategoryExtendFunction.m
// Memory
// Created by ludashi on 14-8-4.
// Copyright (c) 2014年 Mr.li. All rights reserved.
#import "CategoryTest+CategoryExtendFunction.h"
@implementation CategoryTest (CategoryExtendFunction)
//实现扩展的方法
-(
void
)extendFunction
{
NSLog(@
"鲁大师,你好!我是经过类目扩展的方法!"
);
}
@end
|
测试运行结果:
1
|
2014-08-04 17:08:46.187 Memory[1621:303] 鲁大师,你好!我是经过类目扩展的方法!
|
2.对把类中不一样的功能模块分红不一样的文件
1.给上面的类建立两个类目,类目中分别存放实例变量的getter和setter方法,为了节省篇幅下面给出其中一个类目的事例;
接口的声明:
1
2
3
4
5
6
7
8
9
10
11
|
// CategoryTest+Categgory1.h
// Memory
// Created by ludashi on 14-8-4.
// Copyright (c) 2014年 Mr.li. All rights reserved.
#import "CategoryTest.h"
@interface CategoryTest (Categgory1)
//声明Category中实例变量ludashi1的getter和setter方法
-(
void
) setLudashi1:(
int
) vLudashi;
-(
int
) ludashi1;
@end
|
类目的实现文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
// CategoryTest+Categgory1.m
// Memory
// Created by ludashi on 14-8-4.
// Copyright (c) 2014年 Mr.li. All rights reserved.
#import "CategoryTest+Category1.h"
@implementation CategoryTest (Categgory1)
//实现ludashi1的getter和setter方法
-(
void
)setLudashi1:(
int
)vLudashi
{
ludashi1 = vLudashi;
}
//getter方法
-(
int
) ludashi1
{
return
ludashi1;
}
@end
|
对代码测试的结果:
1
|
2014-08-04 17:08:46.188 Memory[1621:303] ludashi1 = 10, ludashi2 = 20
|
3.非正式协议
非正式协议就是给NSObject类建立的类目又叫作非正式协议, 非正式协议通常不须要进行实现,通常在子类中进行方法的重写。代码在这就不赘述啦!
类目的优缺点分析(下面有些是我的观点,不对之处请批评指正)
优势:上面的功能也是类目存在的重要缘由之所在,在这就不重复了
局限性: 在类目中只能够为类添加方法,不能添加实例变量; 类目中得方法的优先级要高。
二.Objective-C中的延展(Extension)
简单的说匿名类目就是延展,在延展中定义的方法是类私有的方法只能在类的内部调用,定义延展的方式就是把类目中括号中得名字省略掉,括号保留这就是延展。其实在延展中定义的方法不是真正的私有方法和C++, Java中得方法还有所区别,在类初始化的文件中引入相应延展的头文件,其延展对应的方法也是能够访问的。是经过隐藏延展的头文件来达到方法私有 的。
定义私有方法有如下三种方式:
1.经过延展来实现方法的私有,延展的头文件独立。这种方法不能实现真正的方法私有,当在别的文件中引入延展的头文件,那么在这个文件中定义的类的对象就能够直接调用在延展中定义所谓私有的方法。demo以下:
代码以下:
延展相应的头文件,延展方法的实如今类对应的.m中给出实现方法:
1
2
3
4
5
6
|
#import "ExtensionTest.h"
@interface ExtensionTest ()
-(
void
)privateFunction1;
@end
|
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
|
#import "ExtensionTest.h"
#import "ExtensionTest_Extension1.h"
//在实现方法里声明延展
@interface ExtensionTest()
-(
void
) privateFunction2;
@end
@implementation ExtensionTest
//实现各类方法
-(
void
)publicFunction
{
NSLog(@
"publicFunction PS:我是正儿八经的公用方法,我在.h中被声明,在.m中被实现"
);
//调用各类私有方法
[self privateFunction1];
[self privateFunction2];
[self privateFunction3];
}
//实现第一个私有方法(第一种实现类方法私有化的方法)
-(
void
)privateFunction1
{
NSLog(@
"PrivateFunction1 PS:我是在别的头文件中定义的延展,在.m中被实现"
);
}
//实现第二个私有方法(第二种实现类方法私有化的方法)
-(
void
)privateFunction2
{
NSLog(@
"PrivateFunction2 PS:我是在本文件中定义的延展,在本文件中进行实现!"
);
}
//在头文件中为声明的方法在.m中直接定义是私有的方法
-(
void
)privateFunction3
{
NSLog(@
"PrivateFunction3: 我是在实现方法中直接定义的方法,我也是私有变量"
);
}
end
|
在main函数里进行测试,若是在main函数里引入#import "ExtensionTest_Extension1.h"也能够调用其里面声明的相应的方法
测试代码以下:
1
2
3
4
|
//测试延展
ExtensionTest *extension = [ExtensionTest
new
];
[extension publicFunction];
[extension privateFunction1];
|
运行结果:
1
2
3
4
5
|
2014-08-05 15:54:46.147 Memory[1683:303] publicFunction PS:我是正儿八经的公用方法,我在.h中被声明,在.m中被实现
2014-08-05 15:54:46.149 Memory[1683:303] PrivateFunction1 PS:我是在别的头文件中定义的延展,在.m中被实现
2014-08-05 15:54:46.149 Memory[1683:303] PrivateFunction2 PS:我是在本文件中定义的延展,在本文件中进行实现!
2014-08-05 15:54:46.150 Memory[1683:303] PrivateFunction3: 我是在实现方法中直接定义的方法,我也是私有变量
2014-08-05 15:54:46.150 Memory[1683:303] PrivateFunction1 PS:我是在别的头文件中定义的延展,在.m中被实现
|
3、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
|
#import <Foundation/Foundation.h>
//建立第一个protocol
@protocol FirstProtocol <NSObject>
//为protocol里加入必须实现的方法
@required
-(
void
)requiredFunction;
//定义可选的方法
@optional
-(
void
)optionalFunction;
@end
|
2.新建一个类命名为ProtocolClass, 在ProtocolClass.h中使用FirstProtocol协议,在ProtocolClass.m文件中实现协议中得方法
ProtocolClass.h的代码以下:
1
2
3
4
5
|
#import <Foundation/Foundation.h>
#import "FirstProtocol.h"
//在普通类中实现协议的方法以下<>
@interface ProtocolClass : NSObject<FirstProtocol>
@end
|
ProtocolClass.m的代码以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#import "ProtocolClass.h"
//不实现协议中必须的方法会产生警告
@implementation ProtocolClass
//实现协议中必须的方法: required方法
-(
void
) requiredFunction
{
NSLog(@
"RequiredFunction PS: 我是协议中required方法,不实现我会有警告!"
);
}
//实现协议中可选的方法,不实现不会有警告
-(
void
) optionalFunction
{
NSLog(@
"OptionalFunction PS: 我是protocol中得可选协议,不实现我,不会有警告!"
);
}
@end
|
测试的运行结果为:
1
2
|
2014-08-05 17:38:50.189 Memory[1907:303] RequiredFunction PS: 我是协议中required方法,不实现我会有警告!
2014-08-05 17:38:50.190 Memory[1907:303] OptionalFunction PS: 我是protocol中得可选协议,不实现我,不会有警告!
|
在声明对象的时候引入协议能够类比这Java中得泛型来学习, 例如声明一个遵照FirstProtocol协议的对象: id<FirstProtocol> obj;下面咱们将用一个事例来介绍具体的用法
1.建立一个CalculatorProtocol的协议,在协议中声明一个calculatorFunction的方法来进行两个数的计算,文件名为:calculatorProtocol.h
代码以下:
1
2
3
4
5
|
#import <Foundation/Foundation.h>
//声明计算方法
@protocol CalculatorProtocol <NSObject>
-(
void
)calculatorFunction : (
int
) x withY : (
int
) y;
@end
|
2.在CalculatorClass类中添加新的方法,在这个类中有一个计算方法,须要对两个数的计算,有一个参数是对象类型的必须遵循协议CalculatorProtocol,主要代码以下:
1
2
3
4
5
6
7
|
//实现传入的对象必须服从协议的方法
-(
void
) calculatorFunction:(
int
)x
withY:(
int
)y
withObj:(id<CalculatorProtocol>)obj
{
[obj calculatorFunction:x withY:y];
}
|
3.定义遵循协议calculatorProtocol的类AddClass,在AddClass中实现calculatorFunction方法,实现两个数相加的功能代码以下
1
2
3
4
5
6
7
8
9
10
11
|
#import "AddClass.h"
@implementation AddClass
//实现CalculatorProtocol必须的方法
-(
void
)calculatorFunction:(
int
)x withY:(
int
)y
{
int
a = x + y;
NSLog(@
"AddClass PS: 我是实现协议的加方法%d + %d = %d"
, x, y, a);
}
@end
|
4.新建一个DecClass类,一样遵循calculatorProtocol协议,实现两个数相减的功能,主要代码以下:
1
2
3
4
5
6
7
8
9
10
|
#import "DecClass.h"
@implementation DecClass
//实现protocol中必须实现的方法
-(
void
) calculatorFunction:(
int
)x withY:(
int
)y
{
int
a = x - y;
NSLog(@
"DecClass PS: 我是重写的减方法%d - %d = %d"
, x, y, a);
}
@end
|
测试代码:
1
2
3
4
5
6
7
|
//测试协议对象
AddClass *add = [AddClass
new
];
//往protocol对象中的calculator方法中传入符合协议的add对象
[pro calculatorFunction:2 withY:2 withObj:add];
DecClass *dec = [DecClass
new
];
[pro calculatorFunction:4 withY:3 withObj:dec];
|
运行结果以下:
1
2
|
2014-08-05 17:38:50.190 Memory[1907:303] AddClass PS: 我是实现协议的加方法2 + 2 = 4
2014-08-05 17:38:50.191 Memory[1907:303] DecClass PS: 我是重写的减方法4 - 3 = 1
|
再举一个理解协议更好理解协议的例子吧,咱们声明一个文件协议,协议的内容是对文件的读和写。咱们在声明一个文件管理系统的类,只要是文件能读和写就能放进咱们的文件管理系统进行管理。
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的简历的写