Остановить рисование CATiledLayer

Можно ли остановить CATiledLayer для рисования (drawLayer: inContext)? Он рисует асинхронно, и когда я пытаюсь освободить CGPDFDocumentRef, который используется CATiledLayer, приложение вылетает (EXC_BAD_ACCESS).

Что мое мнение:

@implementation TiledPDFView

- (id)initWithFrame:(CGRect)frame andScale:(CGFloat)scale{
    if ((self = [super initWithFrame:frame])) {

        CATiledLayer *tiledLayer = (CATiledLayer *)[self layer];
        tiledLayer.levelsOfDetail = 4;
        tiledLayer.levelsOfDetailBias = 4;
        tiledLayer.tileSize = CGSizeMake(512.0, 512.0);
        myScale = scale;
    }
    return self;
}

// Set the layer class to be CATiledLayer.
+ (Class)layerClass {
    return [CATiledLayer class];
}

- (void)stopDrawing{
    CATiledLayer *tiledLayer = (CATiledLayer *)[self layer];
    [tiledLayer removeFromSuperlayer];
    tiledLayer.delegate = nil;
}
// Set the CGPDFPageRef for the view.
- (void)setPage:(CGPDFPageRef)newPage
{
    CGPDFPageRelease(self->pdfPage);
    self->pdfPage = CGPDFPageRetain(newPage);

    //self->pdfPage = newPage;
}


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


// Draw the CGPDFPageRef into the layer at the correct scale.
-(void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context
{   

    // First fill the background with white.
    CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
    CGContextFillRect(context,self.bounds);

    CGContextSaveGState(context);
    // Flip the context so that the PDF page is rendered
    // right side up.
    CGContextTranslateCTM(context, 0.0, self.bounds.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    // Scale the context so that the PDF page is rendered 
    // at the correct size for the zoom level.
    CGContextScaleCTM(context, myScale,myScale);    
    CGContextDrawPDFPage(context, pdfPage);
    CGContextRestoreGState(context);

}

// Clean up.
- (void)dealloc {
    CGPDFPageRelease(pdfPage);

    [super dealloc];
}

И вот где я пытаюсь остановить и выпустить PDF в виде контроллера: v является экземпляром TiledPDFView

 -(void) stopDwaring {
     [v stopDrawing];
     [v removeFromSuperview];
     [v release];
     [self.view removeFromSuperview];
     self.view = nil;
     CGPDFDocumentRelease(pdf);

 }

Ответ 1

этот пост помог мне решить мою собственную проблему с CATiledLayer. В качестве примера я использовал TiledPDFview.m из документации Apple. Поскольку в какой-то момент мне нужно перерисовать весь вид и все плитки, я использую свойство CATiledLayer как свойство. При выходе и освобождении диспетчера представлений он сработал с [CATiledLayer сохранить]: сообщение отправлено на освобожденный экземпляр. Вот мой метод dealloc контроллера вида:

- (void)dealloc {
    self.tiledLayer.contents=nil;
    self.tiledLayer.delegate=nil;
    [self.tiledLayer removeFromSuperlayer];

    // note: releasing the layer still crashes- 
    // I guess removeFromSuperlayer releases it already, 
    // but couldn't find documentation so far.
    // So that why it commented out:
    // [self.tiledLayer release], self.tiledLayer=nil;

    //release the other viewcontroller stuff... 
    [super dealloc];
}

Это работает для меня. Надеюсь, это поможет кому-то.

Ответ 2

Удалите CATiledLayer из своего суперслоя перед выпуском CGPDFDocumentRef.

[yourTiledLayer removeFromSuperlayer];

Не забудьте также установить делегат на нуль.

yourTiledLayer.delegate = nil;

После этого вы можете безопасно освободить CGPDFDocumentRef.

Изменить после добавления кода OP:

Вы получили pdfPage с помощью CGPDFDocumentGetPage()? Если это так, вы не должны его выпускать, это автореализованный объект.

Относительно того, как добавить его в качестве подуровня: Вам не нужен TiledPDFView. В вашем контроллере просмотра вы можете просто сделать это:

CATiledLayer *tiledLayer = [CATiledLayer layer];
tiledLayer.delegate = self; //sets where tiledLayer will look for drawLayer:inContext:
tiledLayer.tileSize = CGSizeMake(512.0f, 512.0f);
tiledLayer.levelsOfDetail = 4;
tiledLayer.levelsOfDetailBias = 4;
tiledLayer.frame = CGRectIntegral(CGRectMake(0.0f, 0.0f, 512.0f, 512.0f));
[self.view.layer addSublayer:tiledLayer];

Затем переместите drawLayer: inContext: реализация в ваш контроллер представления.

Затем в вашем представлении контроллер dealloc, отпустите его как:

[tiledLayer removeFromSuperlayer];
tiledLayer.delegate = nil;
CGPDFDocumentRelease(pdf);

Обратите внимание, что вы не можете сделать это в подклассе UIView, поскольку drawLayer: inContext: будет конфликтовать с основным слоем UIView.

Ответ 3

object.layer.contents = Nil

Это должно дождаться завершения потока. Это помогло мне в моем случае.

Ответ 4

TiledPDFView * pdfView;

В dealloc класса просмотра pdfView, напишите ниже строку кодов.

  - (void)dealloc {
        if (nil != self.pdfView.superview) {
            self.pdfView.layer.delegate = nil;
            [self.pdfView removeFromSuperview];
        }
 }

Это работает для меня. Надеюсь, это поможет.

Ответ 5

У меня была аналогичная проблема. Я закончил настройку переменной float "zoom" в моем TiledPDFView, которую я установил как zoomScale PDFScrollView в методе делегата UIScrollview: scrollViewDidZoom

Затем в моем методе drawLayer внутри TiledPDFView я вызывал только содержимое этого метода, если переменная float "zoom" была выше 2. Это устраняет любые проблемы, связанные с тем, кто покидает представление без масштабирования. Это может быть не идеально для вашего случая, так как эта ошибка все еще возникает, если кто-то увеличивает изображение выше 2, а затем быстро освобождает диспетчер представлений, но вы можете найти подобный метод для покрытия всех баз.

Ответ 6

Похоже, вы делаете то же самое, что и я, который заимствует код ZoomingPDFView и интегрирует его в ваш проект. Если ваши методы делегатов UIScrollView в PDFScrollView не изменяются, вы можете решить свою проблему, просто комментируя обе строки вашего метода dealloc (в TiledPDFView). В любом случае, это должно происходить только тогда, когда вы убиваете родительский вид.