美文网首页IOS三人行runtime精选和blockiOS-OC中级
APP闪退原因之一,请求参数为nil

APP闪退原因之一,请求参数为nil

作者: 小樊 | 来源:发表于2016-08-26 09:51 被阅读2873次

    随着第三方框架AFNetworking的兴起,越来越多的人开始使用AFNetworking来调用接口,发送请求.
    而在需要请求体的请求中,一般都是使用字典来作为请求体.
    字典的初始化有很多种,本人较为常用的是以下这种:

    NSDictionary *params = @{ @"key1":value1 ,@"key2":value2};
    

    但是,value的值一般都是动态传入的,所以有存在nil的可能,结果就是你懂的↓

    *** Terminating app due to uncaught exception 'NSInvalidArgumentException',
    reason: '*** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]
    : attempt to insert nil object from objects[0]'**
    

    那么就有人会说,你应该在传入前判断value是否为nil,或者使用较为安全的方法,如:

    [NSDictionary dictionaryWithObjectsAndKeys:value,@"key", nil];
    

    是的,这些方法都可以解决上面存在的问题,但是我懒,懒得写那么多.
    所以就决定是你了,去吧,

    亮瞎吧.jpg

    一个.m文件搞定问题

    #import <Foundation/Foundation.h>
    #import <objc/message.h>
    
    @implementation NSDictionary (Swizzle)
    
    + (void)load {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            [objc_getClass("__NSPlaceholderDictionary") swizzleSelector:@selector(initWithObjects:forKeys:count:) withSwizzledSelector:@selector(safeInitWithObjects:forKeys:count:)];
        });
    }
    
    - (instancetype)safeInitWithObjects:(const id _Nonnull __unsafe_unretained *)objects forKeys:(const id _Nonnull __unsafe_unretained *)keys count:(NSUInteger)cnt {
        BOOL containNilObject = NO;
        for (NSUInteger i = 0; i < cnt; i++) {
            if (objects[i] == nil) {
                containNilObject = YES;
                NSLog(@"reason: ***object cannot be nil (key: %@)", keys[i]);
            }
        }
        if (containNilObject) {
            NSUInteger nilCount = 0;
            for (NSUInteger i = 0; i < cnt; ++i) {
                if (objects[i] == nil) {
                    nilCount ++;
                }
            }
            NSUInteger length = cnt - nilCount;
            if (length > 0) {
                NSUInteger index = 0;
                id __unsafe_unretained newObjects[length];
                id __unsafe_unretained newKeys[length];
                for (NSUInteger i = 0; i < cnt; ++i) {
                    if (objects[i] != nil) {
                        newObjects[index] = objects[i];
                        newKeys[index] = keys[i];
                        index ++ ;
                    }
                }
                NSLog(@"fixedDictionary:%@",[self safeInitWithObjects:newObjects forKeys:newKeys count:length]);
                return [self safeInitWithObjects:newObjects forKeys:newKeys count:length];
            } else {
                NSLog(@"fixedDictionary:nil (all objects are nil)");
                return nil;
            }
        }
        return [self safeInitWithObjects:objects forKeys:keys count:cnt];
    }
    
    + (void)swizzleSelector:(SEL)originalSelector withSwizzledSelector:(SEL)swizzledSelector {
        Class class = [self class];
        
        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
        
        BOOL didAddMethod = class_addMethod(class,
                                            originalSelector,
                                            method_getImplementation(swizzledMethod),
                                            method_getTypeEncoding(swizzledMethod));
        
        if (didAddMethod) {
            class_replaceMethod(class,
                                swizzledSelector,
                                method_getImplementation(originalMethod),
                                method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    }
    
    @end
    

    当然,我写的这个分类还是有局限性的,限性的,性的,的......
    它只对以下这种创建字典的方式有效

    NSDictionary *params = @{ @"key1":value1 ,@"key2":value2};
    

    导入文件后:


    File.png

    看看效果吧:

    Result.png

    相关文章

      网友评论

      • 凌然九霄:感谢分享,请问一下,为啥要删除.h文件
      • 花色衬衫:不会用 :smirk:
        花色衬衫:太强了,说的这么透彻
        小樊:@花色衬衫 :joy::joy:,创建NSDictionary 的分类,分类名字自己写,然后删掉.h文件,把上面代码复制到.m文件中,Swizzle改成你刚写的分类名,或者你分类名跟我写一样,就直接粘贴就行
      • 等这姑娘老在我心里:为什么不用__weak 而用_Nonull __unsafe_unretained 呢
        小樊:@等这姑娘老在我心里 至于为什么不用__weak,我现在还找不到原因为什么用__weak会出现多次调用,而且崩溃的情况;谢谢你的提议
        小樊:@等这姑娘老在我心里 是的,所以我修改了下代码,你再试试
        等这姑娘老在我心里:@等这姑娘老在我心里 我研究了下这个代码 假如说 所有的object 都是nil 好像会有问题的
      • Lxyang:666 大神 一次型帮我解决了我项目中的几十个bug :smirk: :sob: :stuck_out_tongue_winking_eye: :up:
        Lxyang:@小樊 别,已经很不错了,至少一次型帮我解决了这么多闪退的bug :joy:
        小樊:@coder_yang :joy::joy:,小弟也是渣渣,不敢称之为大神
      • husky_duang:666,我那接口6个参数我判断了好久,很有用, :+1:
      • 邱读书:好像不管用啊
        小樊:@邱读书 这个分类有点局限性,是否你创建字典的方式和文中的不同呢?
      • xgou:不错,赞一个

      本文标题:APP闪退原因之一,请求参数为nil

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