2011-12-16 40 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的一段时间,它不会伤害到在你的代码的互斥体(除轻微的性能损失等),或者只需运行一个版本检查绘图前。