分类
分类(category)是OBJ-C语法中非常方便的一部分,可以在运行时向某个现有类添加新的方法。包括Cocoa框架中的任何类,我们都可以对其进行扩展,这是从Smalltalk(oc的鼻祖)继承过来的,跟C#中的扩展方法比较像。
不谈历史,先来看下用分类进行私有成员的表现。
#import "ViewController.h"
@interface ViewController ()
{
UIButton *button1;
}
@end
比如这里在.m文件,ViewController的上面有一个匿名的分类(类的扩展),这里声明的变量都属于我们的“私有成员”,对外属于隐藏状态。
这样,我们可以进行更多元化的定义,比如“公有可读,私有读写”。
.h文件中声明一个状态属性
@property (nonatomic, readonly) BOOL viewState;
然后在.m文件的匿名分类中对其声明为readwrite, 便可以进行读写操作了。
@interface ViewController ()
{
UIButton *button1;
}
@property (nonatomic, readwrite) BOOL viewState;
@end
@implementation ViewController
- (void)setViewState:(BOOL)viewState
{
code...
return ;
}
- (BOOL)viewState
{
code...
return ;
}
于是,对属性信息的封装便完成了。
添加“成员”的动态实现
利用Runtime可以很好的在分类中添加属性,甚至对其进行设值取值。
这里我已有一个Person类,我想对其增加一个Address分类,并在分类中声明一个属性Address。
@interface Person (Address)
@property (nonatomic, strong) NSString *address;
@end
这样,我就必须对其进行设值取值了,嗯,但是它只是一个分类声明的属性,并不是成员。
于是代码可能就变成了下面这样
- (NSString *)address
{
return self.address;
}
= =于是,我们找到了更好的方法,就是利用runtime的关联引用
static char KPersonAddressKey;
//setter
- (void)setAddress:(NSString *)address
{
objc_setAssociatedObject(self, &KPersonAddressKey, address, OBJC_ASSOCIATION_COPY);
}
//getter
- (NSString *)address
{
return objc_getAssociatedObject(self, &KPersonAddressKey);
}
下面对其进行了测试
Person *p = [[Person alloc] init];
p.address = @"Tianjin University";
NSLog(@"%@", p.address);
打印结果
2013-08-09 00:41:43.033 CatagoryTest[788:303] Tianjin University
那,有没有私有方法呢。。。
有很多使用类的扩展来写私有方法的例子,这些都能够混过编译器进行调用,虽然编译器不会提示,但是还是会从类中找到那个方法并进行调用。
这主要得益于OC的Runtime特性,他的消息转发机制让很多事情都成为了可能,实现的同时甚至还提升了性能。
有时我们也管其叫“蹦床”,讲一个消息从一个对象弹到另一个对象。这种技术允许一个代理对象把消息转移到另一个线程,缓存结果,合并重复消息甚至其他中间的配置。
实现主要使用对 methodSignatureForSelector:以及forwadInvocation:的方法的覆写。
这里大家也可以参见念茜的博客Objective-C 的“多继承”
以上为全部内容,欢迎指正和扩充。