iOS runtime

Runtime看这里 <objc/runtime.h>

2017-03-23  本文已影响189人  大虾咪

一 、Runtime 简介

二 、Runtime作用

//创建person对象  Person *p = [[Person  alloc]init];
// 让p发送消息
本质:让对象发送消息
objc_msgSend(p, @selector(eat));
objc_msgSend(p, @selector(run:),10);
用类名调用类方法,底层会自动把类名转换成类对象调用
本质:让类对象发送消息
objc_msgSend([Person calss], @selector(run));

2.交换方法 (开发使用场景:系统自带的方法功能不够,给系统自带的方法扩展一些功能,并且保持原有的功能。)

@implementation UIImage (Image)
// 加载分类到内存的时候调用
  +(void)load
{
// 交换方法
// 获取imageWithName方法地址
Method imageWithName = class_getClassMethod(self, @selector(imageWithName:));
// 获取imageWithName方法地址
Method imageName = class_getClassMethod(self, @selector(imageNamed:));
// 交换方法地址,相当于交换实现方式
method_exchangeImplementations(imageWithName, imageName);
}
// 不能在分类中重写系统方法imageNamed,因为会把系统的功能给覆盖掉,而且分类中不能调用super.
// 既能加载图片又能打印
+(instancetype)imageWithName:(NSString *)name
{
// 这里调用imageWithName,相当于调用imageName
UIImage *image = [self imageWithName:name];
if (image == nil) {
NSLog(@"加载空的图片");
}
return image;
}
@end

3.动态添加方法

 #import@interface ViewController ()
@end
@implementation ViewController
-(void)viewDidLoad {
[super viewDidLoad];
Person *p = [[Person alloc] init];
objc_msgSend(p, @selector(eat:) ,@10);
//    [p performSelector:@selector(eat:) withObject:@111];
#import "Person.h"#import@implementation Person

/*IMP imp

typedef void (*IMP)(void /* id, SEL, ... */ );
/*默认一个方法都有两个参数,self,_cmd,隐式参数
self:方法调用者
_cmd:调用方法的编号
id :param1 参数
*/
void eatFnv(id self ,SEL _cmd, id param1)
{
NSLog(@"调用eat %@ %@ %@",self,NSStringFromSelector(_cmd),param1);
}
// 动态添加方法,首先实现这个resolveInstanceMethod
//resolveInstanceMethod调用:当调用了方法没有实现时 就会调用
// resolveInstanceMethod作用:就知道哪些方法没有实现,从而动态添加方法
//sel:没有实现的方法
+(BOOL)resolveInstanceMethod:(SEL)sel{
NSLog(@"%@",NSStringFromSelector(sel));
//    if ([NSStringFromSelector(sel) isEqualToString:@"eat:"]) {
if (sel == @selector(eat:)) {
/*
cls:给哪个类添加方法
SEL:添加方法的方法编号是什么
IMP:方法实现,函数入口,函数名
type:方法类型    Type encodings
*/
class_addMethod(self, sel, (IMP)eatFnv, "v@:@");
return YES;
}
return [super resolveInstanceMethod:sel];
}

4.Runtime给分类添加属性

#import "NSObject+Objc.h"#import@implementation NSObject (Objc)
//定义常量 必须是C语言字符串
static char *PersonNameKey = "name";
- (void)setName:(NSString *)name{
/*
OBJC_ASSOCIATION_ASSIGN;            //assign策略
OBJC_ASSOCIATION_COPY_NONATOMIC;    //copy策略
OBJC_ASSOCIATION_RETAIN_NONATOMIC;  // retain策略
OBJC_ASSOCIATION_RETAIN;
OBJC_ASSOCIATION_COPY;
*/
/*
* id object 给哪个对象的属性赋值
const void *key 属性对应的key
id value  设置属性值为value
objc_AssociationPolicy policy  使用的策略,是一个枚举值,和copy,retain,assign是一样的,手机开发一般都选择NONATOMIC
objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
*/
objc_setAssociatedObject(self, PersonNameKey, name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
//    objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)name{
return objc_getAssociatedObject(self, @"name");
}

5.自动生成属性代码 分类拼写 Property(,, )NSStirng *name;

// 解决KVC报错
- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{
if ([key isEqualToString:@"id"]) {
_ID = [value integerValue];
}
// key:没有找到key
// value:没有找到key对应的值
NSLog(@"%@ %@",key,value);
}

6.字典转模型

方法1.KVC (遍历字典) 方法2.runtime(遍历属性名)

 // runtime:遍历模型中所有成员属性,去字典中查找
    // 属性定义在哪,定义在类,类里面有个属性列表(数组)
    // 遍历模型所有成员属性
    // ivar:成员属性
    // class_copyIvarList:把成员属性列表复制一份给你
    // Ivar *:指向Ivar指针
    // Ivar *:指向一个成员变量数组
    // class:获取哪个类的成员属性列表
    // count:成员属性总数
    unsigned int count = 0;
    Ivar *ivarList = class_copyIvarList(self, &count);
    for (int i = 0 ; i < count; i++) {
        // 获取成员属性
        Ivar ivar = ivarList[i];
        // 获取成员名
        NSString *propertyName = [NSString stringWithUTF8String:ivar_getName(ivar)];
        ;
        // 成员属性类型
        NSString *propertyType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
}
上一篇 下一篇

猜你喜欢

热点阅读