UIGraphicsGetCurrentContext()短寿命(UIGraphicsGetCurr

2019-06-25 17:56发布

我有一个实现徒手绘制一个观点,但我有一个小问题。 我注意到了iPad 3的一切去地狱,所以我试图更新我的绘制代码(可能是因为我应该在第一时间做了),只更新被敲击的部分。 然而,在开放的第一招,以及约10秒闲置后的第一个行程是非常缓慢的。 一切都在“热身”后,它是光滑如黄油,只需要大约每drawRect中0.15ms。 我不知道为什么,但整个视图矩形越来越标记为第一的drawRect为脏,闲置后的第一个drawRect中(当时大约需要150毫秒更新)。 堆栈跟踪显示我的矩形正被重写CABackingStoreUpdate_

我试着不去绘制层如果矩形是巨大的,但后来我的整个背景一片空白(将重新出现,因为我画过旧区像乐透票)。 有没有人有任何想法与UIGraphicsGetCurrentContext()继续? 这是我能想象的麻烦是唯一的地方。 也就是说,我的观点得到了上下文由上下文妖怪所以它需要再次完全自我呈现猛拉。 有没有我可以用它来坚持相同的上下文的任何设置? 还是有别的东西怎么回事...有没有必要为它更新初始显示之后的整个矩形。

我的drawRect很简单:

- (void)drawRect:(CGRect)rect
{
    CGContextRef c = mDrawingLayer ? CGLayerGetContext(mDrawingLayer) : NULL;
    if(!mDrawingLayer)
    {
        c = UIGraphicsGetCurrentContext();
        mDrawingLayer = CGLayerCreateWithContext(c, self.bounds.size, NULL);
        c = CGLayerGetContext(mDrawingLayer);
        CGContextSetAllowsAntialiasing(c, true);
        CGContextSetShouldAntialias(c, true);
        CGContextSetLineCap(c, kCGLineCapRound);
        CGContextSetLineJoin(c, kCGLineJoinRound);
    }

    if(mClearFlag)
    {
        CGContextClearRect(c, self.bounds);
        mClearFlag = NO;
    }

    CGContextStrokePath(c);
    CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
    CGContextDrawLayerInRect(UIGraphicsGetCurrentContext(), self.bounds, mDrawingLayer);
    NSLog(@"%.2fms : %f x %f", (CFAbsoluteTimeGetCurrent() - startTime)*1000.f,  rect.size.width, rect.size.height);

}

Answer 1:

我发现了一个有用的线程上的苹果开发论坛描述这种确切的问题。 它只是因为iOS的5.0存在和理论,这是因为苹果推出了双缓冲系统,所以前两个drawRects永远是满的。 但是,为什么这将空闲后再次发生任何解释。 该理论认为,潜在的缓冲区不是由GPU保证,这将随心所欲地被丢弃,需要重新创建。 该解决方案(直到苹果发出某种真正的解决方案)是ping到缓冲区,这样就不会被释放:

mDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(pingRect)];
[mDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

- (void)pingRect
{
    //Already drawing
    if(mTouchCount > 0) return;

    //Even touching just one pixel will keep the buffer alive
    [self setNeedsDisplayInRect:CGRectMake(0, 0, 1, 1)];
}

唯一的弱点是,如果用户保持其手指完全静止的时间超过5秒,但我认为这是一个可以接受的风险。

编辑相关的更新。 事实证明,简单地调用setNeedsDisplay,就足以让缓冲区活着,即使它立即返回。 所以我说这对我的drawRect方法:

- (void)drawRect:(CGRect)rect
{
   if(rect.size.width == 1.f)
       return;
    //...
}

我们希望,这将抑制用电量,这刷新方法必然会增加。



文章来源: UIGraphicsGetCurrentContext() short lifetime