I recently needed to embed the ‘Discrete’ variant of the NSLevelIndicatorCell into an NSTableView. The discrete cell looks like this:
Unfortunately adding the cell caused drawing of the table’s window to slow to crawl. The spinning beachball of death would often appear when I was merely resizing the window. After some quick experimented I narrowed it down to something within the ‘Discrete’ variant of the NSLevelIndicatorCell, the other variants had no such performance problems.
It didn’t take an expert in Shark to realise what was going on:
It looked like NSLevelIndicatorCell was perform an expensive gaussian blur per cell, possibly even for each discrete block within each cell. For a single NSLevelIndicatorCell that shouldn’t be a real problem, but for a whole table column full of them it could create major performance problems.
Some quick google searches showed that people had complained about poor NSLevelIndicatorCell performance before but failed to find a solution.
Switching to another variant of NSLevelIndicatorCell wasn’t an option, the ‘Discrete’ variant was just too sexy. So the obvious solution was to create a subclass of NSLevelIndicatorCell that posed as the real thing, but cached the drawing code of its parent class into NSImages. So I present to the the world the imaginatively titled CCachingLevelIndicatorCell.
CCachingLevelIndicatorCell is designed to pose as NSLevelIndicatorCell but shouldn’t require any other configuration. The class will only cache images for the ‘Discrete’ variant and will use a dictionary of NSImage objects to cache the drawing (one image per discrete value the cell can display). If any other attribute of the cell is changed the class will discard the cache and attempt to recache the drawing at the next opportunity.
Just so you can compare the differences in speed I’ve created two stand-alone test applications so you can compare the speed without CCachingLevelIndicatorCell and with it posing as NSLevelIndicatorCell. The binaries are checked into my public subversion.
Radar bug: rdar://problem/4601201