-[UITableView dequeueReusableCellWithIdentifier:], Storyboard, and VoiceOver – doesn’t work

hsoi blog, talk 6 Comments

I’m starting to explore the iOS Accessibility support, specifically VoiceOver.

As I was working, it was frustrating to see my app constantly crashing every time a UITableView would try to come up. Not really a crash, but a failed assertion. It’d look something like:

‘UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:’

Thing is, I was returning a non-nil cell. Or so I thought.

This app is using iOS 5 and Xcode 4.2’s new UI-designer feature, Storyboard. One thing I really like about Storyboard is the built-in support for making UITableView’s right within the .storyboard file. In this particular case, the UITableView was using a single prototype cell. Apple’s “Converting to Storyboard Release Notes” notes a specific change for -tableView:cellForRowAtIndexPath: about how to handle -dequeueReusableCellWithIdentifier:.

The dequeueReusableCellWithIdentifier: method is guaranteed to return a cell (provided that you have defined a cell with the given identifier). Thus there is no need to use the “check the return value of the method” pattern as was the case in the previous typical implementation of tableView:cellForRowAtIndexPath:. Instead of:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// Configure and return the cell.

you would now write just:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure and return the cell.

This is a welcome change, and it makes sense. Since you have a storyboard, since you are providing the prototype cell, the table should always get a cell for reuse. The only reason you had to do the nil check was to create the cell in the first place, if there wasn’t one for reuse.

I’m following the new paradigm, I expected to never get nil, but in fact I was.

But I was only getting nil when I was running with VoiceOver.

Turn VoiceOver on, fail. Turn VoiceOver off, no fail.

I can only think VoiceOver is somehow involved.

I have submitted a bug to Apple, rdar://problem/10810435. From searching around, it seems others have experienced and reported this as well. One report I saw reported against an iOS 5.1 beta, which doesn’t make me happy. I’d like to hope this would be fixed in the next iOS update.

But, we can work around it for now.

The UITableView in the .storyboard doesn’t have any cells, static nor prototype. The UITableViewCell resides in a lone .xib file and is loaded on demand. This is the same technique discussed in Apple’s “Table View Programming Guide for iOS” in the section discussing how to customize cells, Loading Custom Table-View Cells From Nib Files, The Technique for Dynamic Row Content. Just do that, seems to be working fine.


Comments 6

  1. Just ran in to the same problem. Thanks for the writeup.
    Now off to rewrite some tables.

  2. Post

    I submitted a bug report to Apple (Bug ID# 10810435) and they have confirmed it as a known issue (Bug ID# 10487852).

    You should consider submitting a bug report to Apple as well. Apple takes duplicates as a measure of how widespread the problem is, how badly it’s affecting developers and users. So add your voice, which MAY help bump up the priority of fixing it.

  3. Post

    Good deal. I’m sure it will come back marked as duplicate, but every report hopefully makes it clear to them that this is a big problem and needs to be fixed a.s.a.p.. Thank you for taking the time and trouble to report bugs.

  4. Glad I’m not the only one experiencing this issue. Seems ironic that a feature meant to increase accessibility is actually decreasing it.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.