Reputation: 467
I'm working on an application using AFN to handle my API calls. I'm trying to use the prepare for segue method to initialize some data in the destination view controller. The problem is that, since AFNetworking does its work in the background thread and then runs success:/failure: on the main thread, My segue happens before my success block, and none of the data I need to be passed to the destination VC is getting there.
My question is two-fold:
1) is there a way to block the main thread in prepareForSegue
until AFNetworking finishes running on the background thread so I can utilize the response object before the segue occurs?
2) This seems like a pretty common design issue. Am I going about doing this the wrong way? Should I be making my network call in prepareForSegue
at all?
Here's what I'm trying to do in code:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:@"mySegue"])
{
// Get reference to the destination view controller
DestinationViewController *vc = [segue destinationViewController];
NSMutableArray* responseArray = [[AFNClient sharedClient] getDataWithParameters:@{@"param":@"param"}
CompletionBlock:^(NSError *error) {}]];
//I want to block here
NSLog(@"%@", [vc responseArray]); // <-This logs as an empty array because it's running parallel to to AFN
[vc setArray:responseArray]
}
}
and heres my AFNClient
method definition for getDataWithParameters:CompletionBlock
- (NSMutableArray*) getDataWithParameters:(NSDictionary*)parameters
CompletionBlock:^(NSError *error)block
{
NSMutableArray *returnArray = [[NSMutableArray alloc] initWithArray:@[]];
//build path string
NSString *pathString = @"apiPath"
[self GET:pathString parameters:parameters
success:^(NSURLSessionDataTask *task, id responseObject) {
[returnArray setArray:responseObject];
block(nil);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
block(error);
}];
return returnArray;
}
Thanks in advance for any help! -JA
Upvotes: 0
Views: 604
Reputation: 5935
You don't really want to block threads at all. Open your new view controller with a view on top that just has a label that says "Downloading..." (or run a spinner). In the completion block of your download, call a routine on the main thread [self performSelectorOnMainThread...] that updates all the values in your new view controller, and removes your "Downloading..." view and/or spinner. This will show the new view, but incomplete until the data comes in, then gets updated with the data and the view that tells the user he has to wait gets taken down.
Upvotes: 3
Reputation: 119242
Blocking the main thread while waiting for network access is in any top ten list of things you never do in an iOS app.
I'm not sure why you think you need to block the main thread. Normally you'd have a loading spinner or some indicator in the relevant view which is removed when the network call is complete. You could use the comlletion block in the code above to pass any information into the destination view controller, or you could move the networking code into the other view controller and just pass the parameters along in prepare for segue.
Upvotes: 2