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

有时候服务器很烦不靠谱,老是不经意间返回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
@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

测试代码就不加了。

你可能感兴趣的:(用Runtime中转发消息的方式解决服务器端返回NSNULL的问题(笔记))