关于如何从所需设备中捕获“试图插入零对象”的build议

这是一个情况:霍克亚普和testing飞行时不时抱怨我

“尝试插入零对象”

在可变字典/数组中。 我知道正确的做法是一直检查零,而我做的时候才有意义。我们的testing人员无法捕捉到这些崩溃,但AppStore的用户显然可以。

我的猜测是,有时服务器返回NSNulls,当它不应该。 因此,不要在大型​​项目中插入无为零的检查,我的想法是为testing人员创build一个单独的目标,并为集合类使用方法调整。 说,我会replaceinsertObject:atIndex与我的swizzled_insertObject:atIndex ,其中如果对象实际上是零我login/显示一个描述性的报告之前,崩溃。

事情是我不能用__NSPlaceholderDictionary__NSArrayM (只是因为我不能在私人类上做一个类别)使用__NSPlaceholderDictionary ,这让我很难过。

所以基本上我是在寻求如何捕捉这些令人讨厌的罕见碰撞的build议。 我想到的一个解决scheme是使用try-catch块,我知道它们在Objective-C中是很昂贵的,所以我不会在生产中使用它们,只是为了testing人员。 但是被#ifdef#endif -s包围的try-catche -s包围的方法将会擦除代码的所有可读性。 所以我正在寻找一个更优雅的解决scheme。 谢谢。

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

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

你不需要添加一个类别来做方法swizzling。 我能够通过方法debugginginitWithObjects:forKeys:count:并在原始方法调用周围放置一个try / catch来隔离这样的崩溃。 最后我在catch部分添加了一个断点。 这允许我打破并回到堆栈的零值被使用的地方。 这个代码被添加到我的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; } 

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

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

有一件事要注意崩溃消息本身。

尝试从对象插入nil对象[#] ”意味着索引[#](考虑NSDictionary字面值列表)的键或值是零。

说我有一个词典文字

 NSDictionary *person = @{@"first":firstName,@"last":lastName,@"email":email"}; 

然后索引[0]将是列表中的第一对索引[1]将是第二对,依此类推。 如果对中的任何一个条目都是零,它将触发与相应索引的这个exception。

假设您从服务器使用JSON获取数据,有时候JSON数据中的字段为空,所以在覆盖之后可能会得到NSNull。

所以我的build议是检查服务器中的“null”情况,如果发生,返回faild msg,但是不把坏格式的数据发送给APP。

当APP收到这些数据时,APP不知道如何处理。 已经不正常了 可以捕捉exception并忽略exception数据,但是我的方法是防止它从源头发生。

在大多数系统调用(iOS)或服务器通信可以是零,或者当你在工作时,从第三方库调用函数。 在这些情况下,必须检查一个零值imho。 几位高级开发人员,架构师在线使用多重声明。 非常不好的行为,我读了我的教训,只是写在单独的行来知道哪一行崩溃的代码。 修复它很容易。

如果你在你的代码中找不到。 有伐木工,坠毁记者图书馆。 使用任何比,你会得到的原因,行号,易于修复比。

只是在上面提到的情况下,我不会在任何地方使用零检查或试一试

通过查看创buildNSDictionaries的位置以及添加一些断言语句来检查对象是否为零,只是发现了这一点。

  1. search@{@" – 使用现代语法或NSDictionary开始创buildNSDictionary
  2. 添加NSAssert(object!= nil,@“你的对象在这里是零”); 在插入对象之前
  3. 运行应用程序,检查控制台,find相应的断言并修复它:

    由于未捕获的exception“NSInternalInconsistencyException”而终止应用程序,原因:“您的对象在这里是零”

我试着回答第三个答案,在大多数情况下,它确实给了我帮助。 然而,当我的项目支持框架64,我遇到了一个灾难性的本崩溃,由第三方静态库引起的。 本崩溃点CFDictionaryContainsKey。

 CFDictionaryRef myDictionaryRef = ...... CFDictionaryContainsKey (myDictionaryRef, searchKey [0]). 

当本折叠myDictionaryRef是零。 经过一些testing,我发现一个问题。

 interface __NSPlaceholderDictionary: NSMutableDictionary { } - (Id) initWithObjects: (const id *) arg1 forKeys: (const id *) arg2 count: (unsigned int) arg3; 

比较答案

 static id safe_initWithObjects (id self, SEL _cmd, const id objects [], const id <NSCopying> keys [], NSUInteger count) {.....} 

不同types的参数导致Ben崩溃。 所以,我认为正确的答案是

  #import <objc / runtime.h> #import <objc / message.h> static id safe_initWithObjects (id self, SEL _cmd, const id * objects, const id * keys, unsigned int 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; } 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); 

谢谢答复提供者,也因为我有足够的声誉50.我不能直接发表评论。 我希望你给我一个投票。