关于如何捕获“试图插入零对象”的建议从需要的设备 [英] Advice on how to catch "attempt to insert nil object" from a device needed

查看:100
本文介绍了关于如何捕获“试图插入零对象”的建议从需要的设备的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Here is a situation: Hockeyapp and testflight every now and then complain about me


试图插入nil对象可变字典/数组中的

"attempting to insert nil object"

。我知道正确的事情是一直检查nil,而且当它有意义时我会这样做..我们的测试人员无法捕捉到这些崩溃,但AppStore用户显然可以。

in mutable dictionaries/arrays. I know the right thing is to check for nil all the time, and I do when it makes sense.. Our testers can not catch those crashes, but AppStore users obviously can.

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

My guess is that sometimes server returns NSNulls when it should not. So not to insert checks for nil everywhere in the huge project my idea was to create a separate target for the testers and use method swizzling for collection classes. Say, I'll replace insertObject:atIndex with my swizzled_insertObject:atIndex, where if the object is actually nil I log/show a descriptive report before it crashes.

事情是我无法使用swizzling __ NSPlaceholderDictionary __ NSArrayM (仅仅因为我无法在私人课程上制作类别)这让我感到难过。

The thing is I can not use swizzling for __NSPlaceholderDictionary or __NSArrayM (just because I can not make a category on private classes) and that makes me sad.

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

So basically I'm asking for advice on how to catch those nasty rare crashes. One solution I have in mind is using try-catch blocks, I know they are expensive in Objective-c, so I'd not use them in production, just for testers. But methods surrounded by try-catche-s surrounded by #ifdef-#endif-s will erase all the readableness of the code. So I'm searching for a more elegant solution. Thanks.

更新:堆栈跟踪不一定非常具有描述性,这就是我得到的信息

Update: the stack traces are unfortunaely not very descriptive, here is what I get

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
....


推荐答案

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

You don't need to add a category to do method swizzling. I was able to isolate a crash like this by method swizzling initWithObjects:forKeys:count: and putting a try/catch around the original method call. Finally I added a breakpoint in the catch section. This allowed me to break and go back up the stack to where the nil value was being used. This code is added at the top of my 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;
}

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

And then in my app did finish launching method:

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);

这篇关于关于如何捕获“试图插入零对象”的建议从需要的设备的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆