I want to display an activity indicator while performing some network calls in a dispatch_group_asyc block. But activity indicator only shows when the block finishes. I'm creating a dispatch_group_t because I need to get the result of the network calls before performing some other tasks. This is a simplified version of my code:
- (BOOL)doNetCall
{
[activityIndicator startAnimating];
__block BOOL netResult = NO;
dispatch_queue_t queue = dispatch_queue_create(netQueue, NULL);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group,queue,^{
netResult = [service queryService];
});
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(group);
dispatch_release(queue);
[activityIndicator stopAnimating];
if (netResult) {
// Perform some tasks
}
else {
[self showAlertView];
}
return netResult;
}
What am I doing wrong? Thanks!
EDIT: I need the method to wait until the block finishes in order to return the result I get
You should use activity indicator in this way:
[activityIndicator startAnimating];
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
// Do something...
dispatch_async(dispatch_get_main_queue(), ^{
[activityIndicator stopAnimating];
});
});
If you're using group, just rewrite your code a little bit.
There doesn't appear to be any need for a dispatch group with what you are doing. Try this:
- (void)buttonClicked {
[activityIndicator startAnimating];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
BOOL netResult = [service queryService];
dispatch_async(dispatch_get_main_queue(), ^{
[activityIndicator stopAnimating];
if (netResult) {
// perform some tasks
} else {
// show alert
}
});
});
}
If you have your queue, replace the call to dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) with your own queue.
Related
Hi I m using dispatch_group_t for async web call and during that wait period I want to show activity indicator.
Here is my code which is not working for show/hide activity indicator.
- (BaseResponse*)getResponse:(BaseRequest*)request{
request.header = [[Header alloc]init];
request.header.osType = 2;
NSString *jsonBody = [request toJSONString];
NSURL *requestURL = #"myurl";
__block BaseResponse *baseResponse;
[self showHUDProcessView]; //here activity indicator should start animating but not working as per expected.
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
[[COMHandler sharedCOMHandler] makeServiceCall:jsonBody requestURL_:requestURL completion:^(ComResponse *comResponse){
[self hideHUDProcessView]; //hide activity when receive response
if (comResponse != nil) {
baseResponse = comResponse;
}else{
//show alert
}
dispatch_group_leave(group);
}];
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
return baseResponse;
}
- (void) showHUDProcessView {
[MBProgressHUD showHUDAddedTo:viewController.view animated:YES];
}
- (void) hideHUDProcessView {
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
[MBProgressHUD hideHUDForView:viewController.view animated:YES];
});
});
}
I also tried with starting group in block but also not work..
Tried
dispatch_semaphore_t activity = dispatch_semaphore_create(0);
//show indicator
^myblock {
//hide indicator
dispatch_semaphore_signal(activity);
}
dispatch_semaphore_wait(activity, DISPATCH_TIME_FOREVER);
also but no luck.
Can anybody suggest me when i m doing wrong??
Or want else I can do to achieve this indicator show/hide issue.
Asynchronous block be called in function, add these multiple functions into a group,process all results of blocks when all block execute completely.Is there a common and smart method to implement?
like dispatch_group_notify ,completionBlock
dispatch_group_t _blockTaskGroup;
.....
if (!_blockTaskGroup) {
_blockTaskGroup = dispatch_group_create();
}
dispatch_group_notify(_blockTaskGroup, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSLog(#"finally!");
});
....
dispatch_group_enter(_blockTaskGroup);
[XXXXX computeInBackground:xx completion:^{
NSLog(#"1 done");
dispatch_group_leave(group);
}];
//
dispatch_group_enter(_blockTaskGroup);
[XXXXX computeInBackground:xx completion:^{
NSLog(#"2 done");
dispatch_group_leave(_blockTaskGroup);
}];
//
dispatch_group_enter(_blockTaskGroup);
[XXXXX computeInBackground:xx completion:^{
NSLog(#"3 done");
dispatch_group_leave(_blockTaskGroup);
}];
I want to create 2 async queues with completion blocks and after finished this blocks I want to run some action. I can not achieve it with this code. Where my bad?
dispatch_queue_t queue = dispatch_queue_create("com.company.queue", 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
// block 1
dispatch_group_async(group, queue, ^{
[[WebRequests sharedInstance] request:#{#"type" : [NSNumber numberWithInt:request_uploadAdv], #"adv" : adv} withCompletion:^(id response) {
BOOL success = [response boolValue];
NSLog(#"done1 text");
// block 1 Done
}];
});
// block 2 //картинки
dispatch_group_async(group, queue, ^{
[self getImagesForAdv:adv completion:^(NSArray *images) {
[[WebRequests sharedInstance] uploadPhotos:images completion:^(BOOL success) {
uploadImagesSuccess = YES;
NSLog(#"done1 2\n");
// block 2 Done
}];
}];
});
dispatch_group_notify(group, queue, ^{
printf("all tasks are finished!\n");
});
First, you're missing a }); in there somewhere. Second, there's no need for the outer dispatch_group_async call anyway. Assuming it's there because you want these things to execute with background priority, you can do this instead:
dispatch_queue_t queue = dispatch_queue_create("com.company.queue", 0);
dispatch_set_target_queue(queue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0));
dispatch_group_t group = dispatch_group_create();
// block 1
dispatch_group_async(group, queue, ^{
[[WebRequests sharedInstance] request:#{#"type" : [NSNumber numberWithInt:request_uploadAdv], #"adv" : adv} withCompletion:^(id response) {
BOOL success = [response boolValue];
NSLog(#"done1 text");
// block 1 Done
}];
});
// block 2 //картинки
dispatch_group_async(group, queue, ^{
[self getImagesForAdv:adv completion:^(NSArray *images) {
[[WebRequests sharedInstance] uploadPhotos:images completion:^(BOOL success) {
uploadImagesSuccess = YES;
NSLog(#"done1 2\n");
// block 2 Done
}];
}];
});
dispatch_group_notify(group, queue, ^{
printf("all tasks are finished!\n");
});
This is my code for async fetching JSON
-(void)viewDidAppear:(BOOL)animated
{
[_indicator startAnimating];
_indicator.hidesWhenStopped = YES;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
//Load the json on another thread
[Constants shared].jsonData = [[NSData alloc] initWithContentsOfURL:
[NSURL URLWithString:#"http://api.fessor.da.kristoffer.office/homework/index/?rp[token]=app&rp[workspace]=parent&child_id=22066&type=parent&start_date=2014-05-01&end_date=2014-05-01"]];
//When json is loaded stop the indicator
[_indicator performSelectorOnMainThread:#selector(stopAnimating) withObject:nil waitUntilDone:YES];
[self declareVariables];
[_tableView reloadData];
});
}
And it's not working for some reason.
It shows the spinner, I can see that the data is fetched, it stops and hides the spinner, but the tableView is not reloaded, it's blank.
You want to move all the UI stuff to the main queue. So your code should read as:
-(void)viewDidAppear:(BOOL)animated
{
[_indicator startAnimating];
_indicator.hidesWhenStopped = YES;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
//Load the json on another thread
[Constants shared].jsonData = [[NSData alloc] initWithContentsOfURL:
[NSURL URLWithString:#"http://api.fessor.da.kristoffer.office/homework/index/?rp[token]=app&rp[workspace]=parent&child_id=22066&type=parent&start_date=2014-05-01&end_date=2014-05-01"]];
dispatch_async(dispatch_get_main_queue(), ^{
//When json is loaded stop the indicator
[_indicator stopAnimating];
[self declareVariables];
[_tableView reloadData];
});
});
}
This way your JSON is loaded on the background queue and the UI is updated on the main queue.
You should try to reload your table view on the main thread. Use GCD to dispatch on the main thread.
dispatch_async(dispatch_get_main_queue(), ^{
[_tableView reloadData];
});
If there's no result, try to log in the cellForRowAtIndexPath method to check whether the reload is done or not. If so, you error is elsewhere.
I am trying to show a spinner in a subview on a tableview controller on my main thread. The view is only showing on occasions and generally appears to be showing after my background thread has finished. Here is my code:
[self.view addSubview:spinnerView];
[self.view bringSubviewToFront:spinnerView];
self.spinnerView.layer.cornerRadius = 8;
self.spinnerView.center = CGPointMake(160, 150);
[spinner startAnimating];
dispatch_queue_t downloadQueue = dispatch_queue_create("downloader", NULL);
dispatch_async(downloadQueue, ^ {
dispatch_async(dispatch_get_main_queue(), ^{
[NSThread sleepForTimeInterval:10];
// Add recurring transactions if necessary
if (tran.recur.id != 0) {
[Utilities addRecurringTransactionsUpToCurrentMonthByTransaction:tran];
}
[spinner stopAnimating];
[self dismissViewControllerAnimated:YES completion:nil];
});
});
dispatch_release(downloadQueue);
}
}
Since all UI is running on main thread, you must call performSelectorOnMainThread:withObject:waitUntilDone: like below:
[self.view addSubview:spinnerView];
[self.view bringSubviewToFront:spinnerView];
self.spinnerView.layer.cornerRadius = 8;
self.spinnerView.center = CGPointMake(160, 150);
[spinner performSelectorOnMainThread:#selector(startAnimating) withObject:nil waitUntilDone:NO];
dispatch_queue_t downloadQueue = dispatch_queue_create("downloader", NULL);
dispatch_async(downloadQueue, ^ {
dispatch_async(dispatch_get_main_queue(), ^{
[NSThread sleepForTimeInterval:10];
// Add recurring transactions if necessary
if (tran.recur.id != 0) {
[Utilities addRecurringTransactionsUpToCurrentMonthByTransaction:tran];
}
[spinner performSelectorOnMainThread:#selector(stopAnimating) withObject:nil waitUntilDone:NO];
[self dismissViewControllerAnimated:YES completion:nil];
});
});
dispatch_release(downloadQueue);