浅谈runtime

什么是runtime

1->runtime是一套底层的C语言API(包含很多强大实用的C语言数据类型、C语言函数)

2->实际上,平时我们编写的OC代码,底层都是基于runtime实现的

也就是说,平时我们编写的OC代码,最终都是转成了底层的runtime代码(C语言代码)

runtime有啥用?

1> 能动态产生一个类、一个成员变量、一个方法

2> 能动态修改一个类、一个成员变量、一个方法

3> 能动态删除一个类、一个成员变量、一个方法


常见的函数、头文件

#import <objc/runtime.h> : 成员变量、类、方法

Ivar * class_copyIvarList : 获得某个类内部的所有成员变量

Method * class_copyMethodList : 获得某个类内部的所有方法

Method class_getInstanceMethod : 获得某个实例方法(对象方法,减号-开头)

Method class_getClassMethod : 获得某个类方法(加号+开头)

method_exchangeImplementations : 交换2个方法的具体实现


#import <objc/message.h> : 消息机制

objc_msgSend(....)


首先自定义一个类型

@interface LSPerson : NSObject
@property (nonatomic, copy) NSString *name;
@property(nonatomic,assign) int age;
@end

- (void)viewDidLoad {
    [super viewDidLoad];
    unsigned int count;
    Ivar *ivars= class_copyIvarList([LSPerson class], &count);
    for (int i=0; i<count ; i++) {
        const char *name= ivar_getName(ivars[i]);
        const char *type=ivar_getTypeEncoding(ivars[i]);
        NSLog(@"name:%s type:%s",name,type);
    }
    NSLog(@"count:%d",count);
    
    unsigned int methodCount;
    Method *methods =class_copyMethodList([LSPerson class], &methodCount);
    for (int i=0; i<methodCount ; i++) {
        NSString *methodName= NSStringFromSelector( method_getName(methods[i]));
        NSLog(@"method:%@",methodName);
    }
    NSLog(@"methodCount:%d",methodCount);
}



打印结果,可以看出通过以上方法就可获取一个类的所有成员变量和方法,当然还可以获取属性等这里就不一一列举,实际上MJExtesion就是利用runtime先获取所有的成员变量然后从字典中找对应的键值,当然还有很多许多需要注意的地方,不是那么容易就实现的

2015-11-04 13:02:58.023 runtime[16409:538012] name:_name type:@"NSString"
2015-11-04 13:02:58.024 runtime[16409:538012] name:_age type:i
2015-11-04 13:02:58.024 runtime[16409:538012] count:2
2015-11-04 13:02:58.024 runtime[16409:538012] method:age
2015-11-04 13:02:58.024 runtime[16409:538012] method:setAge:
2015-11-04 13:02:58.024 runtime[16409:538012] method:.cxx_destruct
2015-11-04 13:02:58.024 runtime[16409:538012] method:name
2015-11-04 13:02:58.024 runtime[16409:538012] method:setName:
2015-11-04 13:02:58.025 runtime[16409:538012] count:5



利用runtime来实现交换两个方法,

如果公司的项目做了很久突然要改需求,做某系统的适配,这时候显示的图片就要换了,但是以前的代码又太多没法改,所以我们只能把系统方法换掉,利用如下方法即可实现

#import <UIKit/UIKit.h>
#import <objc/runtime.h>
@implementation UIImage (Extension)
+(void)load
{
    Method originMehtod = class_getClassMethod(self, @selector(imageNamed:));
    Method newMehtod = class_getClassMethod(self, @selector(imageWithName:));
    // 交换2个方法的实现
    method_exchangeImplementations(newMehtod, originMehtod);
}

+(UIImage *)imageWithName:(NSString *)name
{
    BOOL IOS8=[[UIDevice currentDevice].systemVersion doubleValue]>=8.0;
    UIImage *image=nil;
    if (IOS8) {
        NSString *newName=[name stringByAppendingString:@"_os8"];
        image=[self imageWithName:newName];
    }
    if (image==nil) {
        [self imageWithName:name];
    }
    return image;
}
@end


在调试时我们就经常会遇到objectAtIndex bounds 错误就是下标越界了,还有一种情况就是object can not be nil就是不能往数组里添加nil这时候就需要替换系统自带的方法

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@implementation NSObject (Extension)
/**
 *交换某个类的对象方法
 */
+(void)swizzleInstanceMethod:(Class)class originalSelector:(SEL)originalSelector newSelector:(SEL)newSelectoer
{
    Method originalMethod=class_getInstanceMethod(class, originalSelector);
    Method newMethod=class_getInstanceMethod(class, newSelectoer);
    method_exchangeImplementations(originalMethod, newMethod);
}
/**
 *交换某个类的类方法
 */
+(void)swizzleClassMethod:(Class)class originalSelector:(SEL)originalSelector newSelector:(SEL)newSelectoer
{
    Method originalMethod=class_getClassMethod(class, originalSelector);
    Method newMethod=class_getClassMethod(class, newSelectoer);
    method_exchangeImplementations(originalMethod, newMethod);
}
@end


@implementation NSMutableArray(Extension)

/**
 *当程序启动时会把所有的类都加载到内存中,只会调用一次load方法
 */
+(void)load
{
    [self swizzleInstanceMethod:NSClassFromString(@"__NSArrayM") originalSelector:@selector(addObject:) newSelector:@selector(ls_AddObject:)];
    [self swizzleInstanceMethod:NSClassFromString(@"__NSArrayM") originalSelector:@selector(objectAtIndex:) newSelector:@selector(ls_ObjectAtIndex:)];
}
-(id)ls_ObjectAtIndex:(NSUInteger)index
{
    if (index<self.count) {
        return [self ls_ObjectAtIndex:index];//注意一下所有方法里都不会造成循环引用,因为此时的方法已经替换成了系统的<span style="font-family: Arial, Helvetica, sans-serif;">objectAtIndex:方法</span>

    }else{
        return nil;
    }
}
-(void)ls_AddObject:(id)obj
{
    if (obj!=nil) {
        [self ls_AddObject:obj];
    }
}

@end
@implementation NSArray(Extension)

+(void)load
{
    [self swizzleInstanceMethod:NSClassFromString(@"__NSArrayI") originalSelector:@selector(objectAtIndex:) newSelector:@selector(ls_ObjectAtIndex:)];

}
-(id)ls_ObjectAtIndex:(NSUInteger)index
{
    if (index<self.count) {
        return [self ls_ObjectAtIndex:index];
    }else{
        return nil;
    }
}
@end




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值