2

I have a button which when pressed makes calls that load information from a series of URLs (about 5 seconds loading time). Right before actually making those calls I want to add a "loading" alert. When I use a UIAlertView the screen dims like it's about to pop up, but it doesn't until the data is loaded - too late! I have no idea what's going on, it's like the calls I'm making to load the data are immediately taking preference over showing the new view, even though they're made right after the calls adding the new view (or showing the alert). This is a summarized version of the code:

-(void) refresh{
   UIAlertView *av = ...
   [av show]; //this should pop up before dat begins to load
   [myDataSource loadData]; //this contains a series of [NSData initWithURL] calls
   [self.tableView reloadData];
   //here I would hide the AlertView, but if I do I see it for just s split second
   //when the tableView has already reloaded
} 

Thanks in advance for any insight!

***EDIT To anyone who uses performSelectorInBackground beware of the added complexities of creating what is effectively a threaded program. For example, leaks might appear as the new thread doesn't have an autorelease pool - you have to add one, etc.

omsid
  • 77
  • 1
  • 6
  • If I am understanding this correctly you’re effectually blocking the calling thread to *schedule the alert to show*, and reload table view items as the view is scheduled. So when the method returns, the table view already knows all the rows to be populated. Can you do this two things separately and asynchronously? Like, using asynchronous performSelector:afterDelay: or dispatch_after() calls, first show the alert then reload data, separately? That might help. – Evadne Wu Mar 03 '11 at 19:14

3 Answers3

1

when you try to retrieve data from the internet (I guess you are using something like [NSString stringWithContentsOfURL: ...]) the main thread is waiting for those data and for this reason the application cannot redraw the interface. You can try to use:

[mySourceData performSelectorInBackground:@selector(loadData) withObject:nil];

Be careful if you are using coredata to lock the NSManagedObjectContext before doing any operation on it and unlock it when you finish.

cescofry
  • 3,706
  • 3
  • 26
  • 22
  • Ok now I understand what's going on, thanks! I oversimplified my code though, the loadData method actually returns an NSArray and from what I can find I can't use performSelectorInBackground if the method returns a value. I'm thinking I can change loadData so it receives an argument which can be the caller, and then when it's done it can notify the caller to say it's done. That would require setting up a protocol, and the class calling loadData would be the delegate right? I haven't done many things like that yet... – omsid Mar 03 '11 at 20:16
  • right. Also as @Bogatyr suggests you can use NSOperation with NSOperationQueue. – cescofry Mar 03 '11 at 20:25
  • Ok it's all fixed! I set up my protocol, and when the data is loaded my "loading"view gets removed just fine. So basically the method I call to get the data is now (void)loadData:(id)caller. – omsid Mar 03 '11 at 20:54
1

If you have a bunch of operations to perform, in addition to performSelectorInBackground: like cescofry wrote, you can use NSOperation and NSOperationQueue.

Bogatyr
  • 19,255
  • 7
  • 59
  • 72
  • Thanks for the response, I might need to use these in the future with more intensive tasks. – omsid Mar 03 '11 at 20:37
  • One of the really cool things about NSOperationQueue is you get to dial up/down your concurrency trivially, even dynamically in code if you want. – Bogatyr Mar 03 '11 at 20:49
0

You probably don't want an UIAlertView for this anyway. Take a look at MBProgressHUD on GitHub.

Mark Adams
  • 30,776
  • 11
  • 77
  • 77
  • I actually also tried using this (it is much nicer), but basically the same thing happened - the view didn't show up until the table was reloaded! If I figure out what caused both those things I'll probably end up using MBProgressHUD, but for now the fact that the screen dims but the alert doesn't show is maybe more telling. – omsid Mar 03 '11 at 19:15
  • If `-loadData` is a lengthy operation, you should be performing it in a background thread anyway as to not block the UI. Are you building for 4.0+? If so I would seriously suggest taking advantage of GCD and wrapping `-loadData` in a dispatch_async() call. The added benefit is that when dual core iOS devices become standard, your code will essentially be twice as fast overnight. – Mark Adams Mar 03 '11 at 19:18