macoscocoaikimagebrowserview

CALayer only painting on input events


I have a Mac app that's using IKImageBrowserView. I've subclassed IKImageBrowserView and I'm returning a custom cell type from newCellForRepresentedItem.

In my cell, I'm creating and returning a layer from layerForType:

// When asked for a foreground layer, return a new layer that we'll render the icon decorations into
- (CALayer *)layerForType:(NSString *)type {
    if ([type isEqualToString:IKImageBrowserCellForegroundLayer]) {
        @synchronized(self) {
            if (!self.foregroundLayer) {
                self.foregroundLayer = [[CALayer alloc] init];
                self.foregroundLayer.delegate = self;
                self.foregroundLayer.needsDisplayOnBoundsChange = YES;
                [self.foregroundLayer setNeedsDisplay];
            }
        }

        return self.foregroundLayer;
    } else {
        return [super layerForType:type];
    }
}

I have my cell observing an object, and calling setNeedsDisplay on my custom layer when it changes.

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
{
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        self.percentDone = (float)self.bytesSoFar/self.bytesTotal;
        NSLog(@"Update");
        [self.foregroundLayer setNeedsDisplay];
    }];
}

Here's the problem I'm having: The download proceeds, the object being observed fires the observer (so observeValueForKeyPath is called) and setNeedsDisplay is called. I verified this by logging with NSLog messages.

But the drawing method:

- (void)drawLayer:(CALayer *)theLayer
        inContext:(CGContextRef)theContext
{
    NSLog(@"Drawing");
    // Drawing happens here 
}

What I'm seeing is that the drawing starts out okay - printing "Update" and "Drawing" interleaved - but after a short time, the "Drawing" stops and just the "Update" messages continue.

If I click in the image browser, or tap a key on the keyboard, the "Drawing" resumes for a short while, and then stops, back to just "Update".

It's like I need to trigger a repaint using the keyboard or mouse - the setNeedsDisplay isn't doing it - but I don't understand why. It does work for a short time, stops working, then only works while I'm providing mouse input.

This has me baffled. I'd appreciate any suggestions.


Solution

  • I didn't find the problem here, but I did find a solution.

    Invalidating IKImageBrowserView cells doesn't cause them to be repainted because IKImageBrowserView, probably for performance, doesn't redraw cells unless their version changes.

    Instead of invalidating the cell, I now increment the imageVersion returned by my IKImageBrowserItem, and then invalidate the IKImageBrowserView. This reliably redraws the item.