1

I have this method

- (NSString*) createUserWithName:(NSString*)TheName
{
    NSURL *URL =someUrlthatIncludesTheName
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
    [request setHTTPMethod:@"GET"];
    NSURLSession *session = [NSURLSession sharedSession];
    NSURL *URL = [NSURL URLWithString:url];
    NSURLSessionTask *task = [session dataTaskWithURL:URL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (response) {
            NSError* error = nil;
            NSArray *output = [NSJSONSerialization JSONObjectWithData:data
                                                              options:NSJSONReadingMutableContainers
                                                                error:&error];
            myID = [[output objectAtIndex:0] objectForKey:@"UserID"];
        }
    }];
    [task resume];
    return myID;
}

and another method

-(void)doSomethingWith: (NSString*) anID

Somewhere in my code, I call these methods subsequently, like this:

[self createUserWithName:@"John"];
[self doSomethingWith:myID];

However, due to the fact that the NSURLSession in createUserWithName: is asynchronous, doSomethingWith: is fired with myID = (null).

What is the best way to approach this problem, without necessarily falling back to deprecated synchronous NSURLConnection?

Thanks in advance

kye
  • 2,166
  • 3
  • 27
  • 41
Sjakelien
  • 2,255
  • 3
  • 25
  • 43
  • This happens because `createUserWithName` has not finished while the method `[self doSomethingWith:myID]` is executed. You can call `[self doSomethingWith:myID];` into `createUserWithName` method or use CompletionBlock – vroldan Apr 02 '16 at 14:20

1 Answers1

4

The workflow is supposed to be

- (void)createUserWithName:(NSString*)TheName
{
    NSURL *URL =someUrlthatIncludesTheName
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
    [request setHTTPMethod:@"GET"];
    NSURLSession *session = [NSURLSession sharedSession];
    NSURL *URL = [NSURL URLWithString:url];
    NSURLSessionTask *task = [session dataTaskWithURL:URL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (response) {
            NSError* error = nil;
            NSArray *output = [NSJSONSerialization JSONObjectWithData:data
                                                              options:NSJSONReadingMutableContainers
                                                                error:&error];
            myID = [[output objectAtIndex:0] objectForKey:@"UserID"];
            [self doSomethingWith:myID];
        }
    }];
    [task resume];
}

And the call is just

[self createUserWithName:@"John"];

The method doSomethingWith: is asynchronously executed in the completion block.

Alternatively use a custom completion block

- (void)createUserWithName:(NSString *)theName completion:^(NSString *identifier)completion
{
    NSURL *URL =someUrlthatIncludesTheName
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
    [request setHTTPMethod:@"GET"];
    NSURLSession *session = [NSURLSession sharedSession];
    NSURL *URL = [NSURL URLWithString:url];
    NSURLSessionTask *task = [session dataTaskWithURL:URL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (response) {
            NSError* error = nil;
            NSArray *output = [NSJSONSerialization JSONObjectWithData:data
                                                            options:NSJSONReadingMutableContainers
                                                             error:&error];
            myID = [[output objectAtIndex:0] objectForKey:@"UserID"];
            completion(myID);
        }
    }];
    [task resume];
}

and call it with

[self createUserWithName:@"John" completion:^(NSString *identifier) {
    [self doSomethingWith:identifier];
}];
vadian
  • 274,689
  • 30
  • 353
  • 361
  • I guess that does the trick. For the sake of this question, I have simplified my code. In fact, "doSomethingWith:" takes a bunch of other arguments. So, I should pass all these arguments to "createUserWithName" as well, which makes the code kind of unreadable. – Sjakelien Apr 02 '16 at 14:16
  • 1
    The alternative is an additional completion block in your `createUserWithName:` method. Then you can capture the other parameters in the block. – vadian Apr 02 '16 at 14:18