重写KVC

Posted 佛系码农

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重写KVC相关的知识,希望对你有一定的参考价值。

#import "NSObject+WQKVC.h"
#import <objc/runtime.h>
/**
 KVC
    首先调用的方法顺序:
        |-  setter: setKey  -> setIsKey
        |-  getter: getKey  -> key  -> isKey
        |-  - (Bool)accessInstanceVariablesDirectly 不为NO ,默认为YES
 查找成员变量的顺序:
        |-  _key  -> _isKey  -> key   -> isKey
 **/

@implementation NSObject (WQKVC)
- (void)WQ_setValue:(id)value forKey:(NSString *)key
{
    //判断key的合法性
    if (key.length == 0 || key == nil) {
        return;
    }
    NSString *setKey = [NSString stringWithFormat:@"set%@",key.capitalizedString];
    SEL setKeyMethod = NSSelectorFromString(setKey);
    if ([self respondsToSelector:setKeyMethod]) {
        [self performSelector:setKeyMethod withObject:value];
        return;
    }
    
    NSString *setIsKey = [NSString stringWithFormat:@"setIs%@",key.capitalizedString];
    SEL setIsKeyMethod = NSSelectorFromString(setIsKey);
    if ([self respondsToSelector:setIsKeyMethod]) {
        [self performSelector:setIsKeyMethod withObject:value];
        return;
    }
    
    if (![self.class accessInstanceVariablesDirectly]) {
        NSException *exception = [NSException exceptionWithName:@"WQKVC Exception" reason:@"不能设置为NO!" userInfo:nil];
        @throw exception;
        return;
    }
    
    unsigned int count = 0;
    Ivar *ivasList = class_copyIvarList([self class], &count);
    // _Key
    for (int i = 0; i < count ; i ++) {
        NSString *keyStr = [NSString stringWithUTF8String:ivar_getName(ivasList[i])];
        if ([keyStr isEqualToString:[NSString stringWithFormat:@"_%@",key.capitalizedString]]) {
            object_setIvar(self, ivasList[i], value);
            free(ivasList);
            return;
        }
    }
    
    // _isKey
    for (int i = 0; i < count ; i ++) {
        NSString *keyStr = [NSString stringWithUTF8String:ivar_getName(ivasList[i])];
        if ([keyStr isEqualToString:[NSString stringWithFormat:@"_is%@",key.capitalizedString]]) {
            object_setIvar(self, ivasList[i], value);
            free(ivasList);
            return;
        }
    }
    
    // Key
    for (int i = 0; i < count ; i ++) {
        NSString *keyStr = [NSString stringWithUTF8String:ivar_getName(ivasList[i])];
        if ([keyStr isEqualToString:key]) {
            object_setIvar(self, ivasList[i], value);
            free(ivasList);
            return;
        }
    }
    
    // isKey
    for (int i = 0; i < count ; i ++) {
        NSString *keyStr = [NSString stringWithUTF8String:ivar_getName(ivasList[i])];
        if ([keyStr isEqualToString:[NSString stringWithFormat:@"is%@",key.capitalizedString]]) {
            object_setIvar(self, ivasList[i], value);
            free(ivasList);
            return;
        }
    }
    
    // 异常处理!
    [self setValue:value forUndefinedKey:key];
    free(ivasList);
}

- (id)WQ_valueForKey:(NSString *)key
{
    if (key.length == 0 || key == nil) {
        return nil;
    }
    
    // getKey -- Method
    NSString *getKey = [NSString stringWithFormat:@"get%@",key.capitalizedString];
    SEL getKeyMethod = NSSelectorFromString(getKey);
    if ([self respondsToSelector:getKeyMethod]) {
        return [self performSelector:getKeyMethod withObject:nil];
    }
    
    // key -- Method
    SEL KeyMethod = NSSelectorFromString(key);
    if ([self respondsToSelector:getKeyMethod]) {
        return [self performSelector:KeyMethod withObject:nil];
    }

    // isKey -- Method
    NSString *isKey = [NSString stringWithFormat:@"is%@",key.capitalizedString];
    SEL isKeyMethod = NSSelectorFromString(isKey);
    if ([self respondsToSelector:isKeyMethod]) {
        return [self performSelector:isKeyMethod withObject:nil];
    }
    
    if (![self.class accessInstanceVariablesDirectly]) {
        NSException *exception = [NSException exceptionWithName:@"WQKVC Exception" reason:@"不能设置为NO!" userInfo:nil];
        @throw exception;
        return nil;
    }
    
    unsigned int count = 0;
    Ivar *ivasList = class_copyIvarList([self class], &count);
    // _Key
    for (int i = 0; i < count ; i ++) {
        NSString *keyStr = [NSString stringWithUTF8String:ivar_getName(ivasList[i])];
        if ([keyStr isEqualToString:[NSString stringWithFormat:@"_%@",key.capitalizedString]]) {
            Ivar ivar_temp = ivasList[i];
            free(ivasList);
            return object_getIvar(self, ivar_temp);
        }
    }
    
    // _isKey
    for (int i = 0; i < count ; i ++) {
        NSString *keyStr = [NSString stringWithUTF8String:ivar_getName(ivasList[i])];
        if ([keyStr isEqualToString:[NSString stringWithFormat:@"_is%@",key.capitalizedString]]) {
            Ivar ivar_temp = ivasList[i];
            free(ivasList);
            return object_getIvar(self, ivar_temp);
        }
    }
    
    // Key
    for (int i = 0; i < count ; i ++) {
        NSString *keyStr = [NSString stringWithUTF8String:ivar_getName(ivasList[i])];
        if ([keyStr isEqualToString:key]) {
            Ivar ivar_temp = ivasList[i];
            free(ivasList);
            return object_getIvar(self, ivar_temp);
        }
    }
    
    // isKey
    for (int i = 0; i < count ; i ++) {
        NSString *keyStr = [NSString stringWithUTF8String:ivar_getName(ivasList[i])];
        if ([keyStr isEqualToString:[NSString stringWithFormat:@"is%@",key.capitalizedString]]) {
            Ivar ivar_temp = ivasList[i];
            free(ivasList);
            return object_getIvar(self, ivar_temp);
        }
    }

    
    free(ivasList);
    return [self valueForUndefinedKey:key];
    
}


@end

 

以上是关于重写KVC的主要内容,如果未能解决你的问题,请参考以下文章

KVC的底层实现原理

ios开发UI篇—Kvc简单介绍

推进学说代码片段

iOS开发UI篇—KVC简单介绍

java 代码片段

swift kvc赋值