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> 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;
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 174,748评论 25 709
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,281评论 19 139
  • 前言 如何把这个世界变得美好?把你自己变得更美好 我们这篇博客继续来介绍Runtime在开发中的实际应用,通过开源...
    Dely阅读 2,197评论 4 16
  • 出门在外,一个人,其实,我们都是一个人,我们都一样,离开了家,我们都成了流浪者,流浪在异乡的流浪者。或许,现在的你...
    槿晨阅读 593评论 4 1
  • 一、什么是作用域 在 PHP 脚本的任何位置都可以声明变量,但是,声明变量的位置 直接影响访问变量的范围。这个可以...
    anonymous66阅读 430评论 0 6