Runtime+AOP

问题: 开发中有个需求是Model中的任一属性被改变,都要通知,做缓存。
解决1
第一个想到的解决方式是重写Model的所有属性set方法。然后做通知逻辑。
显然他有弊端,如增加了属性,重复性的代码非常多。
我的解决方式:
runtime 获取所有属性set方法,并方法交换(AOP)。当set方法触发的时候触发交换的方法。以下代码

使用Aspects hook详情GitHub

/**
 hook 属性 set 方法,当属性被修改,触发block
 */
- (void)propertysHook {
    // 黑名单属性列表。注意: set 方法有冒号【:】
    NSArray *blackPropertyList = @[@"setPropertyChange:"];
    // 1 遍历属性列表
    for (NSString *selName in [self getObjectPropertyName]) {
        // 2 过滤不需要 hook 的属性,如:block 属性,父类与子类同名的属性 hook 会出问题,不要 hook.
        if ([blackPropertyList containsObject:selName]) {
            continue;
        }
        
        // 3 hook 属性
        SEL sel = NSSelectorFromString(selName);
        [self aspect_hookSelector:sel withOptions:AspectPositionAfter usingBlock:^(id aspectInfo){
            // 4 属性改变通知
            if (self.propertyChange) self.propertyChange();
        } error:NULL];
    }
}

/**
 获取对象所有属性 set 方法字符串

 @return set 方法字符串数组
 */
- (NSMutableArray *)getObjectPropertyName {
    NSMutableArray *propertieArray = [NSMutableArray new];
    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList([self class], &outCount);
    for (i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];
        NSString *propertyName = [[NSString alloc] initWithFormat:@"%s:", property_getName(property)];
        
        if (!propertyName.length) continue;
        
        NSString *firstPropertyName = [[propertyName substringToIndex:1] uppercaseString];
        NSString *lastPropertyName = [propertyName substringFromIndex:1];
        
        propertyName = [NSString stringWithFormat:@"set%@%@", firstPropertyName, lastPropertyName];
        [propertieArray addObject:propertyName];
    }
    free(properties);
    return propertieArray;
}

你可能感兴趣的:(Runtime+AOP)