Crashlytics Crash с NSOperationQueue (QOS: НЕ УКАЗАНО) - PullRequest
0 голосов
/ 19 марта 2019

Я получаю сбой, о котором сообщили в Crashlytics, и я понятия не имею, как воспроизвести ошибку. Это происходит случайно, поэтому трудно отладить ее с помощью Xcode.Есть идеи?

Crashed: NSOperationQueue 0x280419200 (QOS: UNSPECIFIED)
0 libobjc.A.dylib 0x22c471430 objc_retain + 16
1 CoreFoundation 0x22d2b5888 __CFBasicHashAddValue + 1480
2 CoreFoundation 0x22d1e64ac CFDictionarySetValue + 260
3 Foundation 0x22dd04888 _encodeObject + 732
4 myAPI 0x1062b44b0 -[DataCore encodeWithCoder:] (DataCore.m:236)
5 myAPI 0x1062909c4 -[DataHandle encodeWithCoder:] (DataHandle.m:53)
6 Foundation 0x22dd04aa8 _encodeObject + 1276
7 Foundation 0x22dc69c6c +[NSKeyedArchiver archivedDataWithRootObject:] + 168
8 myAPI 0x106288a34 __77+[CachableObject addObjectToCache:withCacheName:withTTL:withCompletionBlock:]_block_invoke (CachableObject.m:162)
9 Foundation 0x22dd198bc NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK + 16
10 Foundation 0x22dc21ab8 -[NSBlockOperation main] + 72
11 Foundation 0x22dc20f8c -[__NSOperationInternal _start:] + 740
12 Foundation 0x22dd1b790 __NSOQSchedule_f + 272
13 libdispatch.dylib 0x22ccc16c8 _dispatch_call_block_and_release + 24
14 libdispatch.dylib 0x22ccc2484 _dispatch_client_callout + 16
15 libdispatch.dylib 0x22cc6582c _dispatch_continuation_pop$VARIANT$mp + 412
16 libdispatch.dylib 0x22cc64ef4 _dispatch_async_redirect_invoke + 600
17 libdispatch.dylib 0x22cc71a18 _dispatch_root_queue_drain + 376
18 libdispatch.dylib 0x22cc722c0 _dispatch_worker_thread2 + 128
19 libsystem_pthread.dylib 0x22cea517c _pthread_wqthread + 472
20 libsystem_pthread.dylib 0x22cea7cec start_wqthread + 4

Вот как выглядит код в DataCore.m

- (void)encodeWithCoder:(NSCoder *)coder {
    [super encodeWithCoder:coder];
    [coder encodeObject:programFormatPlayInfo forKey:@"ProgramFormatPlayInfo"];
    [coder encodeObject:bigScreenPlayInfo forKey:@"BigScreenPlayInfo"];
    [coder encodeObject:pivotHandle forKey:@"PivotHandle"];
    [coder encodeInteger:pivotDataLinkId forKey:@"PivotDataLinkId"];
    [coder encodeInteger:viewContextId forKey:@"ViewContextId"];
    [coder encodeBool:suppressImagePivot forKey:@"SuppressImagePivot"];
    [coder encodeObject:attributeIds forKey:@"AttributeIds"];
    [coder encodeObject:self.overflow forKey:@"Overflow"];
    [coder encodeObject:self.cacheNameWithUser forKey:@"CacheNameWithUser"];
    [coder encodeObject:self.metaData forKey:@"Metadata"];
}

, и здесь я пытаюсь добавить объект в кеш, не уверенный, если онне удается декодировать или что-то связано с фоновой очередью.

+ (void)addObjectToCache:(CachableObject*)object withCacheName:(NSString*)cacheName withTTL:(CacheTime)cacheTimeSeconds withCompletionBlock:(void(^)()) block {
    CachableObject* theObject = object;
    [_backgroundQueue addOperationWithBlock:^{
        @autoreleasepool {
            @try {
                NSString * path = [CachableObject pathForCachedObject:cacheName];
                NSDate * date = [NSDate date];

                [object setCacheDate:date];
                [object setTtlSeconds:[NSNumber numberWithInteger:cacheTimeSeconds]];
                [object setApiVersion:APIVERSION];

                // Add to NSCache
                [[CachableObject objectCache] setObject:theObject forKey:cacheName];

                // Add to file system
                NSError* err = nil;
                NSData * data = [NSKeyedArchiver archivedDataWithRootObject:theObject];
                if (data) {
                    [data writeToFile:path options:NSDataWritingAtomic error:&err];
                }

                // Add to dynamic cache
                unwrapObjectAndComplyWithClass(object, [DataHandle class], ^(id unwrappedObject) {
                    DataHandle *objectUnwrapped = unwrappedObject;
                    DataFrame *objectFrame = objectUnwrapped.frame;
                    for (NSString *eachDependencyName in objectFrame.dependencies) {
                        [[VVIDynamicCacheManager sharedManager]addDependencyToStore:eachDependencyName withCacheName:cacheName];
                    }
                }, ^{
                   /*Not a data handle*/
                });

            } @catch (NSException* ex) {
                NSLog(@"CachableObject: got an exception %@", ex);
            } @finally {
                if (block) {
                    block();
                }
            }
        }
    }];
}

1 Ответ

1 голос
/ 21 марта 2019

Некоторые мысли здесь.

Сначала вы используете @ try / @ catch.Я считаю, что NSKeyedArchiver генерирует исключения, когда на самом деле должен возвращать NSError объекты.Так что, возможно, именно поэтому вы делаете это.Но вы должны иметь в виду, что none фреймворков Apple гарантированно будут исключительными .Это означает, что перехват исключений может привести к тому, что код Apple (и, конечно, ваш собственный) окажется в несогласованных состояниях, что помешает его правильной работе в будущем.

Я бы настоятельно рекомендовал либо удалить @catch, либо ограничить область действия.он чрезвычайно тесно связан с кодом NSKeyedArchiver, если вы поэтому его используете.Это может привести к непреднамеренному введению множества других ошибок в ваше приложение.

Теперь перейдем к конкретному сбою.Это происходит в коде управления памятью среды выполнения.Это очень сильно указывает на коррупцию в куче.Это означает, что у вас есть указатель, который не указывает на действительный объект Objective C в памяти.Это может произойти по многим причинам, и это чрезвычайно распространено.Наиболее распространенная причина известна как висячий указатель.Однако это также может быть вызвано чрезмерным выпуском.И я совсем не удивлюсь, если можно использовать @catch для запуска перевыпуска.(Я знаю, я плохо говорю, но я видел , поэтому много проблем, вызванных этим шаблоном)

Что я обычно рекомендую в этих ситуациях:

  • Найдите другие сбои, связанные с повреждением кучи
  • Попробуйте Zombies в инструментах
  • Попробуйте malloc scribble или guardmalloc, два других хороших инструмента отладки памяти

Трудно, а часто даже невозможно, рассуждать о кучной коррупции.Воспроизведение ошибки также может быть невозможным, поскольку повреждение памяти, как правило, не является детерминированным.

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

...