有时候服务器很烦不靠谱,老是不经意间返回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
测试代码就不加了。
网友评论
Method replaceMethod = class_getInstanceMethod(clazz, replacement);一直报错 如何解决
[self swizzleInstanceMethodWithClass:[NSNull class] originalSel:@selector(forwardInvocation:) replacementSel:@selector(wt_forwardInvocation:)];