views:

431

answers:

2

I have been solving the Stanford free iPhone course project called Presence 3 (found on the stanford site: www.stanford.edu/class/cs193p/cgi-bin/downloads.php, which pulls data from twitter for users, which are stored in a plist. A UIActivityIndicator (spinner) is visible while the data is loading. Once the data has been loaded, a TableView displays the users in a list with their photos, and user statuses show up when a user's cell is clicked. I can successfully display the TableView with the photos and bring up another view controller with statuses when clicked. But when I add in the spinner, my program crashes. I set up my program almost identically to the ThreadedFlickrTableView example project, which can also be found at the same link above (sorry, I'm a new user and can only post one link), which works. I put breakpoints in my code to see where the problem was, and I found that the program crashes when it is loading a cell in the cellForRowAtIndexPath method, specifically when it is retrieving the photo from the appropriate array (followeesPhotoURLs). This is because the array is empty - the photos were never downloaded since the main thread decides to execute the cell-loading method before the thread dedicated to downloading from the internet finishes executing (it does start executing).

I looked on the auditors discussion group page for the course and found that someone else had the same problem, but the thread never resolved the issue, and I emailed to no avail: http://groups.google.com/group/iphone-appdev-auditors/browse%5Fthread/thread/ccfc6ae99b4cf45d/ef1b8935e749c7c2?hl=en&lnk=gst&q=presence3#ef1b8935e749c7c2

+1  A: 

My first rule of UITableView is never report sections or rows that aren't ready (with something, even if only a placeholder) because it will crash every time.

The spinner is spinning while the resource is loading. So you are waiting for a resource that may or may not be ready because you don't know the exact state of your background process. How about setting a value in your main thread indicating that things are not ready. Then when your secondary thread finishes loading things you can do performSelectorOnMainThread to cause some main thread function to set the value to indicate you can proceed. Until the value says proceed, your main thread does not try to access those values the secondary thread might be touching. Maybe your cells will display "loading" or similar until the data is ready, or you will just add cells as they become ready.

One more thing - ONLY the main thread can touch the UI. Nothing in UIKit is thread safe unless explicitly stated. The changes to the progress indicator must be handled by the main thread, it should start the indicator and stop it (probably when your secondary thread notifies "done", as above).

Adam Eberbach
A: 

I just finished working through this today and here's the sequence of events that I observed:

  1. Your table view will load up with nothing because your arrays contain nothing
  2. Your thread will go and retrieve Twitter data
  3. Your table view will be refreshed with the Twitter data [self.tableView reloadData]

If you're like me, you try to set the user name using something similar to

cell.textLabel.text = [[userInfo objectAtIndex:indexPath.row] valueForKey:@"name"];

I think that because it is very specific, the application really tries to look for it and doesn't return null if it doesn't find anything, unlike the code in the example which is

cell.text = [photoNames objectAtIndex:indexPath.row];

...so your application errors out the first time it tries to load data with empty arrays.

The way I worked around this is to create an array that loads the user names from the property list at the very beginning so I know how many entries there should be in my array of content. The key part is to create a condition before setting up your cell so that you know you have all the information that you need such as...

    // Set up the cell...
if ([userInfo count] == [userList count]) {

userInfo is my array of dictionaries with the data that comes from Twitter.

userList is my array of values from the property list.

carloandaya