2013-06-27 1 views
3

Вот ситуация: Hockeyapp и testflight каждый сейчас и потом жалуются мнеСоветы о том, как поймать «попытку вставить объект ноль» от устройства, необходимого

«пытается вставить ноль объект»

в изменяемых словарях/массивах. Я знаю, что правильно все время проверять ноль, и я делаю, когда это имеет смысл. Наши тестеры не могут поймать эти сбои, но пользователи AppStore, очевидно, могут.

Я предполагаю, что иногда сервер возвращает NSNulls, когда это не должно. Поэтому, чтобы не вставлять проверки на нуль во всем огромном проекте, моя идея состояла в том, чтобы создать отдельную цель для тестеров и использовать метод swizzling для классов коллекции. Скажите, я заменил бы insertObject:atIndex моим swizzled_insertObject:atIndex, где, если объект фактически равен нулю, я регистрирую/показываю описательный отчет перед его сбоем.

Дело в том, что я не могу использовать swizzling для __NSPlaceholderDictionary или __NSArrayM (просто потому, что я не могу сделать категорию на частных занятиях), и это меня огорчает.

Итак, в основном я прошу совета о том, как поймать эти неприятные редкие аварии. Одно из решений, которое я имею в виду, это использование блоков try-catch, я знаю, что они дороги в Objective-c, поэтому я не буду использовать их в производстве, просто для тестеров. Но методы, окруженные try-catche, в окружении #ifdef - #endif -s, стирают всю читаемость кода. Поэтому я ищу более элегантное решение. Спасибо.

Update: стек следы unfortunaely не очень описательные, вот что я получаю

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

Вам не нужно проверять 'nil' всюду. Трассировки стека должны сообщать вам, какая строка кода в вашем приложении вызывает проблему. Исправьте этот конкретный код. Но не просто проверяйте «nil». Определите, почему вы получаете «нуль» в первую очередь. – rmaddy

+1

В этом проблема - я не могу определить, почему и где я получаю ноль.и трассировки стека не всегда описывают все, что я получаю, например: erminating app из-за неотображенного исключения «NSInvalidArgumentException», причина: «*** - [__ NSPlaceholderDictionary initWithObjects: forKeys: count:]: попытка вставить нулевой объект из объектов [ 2] ' – dariaa

+0

Еще одна вещь: Вы, кажется, путаете 'nil' с' NSNull'. 'NSNull' - объект; он обычно используется в качестве заполнителя. – trudyscousin

ответ

0

предположит, что вы запрашиваете данные с помощью JSON от сервера, несколько раз на поле в данном JSON является нулевым, так что вы может получить NSNull после coversion.

так что мой совет проверяет «нулевую» ситуацию на сервере, если это происходит, возвращает сбой faild, но не доставляет данные плохих форматов в APP.

Когда APP получает такие данные, APP не знает, как с ним справиться. это уже ненормально. все в порядке, что вы можете поймать исключение и игнорировать ненормальные данные, но мой способ сделать это - предотвратить это из источника.

0

В большинстве системных вызовов (iOS) или связи с сервером может быть nil или когда вы работаете, вызывая функцию из сторонних библиотек. В этих случаях необходимо проверить значение nil imho. Несколько старших разработчиков, архитекторов используют несколько операторов в режиме онлайн. Очень плохое поведение, я учу свой урок, просто напишу в отдельной строке, чтобы узнать, какая строка разбилась именно на код. Гораздо проще это исправить.

Если вы не можете найти в своем коде. Есть журналы, репортерные библиотеки. Используйте любой из них, и вы получите причины, номер строки, легко исправить, чем.

я бы не использовать везде ноль проверки, ни примерочных улов, только в случаях, указанных выше

+0

Спасибо за ваш ответ, я использую hockeyapp и загружаю dsyms, но трассировки стека все еще не очень описательны. Пожалуйста, ознакомьтесь с обновленным вопросом – dariaa

7

Вам не нужно, чтобы добавить категорию, чтобы сделать метод swizzling. Я смог изолировать авария, подобную этому, методом swizzling 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; 
} 

И тогда в мое приложение было закончить метод запуска:

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

Это должен быть принятый ответ! Свидание помогло мне найти катастрофу в таком месте, о котором я бы никогда не подумал. –

+1

Это помогло мне несколько раз. Вы можете сэкономить на проблемах/ошибках при попытке выработать кодировку типа метода («@@: ** L»), предоставив вам время выполнения Obj-C: Метод m1 = class_getInstanceMethod (target, @ селектор (initWithObjects: forKeys: кол :)); const char * methodTypeEncoding = method_getTypeEncoding (m1); Затем вы можете передать это в class_addMethod вместо стробированной строки. – user2067021

0

Просто найти это, глядя на то, где я создаю NSDictionaries и добавив несколько утверждений утверждения, чтобы проверить, нет ли объектов.

  1. поиск @{@" - начало создания словаря с использованием современного синтаксиса, или NSDictionary
  2. Добавить NSAssert (объект = ноль, @ "Ваш объект равен нулю здесь!"); Перед тем как вставить объекты
  3. Запустите приложение, проверьте консоль, найдите соответствующую Assert и исправить:

    Нагрузочный приложение из-за неперехваченного исключением «NSInternalInconsistencyException», причина: «Ваш объект будет равен нулю здесь»

3

Одна вещь, которую нужно отметить в сообщении о сбое.

«попытка вставить нулевой объект из объектов [#]» означает, что либо ключ, либо значение в индексе [#] (мышление в списке литералов NSDictionary) равен нулю.

Скажем, у меня есть словарь буквального

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

Тогда индекс [0] будет первая пара в индексе список [1] ​​будет вторая пара и так далее. Если любая запись в паре равна нулю, она вызывает это исключение с соответствующим индексом.

0

Я попытался ответить на третий ответ, он помогает мне в большинстве случаев. Однако, когда моя инфраструктура поддержки проекта 64, я встретил катастрофический крах Бена, вызванный третьей стороной статической библиотеки. Бен коллапс точек CFDictionaryContainsKey.

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

Когда коллапс Ben myDictionaryRef равен нулю. После некоторого тестирования я нашел проблему.

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) {.....} 

Различные типы параметров, связанных Бен коллапс. так, я думаю, что правильный ответ

#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. Я не могу комментировать непосредственно. Надеюсь, вы дадите мне голосование.

Смежные вопросы