我们都知道Objective-C是一门动态语言,它的动态性一方面就体现在了runtime上。
接下来我们就来看一下,通过runtime来动态的创建一个类,并且给类添加属性和方法,并且还能给已有的类修改、替换方法的实现。
动态的创建一个类的步骤:
- 创建一个类
- 添加属性(一定要在注册前添加)
- 注册这个类
- 添加方法
- 销毁这个类
-(void)createClass
{
//创建一个新类 MyClass
Class myClass = objc_allocateClassPair([NSObject class], "MyClass", 0);
//添加ivar
//@encode(aType):返回该类型的C字符串
class_addIvar(myClass, "_address", sizeof(NSString *), log2(sizeof(NSString *)), @encode(NSString *));
class_addIvar(myClass, "_age", sizeof(NSUInteger), log2(sizeof(NSUInteger)), @encode(NSUInteger));
//注册类
objc_registerClassPair(myClass);
//创建实例
id object = [[myClass alloc] init];
//为ivar设置值
[object setValue:@"china" forKey:@"address"];
[object setValue:@20 forKey:@"age"];
NSLog(@"address=%@,age=%@",[object valueForKey:@"address"],[object valueForKey:@"age"]);
//添加方法
Class class = [self class];
SEL selfInsMethod1 = @selector(instanceMethod1);
Method insMethod1 = class_getInstanceMethod(class, selfInsMethod1);
IMP impInsMethod1 = method_getImplementation(insMethod1);
const char *typeInsMethod1 = method_getTypeEncoding(insMethod1);
SEL selfNewInsMethod = @selector(newInsMethod);
BOOL isInsAdded = class_addMethod(myClass, selfNewInsMethod, impInsMethod1, typeInsMethod1);
if (!isInsAdded) {
NSLog(@"新实例方法添加失败!");
}
[object performSelector:selfNewInsMethod];
//当类或者它的子类的实例还存在,则不能调用objc_disposeClassPair方法
object = nil;
//销毁
objc_disposeClassPair(myClass);
}
-(void)instanceMethod1
{
NSLog(@"%s",__func__);
}
-(void)instanceMethod2
{
NSLog(@"%s",__func__);
}
+ (void)classMethod1
{
NSLog(@"%s",__func__);
}
+ (void)classMethod2
{
NSLog(@"%s",__func__);
}
Method Swizzling
Method Swizzling是iOS开发的黑魔法,可以灵活的对方法进行各种操作。
- 类第一次被调用加载的时候+ (void)load才会被调用,有且只有一次被调用。
- 只在 +load 中执行 swizzling 才是安全的。
+ (void)load
{
NSLog(@"%s",__func__);
//1、获取当前类名
Class class = [self class];
//2、获取方法名(选择器)
SEL selfInsMethod1 = @selector(instanceMethod1);
SEL selfInsMethod2 = @selector(instanceMethod2);
SEL selfClassMethod1 = @selector(classMethod1);
SEL selfClassMethod2 = @selector(classMethod2);
//3、根据方法名获取方法对象
Method insMethod1 = class_getInstanceMethod(class, selfInsMethod1);
Method insMethod2 = class_getInstanceMethod(class, selfInsMethod2);
Method classMethod1 = class_getClassMethod(class, selfClassMethod1);
Method classMethod2 = class_getClassMethod(class, selfClassMethod2);
//4、交换实例方法的实现
if (!insMethod1 || !insMethod2) {
NSLog(@"实例方法实现运行时交换失败!");
return;
}
method_exchangeImplementations(insMethod1, insMethod2);
//5、交换类方法的实现
if (!classMethod1 || !classMethod2) {
NSLog(@"类方法实现运行时交换失败!");
return;
}
method_exchangeImplementations(classMethod1, classMethod2);
//类方法和实例方法也可以交换,前提是没有代码错误
/* 重设类中方法的实现 */
//获取方法的实现
IMP impInsMethod1 = method_getImplementation(insMethod1);
IMP impInsMethod2 = method_getImplementation(insMethod2);
IMP impClassMethod1 = method_getImplementation(classMethod1);
IMP impClassMethod2 = method_getImplementation(classMethod2);
//重新设置方法的实现
method_setImplementation(insMethod1, impInsMethod2);
method_setImplementation(insMethod2, impInsMethod1);
method_setImplementation(classMethod1, impClassMethod2);
method_setImplementation(classMethod2, impClassMethod1);
//获取方法编码类型
const char *typeInsMethod1 = method_getTypeEncoding(insMethod1);
const char *typeInsMethod2 = method_getTypeEncoding(insMethod2);
const char *typeClassMethod1 = method_getTypeEncoding(insMethod1);
const char *typeClassMethod2 = method_getTypeEncoding(insMethod2);
//替换实例方法
class_replaceMethod(class, selfInsMethod1, impInsMethod2, typeInsMethod2);
class_replaceMethod(class, selfInsMethod2, impInsMethod1, typeInsMethod1);
//尝试替换类方法的实现,实际结果是无效的,class_replaceMethod只能替换实例方法的实现
class_replaceMethod(class, selfClassMethod1, impClassMethod2, typeClassMethod2);
class_replaceMethod(class, selfClassMethod2, impClassMethod1, typeClassMethod1);
/* 为类添加新的实例方法和类方法 */
SEL selfNewInsMethod = @selector(newInsMethod);
BOOL isInsAdded = class_addMethod(class, selfNewInsMethod, impInsMethod1, typeInsMethod1);
if (!isInsAdded) {
NSLog(@"新实例方法添加失败!");
}
}
网友评论