使用反射重构代码(OC)

作者: sixleaves | 来源:发表于2016-12-23 11:46 被阅读221次

前沿

OC里的runtime就是Java里反射的概念。关于OC中runtime的应用早就被玩烂了, 今天介绍关于用发射重构代码的例子.
首先介绍两个函数,功能分别如下

  • 获取遵守遵守某个协议的所有类(RMClassesThatConformsToProtocol)
  • 获取继承某个类的所有类(RMClassesThatBaseClass)

实现思路

获取遵守某个协议的所有类
  • 利用反射机制, 获取所有注册的类的个数。
    int numClasses = objc_getClassList(NULL, 0);
  • 根据Class类的大小, 分配对应的内存大小。
    classes = (__unsafe_unretained Class*)malloc(sizeof(Class) * numClasses);
  • 利用反射机制, 获取所有的类。
    numClasses = objc_getClassList(classes, numClasses);
  • 遍历所有的类, 找出遵守某个协议的类加入数组
 for (int index = 0; index < numClasses; index++) { 
        Class aClass = classes[index]; 
        if (class_conformsToProtocol(aClass, protocol))  { 
                  [collection addObject:aClass];
         } 
}

整体代码:

NSArray<Class> *RMClassesThatConformsToProtocol(Protocol *protocol)
{
    Class *classes = NULL;
    NSMutableArray *collection = [NSMutableArray array];
    int numClasses = objc_getClassList(NULL, 0);
    if (numClasses == 0 ) {
        return @[];
    }
    
    classes = (__unsafe_unretained Class*)malloc(sizeof(Class) * numClasses);
    numClasses = objc_getClassList(classes, numClasses);
    for (int index = 0; index < numClasses; index++) {
        Class aClass = classes[index];
        if (class_conformsToProtocol(aClass, protocol)) {
            [collection addObject:aClass];
        }
    }
    free(classes);
    return collection.copy;
}
获取继承某个类的所有类
NSArray<Class> *RMClassesThatBaseClass(Class baseClass)
{
    Class *classes = NULL;
    NSMutableArray *collection = [NSMutableArray array];
    int numClasses = objc_getClassList(NULL, 0);
    if (numClasses == 0 ) {
        return @[];
    }
    NSString *bcls = NSStringFromClass(baseClass);
    classes = (__unsafe_unretained Class*)malloc(sizeof(Class) * numClasses);
    numClasses = objc_getClassList(classes, numClasses);
    for (int index = 0; index < numClasses; index++) {
        Class aClass = classes[index];
        Class superClass = class_getSuperclass(aClass);
        NSString *cls = NSStringFromClass(aClass);
        if ([cls isEqualToString:bcls]) continue;
        NSString *supercls =  NSStringFromClass(superClass);
        if ([supercls isEqualToString: bcls]) {
            [collection addObject:aClass];
        }
    }
    free(classes);
    return collection.copy;
}

重构前的代码

重构前一共有126行代码, 并且每增加一个类, 懂得来手动添加相应的注册,造成两个问题

  • 代码很冗余,很多的重复代码。
  • 很容易忘记添加注册。
    // register API
    [_httpServer addHandlerForMethod:@"GET" path:@"/loadDriver" requestClass:[RMRequest class] processBlock:^GCDWebServerResponse *(__kindof GCDWebServerRequest *request) {
                                    RMHandler *handler = [RMHandlerManager createHandlerWithRequest: request];
                                   [handler start];
        
                                   NSMutableDictionary *json = [NSMutableDictionary dictionary];
                                   [json setObject:handler.sessionID forKey:kRMSessionIDKey];
                                   [json setObject:request.query forKey:@"query"];
                                   return [GCDWebServerDataResponse responseWithJSONObject:json];
    }];
    
    [_httpServer addHandlerForMethod:@"GET" path:@"/startApp" requestClass:[RMRequest class] processBlock:^GCDWebServerResponse *(__kindof GCDWebServerRequest *request) {
        RMHandler *handler = [RMHandlerManager createHandlerWithRequest: request];
        [handler start];
        
        NSMutableDictionary *json = [NSMutableDictionary dictionary];
        [json setObject:handler.sessionID forKey:kRMSessionIDKey];
        [json setObject:request.query forKey:@"query"];
        return [GCDWebServerDataResponse responseWithJSONObject:json];
    }];
    
    [_httpServer addHandlerForMethod:@"GET" path:@"/startMonkey" requestClass:[RMRequest class] processBlock:^GCDWebServerResponse *(__kindof GCDWebServerRequest *request) {
        RMHandler *handler = [RMHandlerManager createHandlerWithRequest: request];
        [handler start];
        
        NSMutableDictionary *json = [NSMutableDictionary dictionary];
        [json setObject:handler.sessionID forKey:kRMSessionIDKey];
        [json setObject:request.query forKey:@"query"];
        return [GCDWebServerDataResponse responseWithJSONObject:json];
    }];
    
    
    [_httpServer addHandlerForMethod:@"GET" path:@"/typeText" requestClass:[RMRequest class] processBlock:^GCDWebServerResponse *(__kindof GCDWebServerRequest *request) {
        RMHandler *handler = [RMHandlerManager createHandlerWithRequest: request];
        [handler start];
        
        NSMutableDictionary *json = [NSMutableDictionary dictionary];
        if (handler) {
            [json setObject:handler.sessionID forKey:kRMSessionIDKey];
            [json setObject:handler.result == nil?@{}:handler.result forKey:kRMQueryKey];
        }else {
            NSLog(@"没有创建相应和路由对象");
        }
        
        return [GCDWebServerDataResponse responseWithJSONObject:json];
    }];
    
    
    [_httpServer addHandlerForMethod:@"GET" path:@"/findElementsByClassname" requestClass:[RMRequest class] processBlock:^GCDWebServerResponse *(__kindof GCDWebServerRequest *request) {
        RMHandler *handler = [RMHandlerManager createHandlerWithRequest: request];
        [handler start];
        
        NSMutableDictionary *json = [NSMutableDictionary dictionary];
        if (handler) {
            [json setObject:handler.sessionID forKey:kRMSessionIDKey];
            [json setObject:handler.result == nil?@{}:handler.result forKey:kRMQueryKey];
        }else {
            NSLog(@"没有创建相应和路由对象");
        }

        return [GCDWebServerDataResponse responseWithJSONObject:json];
    }];
    
    
    
    [_httpServer addHandlerForMethod:@"GET" path:@"/clearText" requestClass:[RMRequest class] processBlock:^GCDWebServerResponse *(__kindof GCDWebServerRequest *request) {
        RMHandler *handler = [RMHandlerManager createHandlerWithRequest: request];
        [handler start];
        
        NSMutableDictionary *json = [NSMutableDictionary dictionary];
        if (handler) {
            [json setObject:handler.sessionID forKey:kRMSessionIDKey];
            [json setObject:handler.result == nil?@{}:handler.result forKey:kRMQueryKey];
        }else {
            NSLog(@"没有创建相应和路由对象");
        }
        
        return [GCDWebServerDataResponse responseWithJSONObject:json];
    }];
    
    
    // tap action
    [_httpServer addHandlerForMethod:@"GET" path:@"/tap" requestClass:[RMRequest class] processBlock:^GCDWebServerResponse *(__kindof GCDWebServerRequest *request) {
        RMHandler *handler = [RMHandlerManager createHandlerWithRequest: request];
        [handler start];
        NSMutableDictionary *json = [NSMutableDictionary dictionary];
        if (handler) {
            [json setObject:handler.sessionID forKey:kRMSessionIDKey];
            [json setObject:handler.result == nil?@{}:handler.result forKey:kRMQueryKey];
        }else {
            NSLog(@"没有创建相应和路由对象");
        }
        return [GCDWebServerDataResponse responseWithJSONObject:json];
    }];
    
    // swipe action
    [_httpServer addHandlerForMethod:@"GET" path:@"/swipe" requestClass:[RMRequest class] processBlock:^GCDWebServerResponse *(__kindof GCDWebServerRequest *request) {
        RMHandler *handler = [RMHandlerManager createHandlerWithRequest: request];
        [handler start];
        NSMutableDictionary *json = [NSMutableDictionary dictionary];
        if (handler) {
            [json setObject:handler.sessionID forKey:kRMSessionIDKey];
            [json setObject:handler.result == nil?@{}:handler.result forKey:kRMQueryKey];
        }else {
            NSLog(@"没有创建相应和路由对象");
        }
        return [GCDWebServerDataResponse responseWithJSONObject:json];
    }];
    
    
    // /inspector
    [_httpServer addHandlerForMethod:@"GET" path:@"/inspector" requestClass:[RMRequest class] processBlock:^GCDWebServerResponse *(__kindof GCDWebServerRequest *request) {
        RMHandler *handler = [RMHandlerManager createHandlerWithRequest: request];
        [handler start];
        
        NSMutableDictionary *json = [NSMutableDictionary dictionary];
        if (handler) {
            [json setObject:handler.sessionID forKey:kRMSessionIDKey];
            [json setObject:handler.result == nil?@{}:handler.result forKey:kRMQueryKey];
        }else {
            NSLog(@"没有创建相应和路由对象");
        }
        
        return [GCDWebServerDataResponse responseWithJSONObject:json];
    }];

重构背景

所有Handler对象都继承自RMHandler, 并且RMHandler提供了start方法用于调用各个Handler对象的功能,所以Handler的之类都要重写该方法,实现对应的功能。通过这样构架,对于上面的代码,就只有path参数不一致。其他几乎是重复的代码。

重构思路

重构并不是一下子就能做的,当你代码越写越多,会发现,上面的注册方法大同小异,只有path参数不同,此时就该考虑重构,将这部分重复代码抽取掉。
使用我上面提供的两个函数功能, 由于所有的RMHandler对象,都继承成自RMHandler,所以我们可以利用反射获取所有的RMHandler对象,然后提供统一接口,由各个类分别根据各自的功能,对接口进行重写。重构后的代码如下,只有16行,却实现了和上面一样的功能,并且是可以很方便进行扩展。

 // register
    NSArray *handlersClasses = RMClassesThatBaseClass(RMHandler.class);
    NSMutableArray *handlers = [NSMutableArray array];
    for (Class aClass in handlersClasses) {
        [_httpServer addHandlerForMethod:[aClass method] path:[aClass path]  requestClass:[RMRequest class] processBlock:^GCDWebServerResponse *(__kindof GCDWebServerRequest *request) {
            RMHandler *handler = [RMHandlerManager createHandlerWithRequest: request];
            [handler start];
            
            NSMutableDictionary *json = [NSMutableDictionary dictionary];
            if (handler) {
                [json setObject:handler.sessionID forKey:kRMSessionIDKey];
                [json setObject:handler.result == nil?@{}:handler.result forKey:kRMQueryKey];
            }else {
                NSLog(@"没有创建相应和路由对象");
            }
            return [GCDWebServerDataResponse responseWithJSONObject:json];
        }];
    }

相关文章

  • 使用反射重构代码(OC)

    前沿 OC里的runtime就是Java里反射的概念。关于OC中runtime的应用早就被玩烂了, 今天介绍关于用...

  • 如何在Swift的代码中使用OC的代码, 在OC的代码中使用Sw

    如何在Swift的代码中使用OC的代码, 在OC的代码中使用Swift的代码? 一、OC的代码中使用Swift代码...

  • 代码重构利器

    使用重构件(Codemod)加速 JavaScript 开发和重构代码重构利器 —— jscodeshift 对于...

  • Swift 中的 NSPredicate

    最近在重构一个 OC 项目中的图片选择组件,在 OC 中调用谓词这句代码的时候 这个代码在 Swift 中该如何翻...

  • iOS 中的反射

    最近在学习Server,再重温Java 代码,对比OC后,有着诸多的感触,其中最深的是:Java中的反射使用是如此...

  • iOS面试题

    1、说一下OC的反射机制; OC 的反射机制以及使用场景 2、block的实质是什么?有几种block?分别是怎样...

  • OC中的反射机制

    你是否接触过OC中的反射机制?简单聊一下概念和使用1). class反射 2). SEL的反射

  • 如何在Swift的代码中使用OC的代码, 在OC的代码中使用Sw

    如何在Swift的代码中使用OC的代码, 在OC的代码中使用Swift的代码? 随着苹果公司对Swift的推广力度...

  • 代码重构专题(转载)

    代码重构(一):函数重构规则代码重构(二):类重构规则代码重构(三):数据重构规则代码重构(四):条件表达式重构规...

  • iOS代码重构

    遗留代码重构的原因: 风险: 详情链接:浅谈遗留代码的重构 从以下几个方面谈谈重构 1. 整理资源文件 删除未使用...

网友评论

    本文标题:使用反射重构代码(OC)

    本文链接:https://www.haomeiwen.com/subject/aahhvttx.html