runtime总结

runtime: 运行时,俗称消息机制,对于C语言而言,函数调用在编译的时候就已经决定要调用哪个函数,对OC而言编译的时候不能真正决定要调用哪个函数,是有在真正运行的时候根据函数的名字来确定调用哪个函数,这就是动态调用过程。 同时,OC在编译过程中可以调用任何函数,即使函数未实现,只有当运行的时候才会报错,但是对于C而言,则不会调用未实现的函数,调用就会报错,每一个OC的方法底层下面都会对应一个runtime方法,类似java中的虚拟机的概念。 对应的消息转发机制调用流程: OC向一个对象发送消息时,runtime库会根据对象的isa指针找到该对象对应的类或者是其父类中查找方法注册方法编号, 根据方法编号查找,找到只是最终函数实现地址,根据地址去方法区调用对应的函数,每一个对象内部都有一个isa指针,这个指针是指向他的真实类型,根据这个指针就知道将来调用哪个类的方法

runtime作用: 动态的交换两个方法的实现: 当然这里不建议使用, 有用过masonry的都知道,在实现圆角的时候并不像我们正常使用代码的时候那样方便仍需调用

layoutSublayersOfLayer:

代码示例:

-(void)load
{ SEL ori = @selector(layoutSublayersOfLayer:);

SEL new = NSSelectorFromString([@"test" stringByAppendingString:NSStringFromSelector(ori)]); switch_Method(self, ori, new);

}

-(void)switchMethod(Class c, SEL orig, SEL new)
{

Method origMethod = classgetInstanceMethod(c, orig); Method newMethod = class_getInstanceMethod(c, new);

method_exchangeImplementations(origMethod, newMethod);

}

这里需要在load中实现,因此大家只需要了解即可,在使用中不建议使用

动态的添加属性: 这里的用法大家应该都比较了解,举个列子,用在分类中,分类中是无法新增属性的,因此可以使用runtime,动态的添加属性,用法如下

-(void)setName:(NSString *)name
{
objcsetAssociatedObject(self, @”name”, name, OBJCASSOCIATIONRETAINNONATOMIC);
}

-(NSString *)name
{
return objc_getAssociatedObject(self, @”name”);
}

实现字典转模型的自动转换:

如果你有看过一些模型解析应该会了解,这个用法,这里只做简单的原理说明:
static BOOL PPValidateAndSetValue (id obj,NSString *key,id value,BOOL forceUpdate,NSError **error)
{ _autoreleasing id validateValue = value;
@try {
if ([obj validateValue:&validateValue forKey:key error:error])
{
if (forceUpdate || value != validateValue)

    {
        [obj setValue:validateValue forKey:key];
    }
    }
}
@catch (NSException *exception)
{
    if (error != NULL)
    { }
}

}

  • (NSString *)description
    {
    return [self dictionaryWithValuesForKeys:self.class.propertyKeys].description;
    }

  • (NSArray *)propertyKeys
    {
    NSArray *cachedKeys = objcgetAssociatedObject(self, &PPModelCachedPropertyKeysKey);
    if (cachedKeys != nil)return cachedKeys;
    NSArray *keys = [self ppmodelProperty:self];
    objc_setAssociatedObject(self, PPModelCachedPropertyKeysKey, keys, OBJC_ASSOCIATION_COPY);
    return keys;
    }

-(NSDictionary *)ppdictionaryWithJSON:(id)json {

if (!json || json == (id)kCFNull) return nil;

NSDictionary *dic = nil; NSData *jsonData = nil;

if ([json isKindOfClass:[NSDictionary class]])
{
    dic = json;
} else if([json isKindOfClass:[NSString class]])
{
    jsonData = [(NSString *)json dataUsingEncoding:NSUTF8StringEncoding];
}else if([json isKindOfClass:[NSData class]]) {
    jsonData = json;
} if (jsonData) {
    dic = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:NULL];

    if (![dic isKindOfClass:[NSDictionary class]])
        dic = nil;
} return dic;

}

+(instancetype)pp_modelWithJSON:(id)json withModelClass:(id)modelClass
{
NSDictionary *dic = [self ppdictionaryWithJSON:json];
id objList = [[modelClass alloc] init];
NSArray *proList = [self ppmodelProperty:modelClass];
[dic enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop)
{
if ([proList containsObject:key])
{ [objList setValue:obj forKey:key];
} }];
return objList;
}

+(NSArray *)ppmodelProperty:(id)modelClass
{
unsigned int count = 0;
objcpropertyt *property = classcopyPropertyList([modelClass class], &count);
NSMutableArray *propertyArray = @[].mutableCopy;
for (unsigned int i = 0; i < count; i ++)
{
objcpropertyt pty = property[i];
const char *cName = propertygetName(pty);
NSString *objcStr = [NSString stringWithCString:cName encoding:NSUTF8StringEncoding];
[propertyArray addObject:objcStr]; }
free(property);
return propertyArray.copy;
}

-(BOOL)validate:(NSError **)error
{
for ( NSString *key in self.class.propertyKeys)
{
id value = [self valueForKey:key];
BOOL success = PPValidateAndSetValue(self, key, value, NO, error);
if (!success)
return NO;
}
return YES;
}
当然,这里面可能会复杂的多,要考虑的东西也比较多,但是原理如此

发送消息:

消息发送,当然前面已经说过了,每段OC代码底层都会对应着一个runtime,
因此发送消息
objc_msgSend(class,@selector(method:),object);
具体实现: 首先根据isa指针找到所属的类, 然后找到类的cache列表,如果没有则会继续找类的方法列表 其次如果能找到与选择子名称相符的方法,就会跳转至实现代码部分,如果找不到,就沿着继承体系继续向上查找,如果能找到与选择子名称相符的方法,找不到,就会继续执行消息转发

猜你喜欢

转载自blog.csdn.net/sinat_29998157/article/details/77082784