2
votes

Please see this simple CATiledLayer example https://github.com/seanhess/CATiledLayer-Example

It consists of one viewController with a hierarchy like this:

view: (frame = window size)
    scrollView: (frame = window size, content size = 200 x 4000)
        contentView: (frame = content size = 200 x 4000, tile size = 100 x 100)

The content view's layer has been overriden to be a CATiledLayer.

If you run the linked code, you'll see that tiles with the same rect are requested multiple times. It happens both when you first run the code, and when you scroll.

Switch to branch "one-column" - it only happens on init, never when you scroll down.

Switch to branch "default-tile-size" - it only happens on init, but very rarely (you have to run it multiple times before it happens)

I'm trying to write some code in drawLayer:inContext: that locates the correct data and draws it. It could be expensive, and I don't want to do it more than once.

Any idea what is going on? What could I do differently?

5
I suspect that nobody really knows CATiledLayer very well, aside from using it to draw huge images. :( Suggestions on where to go for help?Sean Clark Hess
I'm seeing the same thing. I have a small demo app with just 12 tiles that show on the screen without scrolling and the drawing code gets called 22 times. I'll keep looking into this, too.EricK
Amongst the other issues with CATiledLayer, I was wondering the same. Maybe you could separately track which tiles have been requested and simply skip expensive operation for the rect that has been already requested?TheBlack
@TheBlack - that is what I ended up doing, but I'll check out EricK's stuff, below.Sean Clark Hess

5 Answers

2
votes

This is a bug in IOS. It happens when the CPU is dual-core, in that case there are two threads each requesting each tile. That means that the bug is present in the simulator, and on the iPhone 4S, but not on the other iPhone models. I assume it will also be present on dual-core iPads.

I have reported the bug to Apple long ago already (for the simulator) and recently again (for the iPhone 4S). Apple recently gave the impression that they have solved it in IOS 6.

1
votes

Very well solved here:

https://stackoverflow.com/a/8783396/341994

The problem is that (at least in my testing) drawRect: is called simultaneously on two threads. By logging, I can see individual lines of my code being executed twice before we go on to the next line, which is also executed twice! The logging shows that this is because one thread is executing a line and then another thread is executing the same line - and then they both go on to the next line.

This is as nasty as it gets. The solution is to wrap the the whole interior of drawRect: in a dispatch_sync on a serial queue.

0
votes

Have you tried your code on a device? I consistently see this behavior in the simulator, but not on my iPad 1. I just tried this again in an app that is displaying a large tiled image. My tile size is 256 and on the device my drawRect: method is being called 12 times, which is how many tiles are on the screen. In the simulator, the method gets called between 20 and 23 times, with all but the last few tiles being drawn twice.

0
votes

Isn't this due to the setLevelsOfDetailBias ? When I leave everything standard the tiles only get rendered once (testing on the device). But when I set the levelofdetailbias to 2, the tiles get loaded multiple times. I think that's due to the fact that CATiledLayer just starts caching extra detail levels when the device is idle.

0
votes

In the end, the answers didn't work. It is fairly simple, though, to make your delegate method be aware of whether or not it has drawn that cycle.