I’m writing an iPad app and have a problem with ui responsiveness / lock up.
I have a UITableView with items, when an item is clicked, it goes out on the internet and fetches that item and displays it. The rest of the program (not shown) will use the item downloaded, so only one item can be downloaded at a time.
Fetching the item can take a long time. During that time I want the user to still be able to scroll around the UITableView, but not to be able to select anything until the previous item clicked has been downloaded.
I know this can be done using threads,blocks, and callbacks, but right now I don’t have time to do that (impossible time constraint).
I thought a quick way would be to download it sequentially and use run loops and a flag like this two step process:
-
When the user clicks on a table cell didSelectRowAtIndexPath is called, in there I set a global flag, then call the download method to download the item. If the user clicks on another item (before the download is completed, it will see the flag checked and exit that function without downloading anything. Basically this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { static BOOL alreadyInHere=FALSE; if (alreadyInHere) return; alreadyInHere=TRUE; .... downloadItem(...); ShowAndUseItem(...); alreadyInHere=FALSE; }This allows the user to select only one item at a time.
-
To allow the user to be able to still scroll around the UITableView during the long download, I put in a run loop in the downloadItem(…) method shown above like this…
-(void) downloadItem(....) { BOOL downloading=TRUE; callFunctionsToStartdownload(...); // while (downloading) { downloading=DownloadSomeBytes(...); CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.5, YES); } }
The result of (1) and (2) is that the user can still scroll around the UITableView during the sequential download, the alreadyInHere flag prevents them from selecting something and starting another download.
This works in most cases, but around 50% of the time, during the download, the UITableView becomes unresponsive (can’t scroll to other items in the table), and even after the download didSelectRowAtIndexPath is never called again when you click on something making theUITableView basically locked up.
My question is, did I do the runLoop correctly?
I know there are other ways to do it, but I have to do it using this general method for now because of other reasons.
Thanks
You should not try to download or do any other potentially long activity in youR tableview didSelectRow method. Exit (return) from this UI method after setting up an asynchronous download so that you don’t lock up the UI.
Locking out simultaneous downloads is still ok, but you want be careful to reset state after errors or timeouts.