iOS底层原理:KVC简析&自定义

2021-07-05  本文已影响0人  木槿WEIXIAO

简介

常用API

- (void)setValue:(nullable id)value forKey:(NSString *)key;
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
- (nullable id)valueForKey:(NSString *)key;
- (nullable id)valueForKeyPath:(NSString *)keyPath;

原理

取值原理

设值原理

自定义KVC

#import "NSObject+YX_KVC.h"
#import <objc/runtime.h>
@implementation NSObject (YX_KVC)

- (id)yx_valueForKey:(NSString *)key
{
    if (key == nil || key.length == 0) {
        return nil;
    }
    
    NSString *Key = key.capitalizedString;
    NSString *getKey = [NSString stringWithFormat:@"get%@",Key];
    NSString *countOfKey = [NSString stringWithFormat:@"countOf%@",Key];
    NSString *objectInKeyAtIndex = [NSString stringWithFormat:@"objectIn%@AtIndex:",Key];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    if ([self respondsToSelector:NSSelectorFromString(getKey)]) {
        return [self performSelector:NSSelectorFromString(getKey)];
    }else if ([self respondsToSelector:NSSelectorFromString(key)]){
        return [self performSelector:NSSelectorFromString(key)];
    }else if ([self respondsToSelector:NSSelectorFromString(countOfKey)]){
        if ([self respondsToSelector:NSSelectorFromString(objectInKeyAtIndex)]) {
            int num = (int)[self performSelector:NSSelectorFromString(countOfKey)];
            NSMutableArray *mArray = [NSMutableArray arrayWithCapacity:1];
            for (int i = 0; i<num-1; i++) {
                num = (int)[self performSelector:NSSelectorFromString(countOfKey)];
            }
            for (int j = 0; j<num; j++) {
                id objc = [self performSelector:NSSelectorFromString(objectInKeyAtIndex) withObject:@(num)];
                [mArray addObject:objc];
            }
            return mArray;
        }
    }
#pragma clang diagnostic pop
    
    if (![[self class] accessInstanceVariablesDirectly]) {
        @throw [NSException exceptionWithName:@"YXUnknowKey" reason:[NSString stringWithFormat:@"找不到%@的相关get方法",key] userInfo:nil];
    }
    
    NSMutableArray *ivarNameArray = [self getIvarsNameArray];
    NSString *_key = [NSString stringWithFormat:@"_%@",key];
    NSString *_isKey = [NSString stringWithFormat:@"_is%@",Key];
    NSString *isKey = [NSString stringWithFormat:@"is%@",Key];
    if ([ivarNameArray containsObject:_key]) {
        Ivar ivar = class_getInstanceVariable([self class], _key.UTF8String);
        return object_getIvar(self, ivar);
    }
    if ([ivarNameArray containsObject:_isKey]) {
        Ivar ivar = class_getInstanceVariable([self class], _isKey.UTF8String);
        return object_getIvar(self, ivar);
    }
    if ([ivarNameArray containsObject:key]) {
        Ivar ivar = class_getInstanceVariable([self class], key.UTF8String);
        return object_getIvar(self, ivar);
    }
    if ([ivarNameArray containsObject:isKey]) {
        Ivar ivar = class_getInstanceVariable([self class], isKey.UTF8String);
        return object_getIvar(self, ivar);
    }
    
    return @"";
}

- (void)yx_setValue:(id)value forKey:(NSString *)key
{
    if (key == nil || key.length == 0) {
        return;
    }
    
    NSString *Key = key.capitalizedString;
    NSString *setKey = [NSString stringWithFormat:@"set%@",Key];
    NSString *_setKey = [NSString stringWithFormat:@"_set%@",Key];
    NSString *setIsKey = [NSString stringWithFormat:@"setIs%@",Key];
    
    if ([self yx_performSelectorWithSelName:setKey value:value]) {
        return;
    }
    if ([self yx_performSelectorWithSelName:_setKey value:value]) {
        return;
    }
    if ([self yx_performSelectorWithSelName:setIsKey value:value]) {
        return;
    }
    
    if (![[self class] accessInstanceVariablesDirectly]) {
        @throw [NSException exceptionWithName:@"YXUnknowKey" reason:[NSString stringWithFormat:@"找不到%@的相关set方法",key] userInfo:nil];
    }
    
    NSMutableArray *ivarNameArray = [self getIvarsNameArray];
    NSString *_key = [NSString stringWithFormat:@"_%@",key];
    NSString *_isKey = [NSString stringWithFormat:@"_is%@",Key];
    NSString *isKey = [NSString stringWithFormat:@"is%@",Key];
    
    if ([ivarNameArray containsObject:_key]) {
        Ivar ivar = class_getInstanceVariable([self class], _key.UTF8String);
        object_setIvar(self, ivar, value);
        return;
    }
    if ([ivarNameArray containsObject:_isKey]) {
        Ivar ivar = class_getInstanceVariable([self class], _isKey.UTF8String);
        object_setIvar(self, ivar, value);
        return;
    }
    if ([ivarNameArray containsObject:isKey]) {
        Ivar ivar = class_getInstanceVariable([self class], isKey.UTF8String);
        object_setIvar(self, ivar, value);
        return;
    }
    
    if (![[self class] accessInstanceVariablesDirectly]) {
        @throw [NSException exceptionWithName:@"YXUnknowKey" reason:[NSString stringWithFormat:@"找不到%@的相关set方法",key] userInfo:nil];
    }
}
- (BOOL)yx_performSelectorWithSelName:(NSString *)name value:(id)value
{
    if ([self respondsToSelector:NSSelectorFromString(name)]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        [self performSelector:NSSelectorFromString(name) withObject:value];
#pragma clang diagnostic pop
        return YES;
    }
    return NO;
}

- (NSMutableArray *)getIvarsNameArray
{
    NSMutableArray *nameArray = [[NSMutableArray alloc] init];
    unsigned int count = 0;
    Ivar *ivars = class_copyIvarList([self class], &count);
    for (int i = 0; i < count; i ++) {
        Ivar ivar = ivars[i];
        const char * ivarName = ivar_getName(ivar);
        NSString *ivarStr = [NSString stringWithUTF8String:ivarName];
        [nameArray addObject:ivarStr];
    }
    return nameArray;
}
@end

上一篇 下一篇

猜你喜欢

热点阅读