【问题标题】:Crashlytics Crash with NSOperationQueue (QOS: UNSPECIFIED)Crashlytics Crash with NSOperationQueue (QOS: UNSPECIFIED)
【发布时间】:2019-08-09 08:29:57
【问题描述】:

我遇到了崩溃,在 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();
                }
            }
        }
    }];
}

【问题讨论】:

  • “DataCore.m:236”周围的代码是什么样的?
  • 将垃圾指针传递给 CF 层?
  • @PhillipMills 感谢您的快速响应,我用一些代码更新了问题。谢谢
  • 由于错误发生在objc_retain 期间,因此您在第 236 行编码的任何内容都可能是或引用错误的指针。可能是垃圾,也可能是过度发布的东西。 (原始崩溃标头中可能包含更多信息,但我似乎记得 Crashlytics 没有提供这些信息。)
  • 是的,这是有道理的,第 236 行是指 self.metadata 的编码位置,可能是垃圾或坏点被传递给编码器,不幸的是 Crashlytics 没有提供有关崩溃的更多信息.我将浏览这些文件并查看self.metaData 的填充位置,并尝试查看发生了什么。谢谢

标签: ios cocoa-touch crash crashlytics nsoperationqueue


【解决方案1】:

这里有一些想法。

首先,您正在使用@try/@catch。我相信NSKeyedArchiver 在实际应该返回NSError 对象时会抛出异常。所以,也许这就是你这样做的原因。但是,您必须记住,没有一个 Apple 的框架可以保证为exception-safe。这意味着捕获异常可能会使 Apple 的代码(当然还有您自己的)处于不一致的状态,这将阻止它在未来正常工作。

如果这就是您使用它的原因,我强烈建议您删除@catch,或者将其范围严格限制在NSKeyedArchiver 代码周围。这可能会无意中在您的应用中引入各种其他错误。

现在,谈谈具体的崩溃。它发生在运行时的内存管理代码中。这非常强烈地指向堆损坏。这意味着你有一个指针,它不指向内存中有效的 Objective-C 对象。发生这种情况的原因有很多,并且非常很常见。最常见的原因被称为悬空指针。但是,它也可能是由过度释放引起的。而且,如果可以使用@catch 来触发过度释放,我一点也不感到惊讶。 (我知道,我在竖琴,但我已经看到如此许多由这种模式引起的问题)

在这些情况下我一般建议:

  • 查找其他看起来与堆损坏相关的崩溃
  • 在 Instruments 中试用 Zombies
  • 试试 malloc scribble 或 guardmalloc,这两个很好的内存调试工具

很难,甚至通常不可能推断堆损坏。复制错误也可能是不可能的,因为内存损坏通常不是确定性的。

因此,请尝试尽可能多地查找并解决问题。完全有可能其中一个负责各种崩溃,其中一个可能就是这个。

【讨论】:

  • 感谢您的回复,我会尝试使用 Zombies 来检测内存问题,我还发现 archivedDataWithRootObject 已被弃用并且可能是原因之一,因为应用程序崩溃是仅在 iOS 12 中。但是就像您说的那样,几乎不可能重现此崩溃,尤其是在调试版本中...
  • @Mattie 你能分享一些指向 Apple 文档的链接吗?关于他们的框架不是异常安全的?我想了解更多相关信息
  • @Antag 据我所知,关于此的文档很少,developer.apple.com/library/archive/documentation/Cocoa/… 除外
猜你喜欢
  • 2023-01-19
  • 1970-01-01
  • 2020-06-22
  • 1970-01-01
  • 1970-01-01
  • 2020-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多