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. 使用GDB 追踪依赖poco的so程序,core dump文件分析.

    前言 在windows 下 系统核心态程序蓝屏,会产生dump文件. 用户级程序在设置后,程序崩溃也会产生dump文件.以方便开发者用windbg进行分析. so,linux 系统也有一套这样的东东- ...

  2. css多行显示省略号

    首先说css多行显示省略号和单行文本省略号: 我们知道,单行显示省略号时,我们首先需要设置容器的宽度width:value(具体的值),然后强制文本在一行内显示,即white-spacing:nowr ...

  3. IE6中内容高度比高级浏览器高的解决办法

    1.div高度小于12px时,加over-flow:hidden; 2.多用padding,少用margin: 3.img vertical-align:top;

  4. 将Web应用发布到tomcat中的三种方法

    坑啊,为什么网易的博客不能搬过来!!!我一个一个复制过来容易嘛!!!!原文地址:http://buffalo-l.blog.163.com/blog/static/244954022201539111 ...

  5. [转]android:动态创建多个按钮 及 批量设置监听

    之前投机取巧,先创建好多个按钮,再根据需要的数量进行部分隐藏,不过还是逃不过呀. 这样根本无法批量地 findId,批量地 设置监听. 所以今天还是认认真真地研究回“动态创建按钮”,终于,通过不断尝试 ...

  6. [LintCode] Container With Most Water 装最多水的容器

    Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai).  ...

  7. Java ArrayList和Vector、LinkedList与ArrayList、数组(Array)和列表集合(ArrayList)的区别

    ArrayList和Vector的区别ArrayList与Vector主要从二方面来说.  一.同步性:   Vector是线程安全的,也就是说是同步的,而ArrayList是线程序不安全的,不是同步 ...

  8. canvas :曲线的面积图 加渐变效果

    document.body.innerHTML = '<canvas></canvas>' var cvs = document.querySelector("can ...

  9. 为什么要重写hashcode() 方法

    Java中的集合(Collection)有两类,一类是List,再有一类是Set. 前者集合内的元素是有序的,元素可以重复:后者元素无序,但元素不可重复. 那么我们怎么判断两个元素是否重复呢? 这就是 ...

  10. LB 负载均衡的层次结构

    作为后端应用的开发者,我们经常开发.调试.测试完我们的应用并发布到生产环境,用户就可以直接访问到我们的应用了.但对于互联网应用,在你的应用和用户之间还隔着一层低调的或厚或薄的负载均衡层软件,它们不显山 ...