1、什么是RunTime
RunTime即运行时,objective-c是一种运行时的语言,什么是运行时呢,运行时就是在程序运行的时候才去确定我们的对象的类型和需要调用类和对象相对应的方法。
2、RunTime的用法
RunTime是在我们程序运行的时候才去确定我们的对象类型,和调用类与对象相对应的方法,属性等,所以我们可以在程序运行时去修改对象的属性,方法,修改类。
3、RunTime的体现
Animal *a = [[Animal alloc] init];
[a eat];//eat是一个实例方法
//底层运行的状态
[a performSelector:@selector(eat)];
objc_msgSend(a,@selector(eat));
//类方法也是一样
[Animal eat];
//底层运行的状态
Class animalClass = [Animal class];
[[Animal class] performSelector(eat)];
objc_msgSend(animalClass,@selector(eat));
从我们调用方法到底层运行的顺序是:实例方法的调用,然后是底层进行performSelector:然后到objc_msgSend。
4、RunTime的使用场景
- 1、使用RunTime进行方法的调换。
很常见的一个例子,在我们进行图片加载的时候,我们有这样一个需求,在加载图片之后判断这个图片是否为空,如果为空就输出error。我们首先想到就是使用分类来做,使用分类来做是没有问题的,前提是你还没有写多少代码,如果你的项目很庞大,不可能全部都重新修改你加载图片的方法吧,所以说使用分类不是不行,而是很不方便,那么我们需要怎么做呢?我们要坐的就是在分类里面对我们的方法进行替换。首先我们需要写一个我们用来替换原本加载图片的方法的方法。
+(UIImage *)judgeImageName:(NSString *)name{
UIImage \*image = [UIImage imageNamed:name];
if (image == nil) {
NSLog(@"error");
}
return image;
}
//然后在分类的+(void)load;方法进行方法的替换
+(void)load{
Method imageNamedMethod = class_getClassMethod([UIImage class],@selector(imageNamed));
Method judgeimageNamedMethod = class_getClassMethod([UIImage class],@selector(judgeImageName));
Method_exchangeImplementations(imageNamedMethod,judgeimageNamedMethod);
}
需要注意的是,我们使用了这种做法来替换方法之后不能去调用我们在分类中写的方法了,原因是你调用这个方法,这个方法调用原来的方法,原来的方法又去调用我们写的方法,这样的话就是一个死循环。
- 2、使用RunTime添加属性
分类是默认不能添加属性的,就算我们用@property声明了一个属性,该属性的set和get只会声明而不会实现。但是我们可以使用RunTime来为分类添加属性。
@property (nonatomic, strong)NSString *age
-(void)setAge:(NSString *)name{
objc_setAssociatedObject(self,@"age",age,OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
objc_setAssociatedObject
中的参数:
第一个参数为在哪里添加这个属性,这里就是self
第二个参数为属性名
第三个参数为属性值
第四个参数为属性的形式,一般有以下几种
OBJC_ASSOCIATION_ASSIGN = 0, //弱对象
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, //强引用,非原子性
OBJC_ASSOCIATION_COPY_NONATOMIC = 3, //指定对象赋值,非原子性
OBJC_ASSOCIATION_RETAIN = 01401, //强引用, 原子性
OBJC_ASSOCIATION_COPY = 01403 //指定对象赋值,原子性
}
-(NSString *)age{
objc_getAssociatedObject(self,@"age");
}
objc_getAssociatedObject
中的参数:
第一个参数为获取哪个对象里面关联的属性。
第二个参数为什么属性,其实就是属性名。