Совет о том, как поймать «попытку вставить нулевой объект» с необходимого устройства

Вот ситуация: Hockeyapp и testflight время от времени жалуются на меня

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

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

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

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

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

Обновление: трассировка стека, к сожалению, не очень описательна, вот что я получаю

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

Одно замечание в самом сообщении об аварии.

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

Скажем, у меня есть словарный литерал

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • Swizzling низкоуровневые методы TCP на IOS
  • Метод swizzling для свойства в быстрой
  • Как реализовать метод swizzling swift 3.0?
  • iOS - код EXC_BAD_ACCESS = 1 UIWebView падает после (метод swizzling) init
  • Метод UIView swizzling swift 3
  • Магазин приложений - метод Swizzling Legality
  • Как swizzle метод частного класса
  • Расширенный метод swizzling в Objective-C, iOS 9?
  • Отладка основных данных __NSCFSet addObject исключение nil
  • Требуется ли метод
  • Каковы опасности метода Swizzling в Objective C?
  • Interesting Posts

    Добавить регулярное действие в NSAttributedString?

    Как перейти к диспетчеру просмотра с помощью push-уведомления

    сборник подбора ios json

    iOS – ошибка Firebase: использование неразрешенного идентификатора FIRApp с запущенным кодом

    Могу ли я проверить, отображается ли отображение UIAlertView прямо сейчас?

    XCode добавляет дублирующие ограничения?

    Сбой приложения iOS при запуске из-за профиля распространения? (libgdx + robovm)

    Как я могу получить свойство textContentType UITextField, чтобы что-нибудь сделать?

    Получение странного сообщения отладчика: Assertion failed: (cls), function getName: что это?

    Изменение атрибута отслеживания NSManagedObject

    Расчет подшипника между двумя CLLocationCoordinate2Ds

    Чтение и запись изображений в SQLite DB для использования iPhone

    слабый IBOutleCollection всегда равен нулю

    Как изменить изображение для UIButton после того, как пользователь нажал кнопку «Готово», это еще один UIView в iOS

    Приложение не распознается Game Center после сборки с Xcode 6.0.1

    Давайте будем гением компьютера.