美文网首页iOS高级实用技术JC专题
用Runtime中转发消息的方式解决服务器端返回NSNULL的问

用Runtime中转发消息的方式解决服务器端返回NSNULL的问

作者: 城市之光 | 来源:发表于2016-01-08 15:05 被阅读764次

    有时候服务器很烦不靠谱,老是不经意间返回null,所以在iOS端不得不校验它的类型等。譬如:返回的数组为null,首先得判断类型是不是NSArray 还得判断非空。

    NSArray *products = data[@"省心宝"];
    if ([products isKindOfClass:[NSArray class]] && products.count > 0)
    {
        // TO DO
    }
    

    这种问题一多,就会影响我们程序猿的心情,并且代码也变得冗余了,所以换种技巧solve it。

    思路:重写NSNull的消息转发方法, 让他能处理这些异常的方法。
    常见的几种类型为"",0,{},[]了。
    所以,创建一个NSNull的分类 NSNull (InternalNullExtention)

    具体实现如下:
    .h文件
    #import <Foundation/Foundation.h>
    @interface NSNull (InternalNullExtention)
    @end

    .m文件

    #import "NSNull+InternalNullExtention.h"
    
    #define NSNullObjects @[@"",@0,@{},@[]]
    
    @implementation NSNull (InternalNullExtention)
    
    + (void)load
    {
         @autoreleasepool {
               [self wt_swizzleInstanceMethodWithClass:[NSNull class] originalSel:@selector(methodSignatureForSelector:) replacementSel:@selector(wt_methodSignatureForSelector:)];
               [self wt_swizzleInstanceMethodWithClass:[NSNull class] originalSel:@selector(forwardInvocation:) replacementSel:@selector(wt_forwardInvocation:)];
         }
    }
    
    - (NSMethodSignature *)wt_methodSignatureForSelector:(SEL)aSelector
    {
         NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
         if (!signature) {
              for (NSObject *object in NSNullObjects) {
                   signature = [object methodSignatureForSelector:aSelector];
                   if (!signature) {
                        continue;
                   }
                   if (strcmp(signature.methodReturnType, "@") == 0) {
                          signature = [[NSNull null] methodSignatureForSelector:@selector(wt_nil)];
                   }
                   return signature;
              }
              return [self wt_methodSignatureForSelector:aSelector];
         }
         return signature;
    }
    
    - (void)wt_forwardInvocation:(NSInvocation *)anInvocation
    {
        if (strcmp(anInvocation.methodSignature.methodReturnType, "@") == 0)
        {
              anInvocation.selector = @selector(wt_nil);
             [anInvocation invokeWithTarget:self];
             return;
        }
    
        for (NSObject *object in NSNullObjects)
        {
              if ([object respondsToSelector:anInvocation.selector])
              {
                    [anInvocation invokeWithTarget:object];
                    return;
              }
        }
    
         [self wt_forwardInvocation:anInvocation];
        //  [self doesNotRecognizeSelector:aSelector];
    }
    
    - (id)wt_nil
    {
         return nil;
    }
    
    + (void)wt_swizzleInstanceMethodWithClass:(Class)clazz originalSel:(SEL)original replacementSel:(SEL)replacement
    {
          Method originMethod = class_getInstanceMethod(clazz, original);
          Method replaceMethod = class_getInstanceMethod(clazz, replacement);
          if (class_addMethod(clazz, original, method_getImplementation(replaceMethod), method_getTypeEncoding(replaceMethod))
          {
                 class_replaceMethod(clazz, replacement, method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
          }
          else
          {
                method_exchangeImplementations(originMethod, replaceMethod);
          }
    }
    
    @end
    

    测试代码就不加了。

    相关文章

      网友评论

      • 川hc:我看有人写的并没有交换方法,直接写的 消息签名方法覆盖了原来的,请问,为什么你这里要交换方法?
      • 神经病_老头子:if (class_addMethod(clazz, original, method_getImplementation(replaceMethod), method_getTypeEncoding(replaceMethod)) 最后少了个)所以那么多报错
      • fc18f69e6ff0:楼主 这个wt_swizzleInstanceMethodWithClass 方法中 Method originMethod = class_getInstanceMethod(clazz, original);
        Method replaceMethod = class_getInstanceMethod(clazz, replacement);一直报错 如何解决
        风起剑来:@闭上眼睛 你要导入objc的头文件,兄弟
      • 超_iOS:能麻烦楼主给点注释吗?毕竟对runtime不是很熟
        城市之光:@李二超 其实这个就是消息转发的过程了,你可以找些资料看看或看官方文档
      • 四月天__:作者你好,请问下你的load方法里面调用点两个方法是系统等方法吗,我这边一直报错
        城市之光:@97cdca3de987 不是的,你检查下第三方库里有没有重复的方法了
        四月天__:@城市之光 就是这两个方法 是系统的方法吗 [self swizzleInstanceMethodWithClass:[NSNull class] originalSel:@selector(methodSignatureForSelector:) replacementSel:@selector(wt_methodSignatureForSelector:)];
        [self swizzleInstanceMethodWithClass:[NSNull class] originalSel:@selector(forwardInvocation:) replacementSel:@selector(wt_forwardInvocation:)];
        城市之光:@97cdca3de987 没明白你的意思,能说具体点不

      本文标题:用Runtime中转发消息的方式解决服务器端返回NSNULL的问

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