iOS 通过协议将一个对象的属性赋给另一个对象实例和将一个实例的属性赋给另一个实例

直接上代码,注意该段代码的调用者是属性来源所指的对象

- (BOOL)copyValueToInstance:(nonnull __kindof NSObject *)obj
           bySingleProtocol:(nonnull Protocol *)protocol
                  whiteList:(nullable NSArray<NSString *> *)whiteList
                  blackList:(nullable NSArray<NSString *> *)blackList
{
     if (!protocol) {
#if DEBUG
            NSAssert(NO, @"protocol can't be nil");
#endif
            return NO;
    }
    
    if (![self conformsToProtocol:protocol]) {
#if DEBUG
        NSAssert(NO, @"make sure [self conformsToProtocol:protocol] be YES");
#endif
        return NO;
    }
    
    /// 获取协议中的属性
    unsigned int outCount;
    objc_property_t *propertyList;
//    if (@available(iOS 10.0, *)) {
//        //只有iOS 10 以上才支持获取optional属性
//        propertyList = protocol_copyPropertyList2(protocol, &outCount, NO, YES);
//    } else {
    //  只能获取required的属性
        propertyList = protocol_copyPropertyList(protocol, &outCount);
//    }
        
    NSMutableSet <NSString *> *propertyNamesFromProtocol = NSMutableSet.set;
    for (unsigned int i = 0; i < outCount; i++) {
        objc_property_t property = propertyList[i];
        const char *propertyName = property_getName(property);
        NSString *keyName = @(propertyName);
        [propertyNamesFromProtocol addObject:keyName];
    }
    if (propertyList) {
        free(propertyList);
    }
    
    /// 赋值
    for (NSString *targetPropertyName in propertyNamesFromProtocol) {
        SEL getSel = NSSelectorFromString(targetPropertyName);
        if (![self respondsToSelector:getSel]) {
#if DEBUG
            NSAssert(NO, @"make sure [self respondsToSelector:propertySel] be YES");
#endif
            return NO;
        }
       NSString *name = targetPropertyName.copy;
        if ([targetPropertyName hasPrefix:@"_"]) {
            name = [name substringFromIndex:1];
        }
        if (whiteList && ![whiteList containsObject:name]) {
            continue;
        }
        if (blackList && [blackList containsObject:name]) {
            continue;
        }
        NSString *selectorName = nil;
        if (name.length > 1) {
            selectorName = [NSString stringWithFormat:@"set%@%@:",[name substringWithRange:NSMakeRange(0, 1)].uppercaseString,[name substringFromIndex:1]];
        } else if (name.length == 1) {
           selectorName = [NSString stringWithFormat:@"set%@:",[name substringWithRange:NSMakeRange(0, 1)].uppercaseString];
        } else {
            continue;
        }
        
        SEL setSel = NSSelectorFromString(selectorName);
        if (![obj respondsToSelector:setSel]) {
#if DEBUG
            NSAssert(NO, @"make sure [obj respondsToSelector:setSel] be YES");
#endif
            return NO;
        }
        id value = [self valueForKey:targetPropertyName];
        if (value) {
          [obj setValue:value forKey:targetPropertyName];
        } else {
            IMP imp = [obj methodForSelector:setSel];
            void (*func)(id, SEL,id) = (void *)imp;
            func(obj, setSel,nil);
        }
    }
    return YES;
}

下面来看一下将一个实例的属性赋给另一个实例,前提是保证被赋值的实例完全支持来源实例的属性,该方法是内联方法,直接调用

id makeRemoteModelToCoreDataModel(id remoteModel,Class remoteDataClass,NSManagedObject *coreDataModel) {
    int i;
    unsigned int propertyCount = 0;
    objc_property_t *propertyList = class_copyPropertyList(remoteDataClass, &propertyCount);
    
    
    NSMutableArray *propertyNameList = [NSMutableArray array];
    for ( i=0; i < propertyCount; i++ ) {
        objc_property_t *thisProperty = propertyList + i;
        const char* propertyName = property_getName(*thisProperty);
        NSString *string = [NSString stringWithFormat:@"%s",propertyName];
        [propertyNameList addObject:string];
    }
    
    if (propertyNameList.count > 0) {
        [propertyNameList enumerateObjectsUsingBlock:^(NSString* key, NSUInteger idx, BOOL *stop) {
            id obj = [remoteModel valueForKey:key];
            if (obj) {
                if ([obj isKindOfClass:[NSString class]]) {
                    [coreDataModel setValue:obj forKey:key];
                }else {
                    NSData *objData = [NSKeyedArchiver archivedDataWithRootObject:obj];
                    [coreDataModel setValue:objData forKey:key];
                }
            }
            
        }];
        free(propertyList);
        return coreDataModel;
    }else return nil;
}

猜你喜欢

转载自blog.csdn.net/LIUXIAOXIAOBO/article/details/114531976