关于如何从所需设备捕获"尝试插入nil对象"的建议

dar*_*iaa 3 runtime objective-c swizzling ios objective-c-category

这是一种情况:Hockeyapp和testflight时不时地抱怨我

"试图插入零对象"

在可变字典/数组中.我知道正确的方法是一直检查nil,并且当它有意义时我会这样做.我们的测试人员无法捕获那些崩溃,但AppStore用户显然可以.

我的猜测是,有时服务器会返回NSNulls.因此,不要在巨大的项目中插入nil的检查,我的想法是为测试人员创建一个单独的目标,并使用方法调整集合类.说,我将替换insertObject:atIndex为my swizzled_insertObject:atIndex,如果对象实际上是nil ,我会在崩溃之前记录/显示描述性报告.

事情是我不能使用调酒__NSPlaceholderDictionary__NSArrayM (因为我不能在私人课程上制作类别)这让我很难过.

所以基本上我是在寻求关于如何捕捉那些令人讨厌的罕见崩溃的建议.我想到的一个解决方案是使用try-catch块,我知道它们在Objective-c中很昂贵,所以我不会在生产中使用它们,仅供测试人员使用.但是,包围方法try-catche包围-s #ifdef- #endif-s将清除代码的所有readableness.所以我正在寻找更优雅的解决方案.谢谢.

更新:堆栈跟踪不一定不是很具描述性,这是我得到的

Exception Type:  SIGABRT
Exception Codes: #0 at 0x3a378350
Crashed Thread:  0

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

Last Exception Backtrace:
0   CoreFoundation                      0x321522a3 <redacted> + 163
1   libobjc.A.dylib                     0x39e7a97f _objc_exception_throw + 31
2   CoreFoundation                      0x320a355f <redacted> + 135
3   CoreFoundation                      0x320da0d3 <redacted> + 51
....
Run Code Online (Sandbox Code Playgroud)

Dav*_*uma 7

您不需要添加类别来进行方法调配.我能够通过方法调整initWithObjects:forKeys:count:并在原始方法调用周围放置try/catch来隔离这样的崩溃.最后我在catch部分添加了一个断点.这允许我打破并返回堆栈到使用nil值的位置.此代码添加在AppDelegate.m的顶部:

#import <objc/runtime.h>
#import <objc/message.h>
static id safe_initWithObjects(id self, SEL _cmd, const id objects[], const id <NSCopying> keys[], NSUInteger count) {
    id orignialResult = nil;
    @try {
        orignialResult = objc_msgSend(self, @selector(safe_initWithObjects:forKeys:count:), objects, keys, count);
    }
    @catch (NSException *exception) {
        NSLog(@"BUSTED!"); // put breakpoint here
    }

    return orignialResult;
}
Run Code Online (Sandbox Code Playgroud)

然后在我的应用程序中完成启动方法:

Class target = NSClassFromString(@"__NSPlaceholderDictionary");
class_addMethod(target, @selector(safe_initWithObjects:forKeys:count:), (IMP)&safe_initWithObjects, "@@:**L");

Method m1 = class_getInstanceMethod(target, @selector(safe_initWithObjects:forKeys:count:));
Method m2 = class_getInstanceMethod(target, @selector(initWithObjects:forKeys:count:));
method_exchangeImplementations(m1, m2);
Run Code Online (Sandbox Code Playgroud)