无业游民

千里之行始于足下

导航

Objective-C动态特性

1. 动态类型,自不必多说,我们通常所定义的id类型即为动态类型,任何对象队可以被id指针所指,只有到运行时再将相应的id类型转换为静态类型,才可以调用静态类型所对应的方法。

2. 动态绑定,能使程序直到执行时才确定对应对象调用的实际方法。 这里面有一个关键的IMP类型,这个是对应实现方法在内存中的地址(Implementation缩写)。动态绑定我们需要把objc/runtime.h加到源文件中。

#import <objc/runtime.h>

Objetive-C中的Method结构
    struct objc_method{
       SEL method_name;//方法名
        char *method_types; //返回值以及参数类型
        IMP method_imp; //方法地址(IMP)
    };
使用一个类的方法替换另一个类的方法,返回结果以及参数要保持一致,方法名不一致同样可以调用成功(两个类对应的方法名不一样,如一个叫getImage, 一个叫fetchImage, 只要保证他们的返回值以及参数相同即可),因为IMP指向的是方法实现的代码在内存中的地址。如下代码可以把NewsViewController中的getImage实现方法替换为CustomViewController中的实现方法。
Method method = class_getInstanceMethod(NSClassFromString(@"NewsViewController"), @selector(getImage));
IMP imp = [NSClassFromString(@"CustomViewController") instanceMethodForSelector:@selector(getImage)];
IMP newImp = method_setImplementation(method, imp);

另外,实现方法还可以使用C语言的写法,就是一个函数。返回值以及参数参考文档,例如如下的”@@:”表示返回返回值类型为id, “@:”必须分别占据字符指针所指向的第2第3位,第一位为返回值,查表可知@代表id类型,在”@:”后面的为参数类型,如有参数,查表填写对应参数即可。

BOOL result = class_addMethod(NSClassFromString(@"NewsViewController"), @selector(getWrongImg), (IMP)getWrongImg, "@@:@");

UIImage* getWrongImg(id self, SEL _cmd, NSString *imageNmae)
{
    return [UIImage imageNamed:imageNmae];
}
在NewsViewController类调用方法如下
IMP imp = [self methodForSelector:NSSelectorFromString(@"getWrongImg")];
UIImage* image = imp(self, NSSelectorFromString(@"getWrongImg"), @"btn_home");
 
如果不用C语言的写法,可用如下代码,等价于上面这段代码。
IMP newImp = [MainViewController instanceMethodForSelector:@selector(getWrongImg)];
BOOL result = class_addMethod(NSClassFromString(@"NewsViewController"), @selector(getWrongImg), newImp, "@@:@");

- (UIImage *)getWrongImg:(NSString *imageNamed)
{
    return [UIImage imageNamed:imageNamed];
}

在NewsViewController调用方法如下
IMP imp = [self methodForSelector:NSSelectorFromString(@"getWrongImg")];
UIImage* image = imp(self, NSSelectorFromString(@"getWrongImg"), nil);

最后再介绍动态添加一个类,以及如何调用该类的方法,不过目前没有想到有什么实用的地方,可能自己编译方面的知识还没有学到家,不然可以动态注入或者是怎样玩。

Class myClass = objc_allocateClassPair([NSObject class], "MyClass", 0);
//class_addIvar(myClass, "image", sizeof(UIImage *), log2(sizeof(UIImage *)), "@");
BOOL result = class_addMethod(myClass, @selector(getImage), (IMP)getImage, "@@:@");
NSLog(@"addMethod:%@", result?@"YES":@"NO");
objc_registerClassPair(myClass);

UIImage *getImage(id self, SEL _cmd, NSString *imageName)
{
    return [UIImage imageNamed:imageName];
}

调用新类的方法
Class myClass = NSClassFromString(@"MyClass");
IMP imp = class_getMethodImplementation(myClass, @selector(getImage));
return imp(self, @selector(getImage), imageNmae);

3. 动态加载,这个好理解,根据不同的环境不同的机型,加载对应的资源,如图片的.png和@2x.png。

posted on 2013-04-18 18:05  PeterHuang  阅读(1694)  评论(0编辑  收藏  举报