[iOS]在运行时为类添加方法

来源:互联网 发布:linux定时重启机器 编辑:程序博客网 时间:2024/06/06 07:00

[iOS]在运行时为类添加方法


On 02/05/2012, in Development, iOS Dev, Mac Dev, by ultragtx




Obj-C用起来真是各种happy,比如现在有这样一种情况:有一个类,我们希望它能响应一个消息(message),但是这个类没有相应的方法(method),而你又偏偏不能重写/继承这个类。这时我们可能会想到,能不能动态地给类添加一个方法呢?感谢Obj-C,仅需简单几步就能实现。

先看一段代码

1234567891011121314151617181920212223242526272829
#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, "v@:")// Test Method    EmptyClass *instance = [[EmptyClass alloc] init];    [instance sayHello2][instance release]}

我们首先定义了一个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,添加方法成功。

接下来说一下types参数,
比如我们要添加一个这样的方法:-(int)say:(NSString *)str; 
相应的实现函数就应该是这样:

1234
int say(id self, SEL _cmd, NSString *str) {    NSLog(@"%@", str);    return 100;//随便返回个值}

class_addMethod这句就应该这么写:

1
class_addMethod([EmptyClass class], @selector(say:), (IMP)say, "i@:@");

其中types参数为"i@:@“,按顺序分别表示:

i:返回值类型int,若是v则表示void

@:参数id(self)

::SEL(_cmd)

@:id(str)

这些表示方法都是定义好的(Type Encodings),关于Type Encodings的其他类型定义请参考官方文档

最后调用say:方法:

12
int a = [instance say:@"something"];NSLog(@"%d", a);

输出something和100。

关于本文所涉及内容的详细信息请参考Objective-C Runtime Reference

本文参考了:

  • Add Methods at Runtime in Objective-C(原文的class_addMethods已经废弃了)
  • The Coolest iOS Hack

推荐去看看
—以上—