2011-12-16 42 views
1

我正在使用CATiledLayer作爲我的UIView的背景層,我已將其放入UIScrollView。在我的視圖的init方法中,我創建了繪製簡單線條的CGPathRef對象。當我試圖在drawLayer:inContext中繪製此路徑時,它在滾動/縮放時偶爾會與EXEC_BAD_ACCESS(很少)一起崩潰。CATiledLayer在繪製先前準備好的CGPath時崩潰

代碼是很簡單的,我使用的唯一標準CG *功能:

- (id)initWithFrame:(CGRect)frame 
{ 
    self = [super initWithFrame:frame]; 
    if (self) { 
     CATiledLayer *tiledLayer = (CATiledLayer *)[self layer]; 
     tiledLayer.levelsOfDetail = 10; 
     tiledLayer.levelsOfDetailBias = 5; 
     tiledLayer.tileSize = CGSizeMake(512.0, 512.0); 

     CGMutablePathRef mutablePath = CGPathCreateMutable(); 
     CGPathMoveToPoint(mutablePath, nil, 0, 0); 
     CGPathAddLineToPoint(mutablePath, nil, 700, 700); 
     path = CGPathCreateCopy(mutablePath); 
     CGPathRelease(mutablePath); 
    } 
    return self; 
} 

+ (Class) layerClass { 
    return [CATiledLayer class]; 
} 

- (void) drawRect:(CGRect)rect { 
} 

- (void) drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx { 
    CGContextSetRGBFillColor(ctx, 1, 1, 1, 1); 
    CGContextFillRect(ctx, self.bounds); 

    CGContextSetLineWidth(ctx, 5); 

    CGContextAddPath(ctx, path); 
    CGContextDrawPath(ctx, kCGPathStroke); 
} 

- (void)dealloc { 
    [super dealloc]; 
} 

更新: 我已經noiced一種只存在於iOS 5的這個問題,它的工作原理罰款4.3

+0

調試EXEC_BAD_ACCESS很簡單,當你打開NSZombieEnabled時,它會告訴你哪個被釋放的變量被調用。 – Wolfert 2011-12-16 12:03:45

+0

但在這段代碼中,不可能對內存做一些壞事,無論如何它只發生在CATiledLayer和多線程中。 – 2011-12-16 13:04:13

回答

5

嘗試在自定義MKOverlayView上繪製緩存的CGPath對象時遇到類似的問題。

可能會發生崩潰,因爲CGPath不能同時在多個線程上繪製 - 它是一個不透明的類(在文檔中指定)包含一個指向其點數組中的當前點的指針。兩個或多個線程在繪製數據時同時迭代該數組可能會導致未定義的行爲和崩潰。

我工作圍繞這通過複製CGPath對象到每個線程繪圖(包含一個互斥鎖內,以避免不完全的複製):

//lock the object's cached data 
pthread_mutex_lock(&cachedPathMutex); 
//get a handle on the previously-generated CGPath (myObject exists on the main thread) 
CGPathRef myPath = CGPathCreateCopy(myObject.cachedPath); 
//unlock the mutex once the copy finishes 
pthread_mutex_unlock(&cachedPathMutex); 

// all drawing code here 
CGContextAddPath(context, myPath); 
... 
... 
CGPathRelease(myPath); 

如果你擔心做副本的內存開銷每個線程,你也可以直接在高速緩存CGPath對象的工作,但互斥量將在整個繪製過程保持鎖定(其中一種失敗螺紋拉絲的目的):

//lock the object's cached data 
pthread_mutex_lock(&cachedPathMutex); 

//get a handle on the previously-generated CGPath (myObject exists on the main thread) 
CGPathRef myPath = myObject.cachedPath; 

// draw the path in the current context 
CGContextAddPath(context, myPath); 
... 
... 

//and unlock the mutex 
pthread_mutex_unlock(&cachedPathMutex); 

我會資格我的回答是這樣說的我不是使用Quartz進行多線程繪圖的專家,只是這種方法解決了我的場景中的崩潰問題。祝你好運!

更新: 我重新審視了這個代碼,現在iOS 5.1.0已經不存在了,它看起來像這個問題的根本原因可能實際上是iOS 5.0.x中的Quartz中的一個錯誤。在iOS 5.1.0上使用CGPathCreateCopy()和互斥體調用進行測試時,我看不到任何iOS 5.0.x上發生的崩潰。

//get a handle on the previously-generated CGPath (myObject exists on the main thread) 
CGPathRef myPath = myObject.cachedPath; 

// all drawing code here 
CGContextAddPath(context, myPath); 
... 
... 
//drawing finished 

因爲沒準我們會支持的iOS 5.0.x的一段時間,它不會傷害到在你的代碼的互斥體(除輕微的性能損失等),或者只需運行一個版本檢查繪圖前。