[更新:此問題已解決;這個問題不在drawInRect:
,但在UIGraphicsBeginImageContext()
]必須drawInRect:在主線程上執行一個單獨的上下文嗎?
在我的應用程序,我抓住一堆大圖像,剪裁縮略圖大小和存儲縮略圖預覽。
請注意,我在單獨的圖像上下文中執行此操作 - 這是而不是有關重新繪製屏幕上的UIView
。
此代碼相當密集,所以我在單獨的線程中運行它。實際的比例是這樣的,而且是對UIImage
頂部的類別執行:
- (UIImage *) scaledImageWithWidth:(CGFloat)width andHeight:(CGFloat)height
{
CGRect rect = CGRectMake(0.0, 0.0, width, height);
UIGraphicsBeginImageContext(rect.size);
[self drawInRect:rect]; // <-- crashing on this line
UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return scaledImage;
}
這是從一個單獨的方法,它通過將圖像中的循環轉,做了處理調用。上述方法的實際調用看起來是這樣的:
UIImage *small = [bigger scaledImageWithWidth:24.f andHeight:32.f];
這一切工作的大部分時間,但偶爾我得到一個EXC_BAD_ACCESS
。
回溯:
#0 0x330d678c in ripc_RenderImage()
#1 0x330dd5aa in ripc_DrawImage()
#2 0x300e3276 in CGContextDelegateDrawImage()
#3 0x300e321a in CGContextDrawImage()
#4 0x315164c8 in -[UIImage drawInRect:blendMode:alpha:]()
#5 0x31516098 in -[UIImage drawInRect:]()
#6 0x0000d6e4 in -[UIImage(Scaling) scaledImageWithWidth:andHeight:] (self=0x169320, _cmd=0x30e6e, width=48, height=64) at /Users/me/Documents/svn/app/trunk/Classes/UIImage+Scaling.m:20
#7 0x00027df0 in -[mgMinimap loadThumbnails] (self=0x13df00, _cmd=0x30d05) at /Users/me/Documents/svn/app/trunk/Classes/mgMinimap.m:167
#8 0x32b15bd0 in -[NSThread main]()
#9 0x32b81cfe in __NSThread__main__()
#10 0x30c8f78c in _pthread_start()
#11 0x30c85078 in thread_start()
[更新4]當我在模擬器中運行這個,還有這個問題發生,控制檯還顯示以下內容:
// the below is before loading the first thumbnail
<Error>: CGContextSaveGState: invalid context
<Error>: CGContextSetBlendMode: invalid context
<Error>: CGContextSetAlpha: invalid context
<Error>: CGContextTranslateCTM: invalid context
<Error>: CGContextScaleCTM: invalid context
<Error>: CGContextDrawImage: invalid context
<Error>: CGContextRestoreGState: invalid context
<Error>: CGBitmapContextCreateImage: invalid context
// here, the first thumbnail has finished loading and the second one
// is about to be generated
<Error>: CGContextSetStrokeColorWithColor: invalid context
<Error>: CGContextSetFillColorWithColor: invalid context
我的直覺是,我偶爾最終會嘗試drawInRect:
,而操作系統也在嘗試繪製某些東西,偶爾會導致崩潰。我總是推測,只要你不畫實際的屏幕,這是可以接受的 - 是不是這種情況?或者如果是這樣的話,有什麼想法可能會造成這種情況?
更新(r2):我忘了提及這個應用程序運行在相當嚴重的內存限制下(我有很多圖像在任何給定的時間加載,這些交換進/出),所以這可能是內存不足的情況(繼續閱讀 - 不是)。但我不確定如何驗證,所以對此的想法也會受到歡迎。我通過嚴格減少正在加載的圖像數量並添加一個檢查以確保它們正確地釋放(它們是,並且崩潰仍然發生)來驗證這一點。
更新3:我以爲我發現了這個問題。下面是我寫的答案,在崩潰再次發生之前:
代碼會(在我發佈此問題後)偶爾以退出代碼0
開始退出,有時退出代碼爲10 (SIGBUS)
。 0
意味着「沒有錯誤」,所以這是非常奇怪的。 10
似乎意味着一切,所以這也無濟於事。但是,當碰撞發生在那裏時,電話drawInRect:
是一個很大的暗示。
通過循環顯示縮略圖,生成了許多自動發佈的圖像。我有一個autorelease池,但它包裝整個for循環。我添加了第二個自動釋放池for
循環中:
- (void)loadThumbnails
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
for (...) {
NSAutoreleasePool *cyclePool =
[[NSAutoreleasePool alloc] init]; // <-- here
UIImage *bigger = ...;
UIImage *small = [bigger scaledImageWithWidth:24.f andHeight:32.f];
UIImage *bloated = [i scaledImageWithWidth:48.f andHeight:64.f];
[cyclePool release]; // <-- ending here
}
[pool release];
}
我想上面的固定問題,直到我跑的應用程序,它與「退出代碼0」又不僅限於之前墜毀,機上我。回到繪圖板...
從iOS4.0開始繪製到UIKit中的圖形上下文現在是線程安全的。具體來說: 用於訪問和操作圖形上下文的例程現在可以正確處理駐留在不同線程上的上下文。參考:http://developer.apple.com/library/ios/#releasenotes/General/WhatsNewIniPhoneOS/Articles/iPhoneOS4.html#//apple_ref/doc/uid/TP40009559-SW29 – MattyG 2011-09-14 04:03:44
感謝您的發現,MattyG。絕對有趣。 – Kalle 2011-10-03 16:10:56
@Kalle:你改變了什麼代碼?你可以分享嗎? – 2014-10-02 09:52:58