前言
Objective-C的面向对象编程中,分类,扩展,协议这几个概念经常会使用到,这篇文章简单的记录了我在学习Objective-C时候对它们的理解
正文
类别(Category)
先看一段代码来看看类别到底长得是个什么样子
@interface NSString(NumberConvenience)
- (NSNumber*)lengthAsNumber;
@end
@implementation NSString(NumberConvenience)
-(NSNumber *)lengthAsNumber
{
unsigned int length = [self length];
return ([NSNumber numberWithUnsignedInt : length]);
} //lengthAsNumber
@end //NumberConvenience
上面的代码是对NSString这个类进行扩展出一个新的方法,在写类别的时候需要注意下面几点
- 总是习惯把类别的代码放到单独的文件,通常会以“类名称+类别名称”的风格命名,如在项目中经常可以看到这样形式的文件:NSString+NumberConvenience
- 在@interface 和@implementation 的类名称后面都要加一个括号,括号里面是新名称
- 类别中不能写成员变量,只能写属性,属性的好处就是可以通过点表达式访问setter和getter方法
- 小心名称冲突,如果发送名称冲突时,类别具有更高的优先级,你的类别方法将完全取代初始方法。你可以给自己扩展的方法增加一个前缀来确保不发生冲突
ignore:之前使用比如NSString这样的类的时候,发现它不能满足我需要的功能,我网上找了第三方库,它对NSString功能上做了扩展。它其实就是NSString+XXXX 这样的文件,我只要在需要的地方引入头文件就可以了
扩展(Extension)
“扩展”是“类别”的一种特殊的形式,它弥补了类别一些缺陷,我们先从代码上来比较两者有什么区别
@interface Things : NSObject
@property (assign) NSInteger thing1;
@property (readonly,assign) NSInteger thing2;
- (void) resetAllValues;
@end
@interface Things() {
NSInteger thing4;
}
@property (readwrite,assign) NSInteger thing2;
@property (assign) NSInteger thing3;
@end
从上面的代码中,我们可以得出下面的一些结论
- “扩展” 不需要名字,但是不要忘记后面有一个括号
- “扩展”可以添加成员变量(实例变量)
- 可以把它写在源代码类里面(.m)
- 可以将头文件的只读权限变成可读写的权限
- 扩展的属性,方法,成员变量都是私有的
- 创建的数量不限
需要讲一下第4点,之前对这样的写法感到很困惑。在类的公共接口(.h)中定义一个只读的属性供外部访问,但是在实现类中(.m)中我想用到它的setter方法,该如何设置。 别急,扩展可以更改成可读写权限,如上面代码一样,使用@property (readwrite,assign) NSInteger thing2; 就可以了。 需要注意的是这个setter只能在这个类中访问,公共接口还是只有getter方法
ignore: 面向对象编程中的封装性就是对信息的隐藏,我们只需要给外部提供所需要的方法,其他的一些细节可以隐藏,“扩展”可以实现这一个目标
协议(protocol)
类似于java的接口(interface),先从代码上来认识协议
@protocol myProtocol <NSObject>
@required
-(void) protocolNameA:(NSString*)string;
@optional
-(void) protocolNameB:(NSString*)string;
@end
从代码上来看有几点需要注意的地方
- 协议可以继承协议(java中接口继承接口类似),继承的方式就是在后面的尖括号中写入需要实现的协议,如果有多个的话,用逗号隔开
- 提供了@require 和 @optional选项,从字面上理解就是这个协议中的方法是不是需要实现,@required表示必须的实现(否则编译错误)
- 类要实现这个协议,写法如下
@interface myClass <myProtocol>
@interface myClass :NSObject<myProtocol>
@interface myClass :NSObject<myProtocol, NSCoding>
ignore: 之前由于时间仓促,基础不扎实就去改外包的代码,对于其中的委托(回调)机制非常不理解,常常是一个流程走完了,还找不到某个功能实现的地方。它其实使用就是协议,例如在类A中实现了协议,把A实例对象传递给B类的成员变量(id <myProtocol> delegate;
),在A中使用B类的方法的时候,这里面的方法会去回调类A中所实现的协议方法。比如iOS的UI类,网络通信CocoaAsyncSocket(弄懂这些协议被调用的时机,应该理解起来不困难)