说明:利用
Objective-C的动态运行时分配机制,你可以为现有的类添加方法或计算属性,这种机制称为类别(category)。
- 可以在类中添加属性(
@property),且只能是计算属性(不能添加实例变量)- 可以向一个
类添加任意数量的类别类别可以访问其扩展的类的实例变量总结:我将
类别分3种
| 种类 | @interface |
@implementation |
|---|---|---|
| 类别 | @interface 类名(类别名) |
@implementation 类名(类别名) |
| 类扩展(匿名类别) | @interface 类名() |
无 |
| 前向引导 | @interface 类名(类别名) |
@implementation 类名 |
12.1 创建类别
说明:可以为人和类添加新的方法,包括那些没有源代码的类。
技巧:通常把类别代码放在独立的文件中,通常以类名称+类别名称的风格命名。
12.1.1 开始创建类别独立文件
说明:使用
Xcode往项目中添加类别非常容易,甚至可以类名称+类别名称命名类别文件。
- 新建文件
- 选择模版
- 文件相关
- 完成
12.1.2 @interface部分
NSString+NumberConvience.h
1 |
|
12.1.3 @implementation部分
NSString+NumberConvience.m
1 |
|
main.m
1 |
|
12.1.4 类别的缺陷
说明:类别有2个局限性
- 无法向类中添加实例变量
- 当类别添加的方法和类中原有的方法重名时,类别具有更高的优先级
解决命名冲突:可以在类别的方法名中添加一个前缀,以确保不会发生名称冲突。
添加实例变量:使用全局字典来存储对象与想关联的额外变量之间的映射。
12.1.5 类别的优势
说明:类别主要有3个用途
- 将类的实现代码分散到多个不同文件或框架中
- 创建对私有方法的前向引用
- 向对象添加非正式协议(informal protocol)
12.1.6 类扩展
说名:
类扩展(class extension)是一个特殊的类别,它不需要命名(只有@interface没有@implementation)。
- 可以包含源代码的类中使用
- 可以添加实例变量
- 可以将只读权限改成可读写的权限
- 创建数量不限
信息隐藏:分2种情况
类扩展所在文件 |
可访问性 |
|---|---|
扩展的目标类的@implementation所在.m文件 |
目标类的内部 |
单独的私有.h文件 |
目标类的内部、目标类的子类和友类 |
注意:可以拥有多个
类扩展,不过这样会引发很难察觉的bug,所以请理智使用。
Things.h:类的@interface
1 |
|
Things.m:类的@implementation和类扩展
1 |
|
main.m:使用被扩展后的NSString
1 |
|
12.2 利用类别分散实现代码
说明:如果想将大型的单个类分散到多个不同的
.m文件中,可以使用类别。
举例:AppKit中的NSWindow,拥有大量的类别声明
@interface NSWindow(NSKeyboardUI)@interface NSWindow(NSToolbarSupport)@interface NSWindow(NSDrag)@interface NSWindow(NSCarbonExtensions)扩展:
类别还可以将方法分散到逻辑群组中,使编程人员可以更加容易地阅读头文件。
在项目中使用类别
说明:将类的
类别的实现部分分散在三个独立的文件中。
CategoryThing.h:类的@interface和3个类别的@interface
1 |
|
CategoryThing.m:类的@implementation
1 |
|
CategoryThing+Thing1.m:类别Thing1的@implementation
1 |
|
CategoryThing+Thing2.m:类别Thing2的@implementation
1 |
|
CategoryThing+Thing3.m:类别Thing3的@implementation
1 |
|
main.m:调用类通过类别扩展的功能
1 |
|
12.3 通过类别创建前向引用
背景:
Objective-C的私有方法分两种
- 如果在一个类的
@implementation部分定义了某个方法,而对应的@interface部分没有相应的方法声明- 通过
类扩展(匿名类别)扩展的方法然而,
O-C并不真的支持私有方法,所以私有方法仍然可以通过对象调用,只不过这时Xcode会给出警告。
说明:当从外部访问某个类的私有方法时,为了避免Xcode给出警告,可以通过类别补充一个声明,即前向引导。
扩展:实际上,苹果公司官网在知道方针中指出,应用程序不能访问类里面的私有变量和方法,如果你的应用程序有这样的行为,那么苹果公司会拒绝让它上架。
main.m:在最前面创建类别来补充私有方法的声明
1 | @interface Car (Private) |
Car.m:方法的实现部分是Car的私有方法
1 | @implementation Car |
12.4 非正式协议和委托类别
委托:将某些工作交给另一个类执行就叫做
委托(delegate)。
委托对象:委托技术中,被委托用来执行某些工作的对象。
说明:除了通过继承创建委托对象外,可以通过类别扩展NSObject(即创建了一个非正式协议),使其获得委托方法,从而将任何对象都变成委托对象。
12.4.1 iTunesFinder项目
说明:用来说明
Cocoa中是如何使用委托技术的。
Bonjour
说明:查找由
Bonjour发布的网络服务的Cocoa类是NSNetServiceBrowser。
用法:告诉网络服务浏览器你需要的服务,并为其提供一个委托对象。浏览器对象将会向该委托对象发送消息,告知其发现新服务的时间。
ITunesFinder.h
1 |
|
ITunesFinder.m
1 |
|
main.m
1 |
|
12.4.2 委托和类别
说明:除了通过
继承创建委托对象外,可以通过类别扩展NSObject(即创建了一个非正式协议),使其获得委托方法,从而将任何对象都变成委托对象。
1 | @interface NSObject (NSNetServerBrowserDelegateMethods) |
12.4.3 响应选择器
说明:
NSNetServiceBrowser为了确定其委托对象是否能够处理那些发送给它的消息,会首先检查对象,询问其能否响应该选择器,是泽发送消息,否则忽略这个委托对象,程序继续运行。
选择器(selector)
说明:只是一个方法名称,但以
Objective-C运行时使用的特殊方式编码,以快速执行查询。
语法:@selector(方法名)
用途:NSObject提供了一个名为responendsToSelector的方法,该方法询问对象以确定其是否能够响应某个特定的消息。
1 | Car *car = [[Car alloc] init]; |
12.4.4 选择器的其它应用
说明:选择器可以
- 被传递
- 作为方法的参数
- 作为实例变量被存储
举个例子:
Foundation框架中的NSTimer




