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.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中被实现

三、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

  然后我们可以把各种不同文件但都遵循我们文件协议的文件放入到我们的文件管理系统进行管理

     //声明文件,然后放入文件管理系统
File *file = [File new];
file.fileName = @"浪潮之巅"; //实例化文件二,只要符合文件协议即可
File *file1 = [File new];
file1.fileName = @"file1"; JianLi *jianLi = [JianLi new];
jianLi.fileName = @"lusashi的简历"; //实例化文件管理系统
FileManagerSystem *fileSystem = [FileManagerSystem new]; //把书加入到管理系统中
[fileSystem insertFileSystem:file];
[fileSystem insertFileSystem:file1];
[fileSystem insertFileSystem:jianLi];

  运行结果:

 -- ::47.956 Memory[:] 我是文件浪潮之巅,你可以对我进行阅读
-- ::47.958 Memory[:] 我是文件浪潮之巅,你可以对我进行修改
-- ::47.958 Memory[:] 我是文件file1,你可以对我进行阅读
-- ::47.959 Memory[:] 我是文件file1,你可以对我进行修改
-- ::47.959 Memory[:] 对简历lusashi的简历的读
-- ::47.959 Memory[:] 对简历lusashi的简历的写

Objective-C中的类目,延展,协议的更多相关文章

  1. Objective-C中的类目(Category),延展(Extension)

    类目和延展的作用都是为了扩展一个类. Objective-C中的类目(Category) 一.类目的定义和作用 类目也叫分类,英文Category,在没有原类.m文件的基础上,给该类添加方法. 比如, ...

  2. Java生鲜电商平台-生鲜电商中商品类目、属性、品牌、单位架构设计与实战

    Java生鲜电商平台-生鲜电商中商品类目.属性.品牌.单位架构设计与实战 说明:Java生鲜电商平台-生鲜电商中商品类目.属性.品牌.单位架构设计与实战经验分享 凡是涉及到购物,必然是建立在商品的基础 ...

  3. object-c中的类目,延展,协议

    协议 协议只有方法的声明(类似于其他编程语言的接口)   协议相当于大家都所遵循的 关键字 @protocol 协议名 <所遵循的协议> 默认NSObject   @end     @pr ...

  4. Objective-C学习笔记类目、协议

    不是所有的方法都可以被覆盖的!比如:intValue就不能被覆盖!! 原因正在查找中! 别人的电脑上却可以! 类目.h件 #import <Foundation/Foundation.h> ...

  5. iOS类目、延展和协议

    类目:为已知的类增加新的方法:注意:类目里面只能写方法,不能写声明和属性,所以,类目不能作为接口来用 1.类目无法向已有类中添加实例变量.2.如果类目中的方法和已有类中的方法名称冲突时,类目中的方法优 ...

  6. objective-c 类目(Category)和延展(Extension)

    类目的基本概念: 如果有封装好的一个类,随着程序功能的增加,需要在类中增加一个方法,那我们就不必在那个类中做修改或者再定义一个子类,只需要在用到那个方法时添加一个该类的类目即可. 1.在类目定义的方法 ...

  7. OC中协议, 类目, 时间, 延展, 属性

    只有继承和协议需要引IMPORT "头文件"; 必须接受marryprotocol协议, id<marryprotocol>基于类型的限定, 才能给实例变量赋值 @pr ...

  8. OC 中 类目、延展和协议

    Category : 也叫分类,类目. *是 为没有源代码的类 扩充功能 *扩充的功能会成为原有类的一部分,可以通过原有类或者原有类的对象直接调用,并且可继承 *该方法只能扩充方法,不能扩充实例变量 ...

  9. iOS -类目,延展,协议

    1.类目 类目就是为已存在的类添加新的方法.但是不能添加实例变量.比如系统的类,我们看不到他的.m文件,所以没有办法用直接添加方法的方式去实现. @interface NSMutableArray ( ...

随机推荐

  1. PHP的数组排序函数

    <?php class order{ /** * * 数组排序 * @param array $arr 例如: * array ( array ( 'deskId' => '460646' ...

  2. java web(六)多个请求对应一个Servlet

    概要: 提交请求的常用方式有两种,get/post , 运行程序后被请求,在加载执行web.xml文件时通过该文件中的映射关系找到即将要执行的Servlet; 而在要执行的Servlet文件中可通过反 ...

  3. Android再学习

    1.点击事件的几种实现方式 Button Btn1 = (Button)findViewById(R.id.button1);//获取按钮资源 Btn1.setOnClickListener(new ...

  4. python读取文本文件

    1. 读取文本文件 代码: f = open('test.txt', 'r') print f.read() f.seek(0) print f.read(14) f.seek(0) print f. ...

  5. ant 自动化编译

    bulid.xml配置: <?xml version="1.0" encoding="UTF-8" ?> <project name=&quo ...

  6. MapleSim助力长臂挖掘机建模问题解决

    1.问题描述 一家机械零部件设计公司需要一个挖掘机模型,验证他们的零部件是否匹配完整的挖掘机系统.由于他们是一个零部件供应商,公司没有足够的资源和研发人员使用传统的工具创建一个完整系统的详细模型.然而 ...

  7. HTML input小结

    一.Input表示Form表单中的一种输入对象,其又随Type类型的不同而分文本输入框,密码输入框,单选/复选框,提交/重置按钮等,下面一一介绍. 1.type=text 输入类型是text,这是我们 ...

  8. 如何在.NET上处理二维码

    在移动设备,网站以及应用程序间传送数据,而使用二维码真是一种较快捷的方法,也避免了蓝牙配对的混乱状况.ZXing.NET是一个开源,多格式1D/2D条码图像处理库的C#实现,ZXing.NET是个相当 ...

  9. 剑指Offer面试题:16.合并两个排序的链表

    PS:这也是一道出镜率极高的面试题,我相信很多童鞋都会很眼熟,就像于千万人之中遇见不期而遇的人,没有别的话可说,唯有轻轻地问一声:“哦,原来你也在这里? ” 一.题目:合并两个排序的链表 题目:输入两 ...

  10. 剑指Offer面试题:25.二叉搜索树与双向链表

    一.题目:二叉搜索树与双向链表 题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向.比如输入下图中左边的二叉搜索树,则输出转换之后的 ...