How to wait for threading blocks to finish

回眸只為那壹抹淺笑 提交于 2019-12-23 05:27:40

问题


I am having issues with threading in my app. This is the first time I have used both AFNetworking and Parse. The problem is that I am calling both features and they both are required to finish before moving onto the next segue.

Here is my code. The first block is for the network request using AFHTTP and the second is the parse request.

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = @{@"foo": @"bar"};
[manager POST:@"http://example.com/resources.json" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"JSON: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
}];



PFQuery *query = [PFQuery queryWithClassName:@"dependant"];
[query whereKey:@"parentID" equalTo:[masterAccount getObjectID]];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {

for (PFObject *dependant in objects) {
   //do some stuff with parse object here           
    }
     [self performSegueWithIdentifier: @"MySegue" sender: self];
     }];

To my knowledge, both of these create and run off in their own threads so as to not block the gui, is this correct? Where would I move the segue call (currently at the end of the Parse block) so that it would not be called until both of these requests have fully completed?


回答1:


You can solve this problem using Grand Central Dispatch, more specifically "Dispatch Groups"

https://developer.apple.com/library/mac/documentation/performance/reference/gcd_libdispatch_ref/Reference/reference.html

Grouping blocks allows for aggregate synchronization. Your application can submit multiple blocks and track when they all complete, even though they might run on different queues. This behavior can be helpful when progress can’t be made until all of the specified tasks are complete.




回答2:


Here's what's happening:

// Runs 1st
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = @{@"foo": @"bar"};
[manager POST:@"http://example.com/resources.json" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {

    // Runs 3rd
    NSLog(@"JSON: %@", responseObject);

    // Run your code here, or trigger your code here
    PFQuery *query = [PFQuery queryWithClassName:@"dependant"];
    [query whereKey:@"parentID" equalTo:[masterAccount getObjectID]];
    [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
        for (PFObject *dependant in objects) {
            //do some stuff with parse object here           
        }
        [self performSegueWithIdentifier: @"MySegue" sender: self];
    }];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
}];

// Runs 2nd



回答3:


I think this is what you want...

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = @{@"foo": @"bar"};
__weak __typeof(self) weakSelf = self;
[manager POST:@"http://example.com/resources.json" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"JSON: %@", responseObject);
    PFQuery *query = [PFQuery queryWithClassName:@"dependant"];
    [query whereKey:@"parentID" equalTo:[masterAccount getObjectID]];
    [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
        __strong __typeof(self) strongSelf = weakSelf;
        for (PFObject *dependant in objects) {
           //do some stuff with parse object here           
        }
        [strongSelf performSegueWithIdentifier: @"MySegue" sender: self];
    }];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
}];

This code runs each asynchronous request sequentially, which is the simplest way to do it.




回答4:


A simple way to do this is to have a separate object, say ResourceState. Give it two properties, one for gotJsonData, one for gotParseData. In the completion handlers just call a method in ResourceState which updates the appropriate property (json or parse) and if both properties are set to success, triggers the segue. I would not try to do a block-inside-a-block approach -- it's less code but can make the code hard to maintain.

The underlying problem you have here is that you need a clean separation between 'model' and 'view controller'. The way I normally work is to have the model do all the work, including network requests, and when it knows a UI-side update is needed, it sends a NSNotification which the UI on the main thread listens to and then updates the UI.



来源:https://stackoverflow.com/questions/23111929/how-to-wait-for-threading-blocks-to-finish

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!