我正在使用UIImage
在后台队列上创建-[UIImage initWithCGImage:scale:orientation:]
,因此崩溃了:
崩溃1
Crashed: com.apple.root.background-qos
0 libsystem_kernel.dylib 0x183778140 __pthread_kill + 8
1 libsystem_pthread.dylib 0x183840ef8 pthread_kill + 112
2 libsystem_c.dylib 0x1836e9dac abort + 140
3 libsystem_malloc.dylib 0x1837acd34 free_list_checksum_botch + 438
4 libsystem_malloc.dylib 0x1837aced8 free_tiny_botch + 84
5 CoreFoundation 0x183c08038 __CFBasicHashRehash + 2448
6 CoreFoundation 0x183c09034 __CFBasicHashAddValue + 100
7 CoreFoundation 0x183ab49c4 CFDictionarySetValue + 248
8 UIKit 0x18926fd30 _UITraitCollectionCacheForBuiltinStorage + 152
9 UIKit 0x189272090 +[UITraitCollection traitCollectionWithDisplayScale:] + 52
10 UIKit 0x1888d5070 -[UIImage initWithCGImage:scale:orientation:] + 236
11 UIKit 0x1888d4f74 +[UIImage imageWithCGImage:scale:orientation:] + 72
12 MyApp 0x10001a168 -[UIImage(Additions) foo_scaledImageData] (Foo.m:1527)
13 MyApp 0x100017304 -[Foo bar] (Foo.m:731)
14 MyApp 0x100017094 __95-[Foo bar]_block_invoke_3 (Foo.m:691)
15 libdispatch.dylib 0x183629630 _dispatch_call_block_and_release + 24
16 libdispatch.dylib 0x1836295f0 _dispatch_client_callout + 16
17 libdispatch.dylib 0x183637a88 _dispatch_root_queue_drain + 2140
18 libdispatch.dylib 0x183637224 _dispatch_worker_thread3 + 112
19 libsystem_pthread.dylib 0x18383d470 _pthread_wqthread + 1092
20 libsystem_pthread.dylib 0x18383d020 start_wqthread + 4
我还遇到了以下两个线程的崩溃:
崩溃2,主题1:
Crashed: com.apple.root.background-qos
0 libsystem_kernel.dylib 0x237d3c5c __pthread_kill + 8
1 libsystem_pthread.dylib 0x23879b47 pthread_kill + 62
2 libsystem_c.dylib 0x237680c5 abort + 108
3 libsystem_malloc.dylib 0x238040e9 free_list_checksum_botch + 362
4 libsystem_malloc.dylib 0x23804105 free_list_checksum_botch + 28
5 libsystem_malloc.dylib 0x237fbbff tiny_malloc_from_free_list + 202
6 libsystem_malloc.dylib 0x237fa987 szone_malloc_should_clear + 218
7 libsystem_malloc.dylib 0x237fa879 malloc_zone_malloc + 88
8 CoreFoundation 0x23a4e291 _CFRuntimeCreateInstance + 236
9 CoreGraphics 0x24e792a9 CGTypeCreateInstance + 20
10 CoreGraphics 0x24db7d23 CGColorTransformCreate + 246
11 ImageIO 0x2533c64b IIO_ConvertCGColorToColorComponents + 26
12 ImageIO 0x252f5775 CGImagePixelDataProviderCreate + 276
13 ImageIO 0x25319af1 CGImagePixelDataProviderCreateConforming + 1684
14 ImageIO 0x252f418d CGImageDestinationAddImage + 2852
15 UIKit 0x283fe4f5 _UIImageJPEGRepresentation + 620
16 MyApp 0xf6785 -[UIImage(Additions) foo_scaledImageData] (Foo.m:1538)
17 MyApp 0xf3ecd -[Foo bar] (Foo.m:731)
18 MyApp 0xf3d29 __95-[Foo bar]_block_invoke_3 (Foo.m:691)
19 libdispatch.dylib 0x236d7cbf _dispatch_call_block_and_release + 10
20 libdispatch.dylib 0x236e36a1 _dispatch_root_queue_drain + 1572
21 libdispatch.dylib 0x236e307b _dispatch_worker_thread3 + 94
22 libsystem_pthread.dylib 0x23876e0d _pthread_wqthread + 1024
23 libsystem_pthread.dylib 0x238769fc start_wqthread + 8
崩溃2,主题2:
com.apple.root.background-qos
0 libsystem_malloc.dylib 0x238041d8 free_tiny_botch
1 CoreFoundation 0x23b6f560 __CFBasicHashRehash + 2968
2 CoreFoundation 0x23b706d4 __CFBasicHashAddValue + 100
3 CoreFoundation 0x23a4f933 CFDictionarySetValue + 206
4 UIKit 0x28a87ffb _UITraitCollectionCacheForBuiltinStorage + 146
5 UIKit 0x28a8a2a7 +[UITraitCollection traitCollectionWithDisplayScale:] + 50
6 UIKit 0x2812390f -[UIImage initWithCGImage:scale:orientation:] + 214
7 UIKit 0x2812382b +[UIImage imageWithCGImage:scale:orientation:] + 62
8 MyApp 0xf676d -[UIImage(Additions) foo_scaledImageData] (Foo.m:1527)
9 MyApp 0xf3ecd -[Foo bar] (Foo.m:731)
10 MyApp 0xf3d29 __95-[Foo bar]_block_invoke_3 (Foo.m:691)
11 libdispatch.dylib 0x236d7cbf _dispatch_call_block_and_release + 10
12 libdispatch.dylib 0x236e36a1 _dispatch_root_queue_drain + 1572
13 libdispatch.dylib 0x236e307b _dispatch_worker_thread3 + 94
14 libsystem_pthread.dylib 0x23876e0d _pthread_wqthread + 1024
15 libsystem_pthread.dylib 0x238769fc start_wqthread + 8
崩溃2,线程2看起来像Crash 1,线程1,这让我觉得它们是相关的,但是Crash 2,线程2是一个异常值。我有很多其他崩溃看起来像没有线程2堆栈的崩溃2,这让我觉得UIImageJPEGRepresentation
也可能不是线程安全的。
答案 0 :(得分:2)
我无法说出来源,但它正在被照顾。 (或至少一个 雷达已由Apple内部人员提交
附注:我查看了UIKit反汇编并且API调用了 traitCollection和其他一些东西,但实际上是一切 线程安全;更多,所以它真的应该只在主要调用 理想的线程。我们可以调整并直接将锁添加到 实现,这至少会删除任何事实 非AFNetworking消费者仍然可以在没有锁定的情况下调用它 可能引发竞争条件;但它也非常不漂亮。
直接使用CGImageSource可以做得更多,但可能会更好 溶液
当提及AFNetworking
问题并显示堆栈跟踪时,这似乎是-[UIImage initWithCGImage:scale:orientation:]
调用UITraitCollection
。我在UITraitCollection.h
或UITraitCollection
documentation中找不到任何说明UITraitCollection
是线程安全的内容。
因此,即使UIImage
documentation说UIImage
是线程安全的:
因为图像对象是不可变的,所以你无法改变它们 创建后的属性。大多数图像属性是自动设置的 在附带的图像文件或图像数据中使用元数据。该 图像对象的不可变性也意味着它们可以安全使用 从任何线程。
文档必须意味着在主线程上创建后可以安全使用,或者如果它们仅以串行方式创建,则可以安全使用。 (这就是AFNetworking
fixed their issue的方式。)对于我的解决方法,我转而使用CoreGraphics
:
CGImageRef image = ...
CGSize scaledSize = ...
CGContextRef context = CGBitmapContextCreate(NULL,
scaledSize.width,
scaledSize.height,
CGImageGetBitsPerComponent(image),
CGImageGetBytesPerRow(image),
CGImageGetColorSpace(image),
CGImageGetAlphaInfo(image));
CGImageRef scaledImage;
if (context)
{
CGContextDrawImage(context,
CGRectMake(0,
0,
scaledSize.width,
scaledSize.height),
image);
scaledImage = CGBitmapContextCreateImage(context);
CGContextRelease(context);
}
else
{
scaledImage = NULL;
}
然后,为避免在后台线程上使用UIImageJPEGRepresentation
,我使用ImageIO
导出JPEG数据:
NSData *NSDataFromCGImage(CGImageRef scaledImage)
{
NSMutableData *scaledImageMutableData = scaledImage ? [NSMutableData new] : nil;
CGDataConsumerRef scaledImageDataConsumer = scaledImageMutableData ? CGDataConsumerCreateWithCFData((__bridge CFMutableDataRef) scaledImageMutableData) : NULL;
// from the iOS 9.3 header:
// The `options' dictionary is reserved for future use; currently, you
// should pass NULL for this parameter.
CGImageDestinationRef scaledImageDestination = scaledImageDataConsumer ? CGImageDestinationCreateWithDataConsumer(scaledImageDataConsumer,
kUTTypeJPEG,
1,
NULL) : NULL;
BOOL success = (^BOOL ()
{
if (scaledImageDestination)
{
NSDictionary *addImageOptions = @{(__bridge NSString *)kCGImageDestinationLossyCompressionQuality : @(0.9),
};
CGImageDestinationAddImage(scaledImageDestination,
scaledImage,
(__bridge CFDictionaryRef)addImageOptions);
return (BOOL) CGImageDestinationFinalize(scaledImageDestination);
}
else
{
return NO;
}
})();
if (scaledImageDestination)
{
CFRelease(scaledImageDestination);
}
CGDataConsumerRelease(scaledImageDataConsumer);
if (success)
{
return scaledImageMutableData;
}
else
{
return nil;
}
}