一、在运行时为类添加方法
我们首先定义了一个EmptyClass,继承NSObject,没有任何自带方法,接着定义了一个函数。这里提一句,Obj-C的方法(method)就是一个至少需要两个参数(self,_cmd)的C函数,这个函数仅仅输出一句Hello。接下来在addMethod方法中,我们调用class_addMethod()为EmptyClass添加方法,class_addMethod()是这样定义的:
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
参数说明:
cls:被添加方法的类。
name:可以理解为方法名,这个貌似随便起名,比如我们这里叫sayHello2。
imp:实现这个方法的函数。
types:一个定义该函数返回值类型和参数类型的字符串。
接着创建EmptyClass的实例,调用sayHello2,运行,输出Hello,添加方法成功。
#if TARGET_IPHONE_SIMULATOR
#import <objc/objc-runtime.h>
#else
#import <objc/runtime.h>
#import <objc/message.h>
#endif
@interface EmptyClass:NSObject
@end
@implementation EmptyClass
@end
void sayHello(id self, SEL _cmd) {
NSLog(@"Hello");
}
- (void)addMethod {
class_addMethod([EmptyClass class], @selector(sayHello2), (IMP)sayHello, "[email protected]:");
// Test Method
EmptyClass *instance = [[EmptyClass alloc] init];
[instance sayHello2];
[instance release];
}
二、为什么不要重写原有类方法
主要原因如下:
CocoaFramework有很多是用Category实现的,重写之后,会导致在Runtime的时 候,只有一个方法会被执行,而哪个会被执行是undefined。
例如,重写NSString的一个方法base64EncodedString,而其他CocoaFramework的也有可能使用Category来实现这个方法,这样就会导致在Runtime的时候,执行哪个方法是Undefined。
另外,有个地方要注意,那就是Category方法的命名。
通常的明明方式是加一个前缀,例如
-(void)WC_setUpCustomButton;
因为,现在名字并未发生冲突,IOS版本在更新,SDK也在更新,也就是说要尽量保证将来方法的名称也不发生冲突。
三、联合存储实现方式及底层原理解析
动态语言的最大好处,就是灵活性,对于Objective-C来说,能在运行时动态地为类增加方法和实例变量是很多其它语言羡慕不已的能力。现在说说为类增加实例变量用到的技术:联合存储。
一、联合存储的实现方式
下面这段代码实现了为Duck类增加color属性:
Duck+associative.h文件
#import "Duck.h"
@interface Duck (associative)
@property (nonatomic, retain) NSString *color;
@end
Duck+associative.m文件
#import "Duck+associative.h"
#import <objc/runtime.h>
@implementation Duck (associative)
static char colorKey = NULL;
- (NSString *)color {
return objc_getAssociatedObject(self, &colorKey);
}
- (void)setColor:(NSString *)aColor {
objc_setAssociatedObject(self, &colorKey,
aColor,
OBJC_ASSOCIATION_RETAIN);
}
调用举例:
Duck *smallDuck = [[Duck alloc] init];
smallDuck.color = @"red color";
NSLog(@"duck color:%@",smallDuck.color);
[smallDuck release];
输出结果:
2013-07-18 19:09:26.578 ObjcRunTime[429:403] duck color:red color
至此,我们已经成功的为Duck类增加了一个color属性。
四、联合存储的优缺点
1、优点
联合存储的最大的优点,在于它能通过灵活的方式实现为类增加属性。
2、缺点
效率低,使用单条机器指令就可以访问真正的实例变量,但是访问存储在映射表中的值需要多个函数调用,效率问题还是需要注意的。
事实上,目前许多Cocoa类,像NSAttributedString、NSFileManager、NSNotification、NSProcessInfo等都广泛地使用了联合存储。
参考链接:
- iOS在运行时为类添加方法
- Objective-C通过联合存储为类增加属性及原理解析
- iOS - 如何给1个类添加属性
- Add variables to an existing class in objective-c
- Faking instance variables in Objective-C categories with Associative References