Search code examples
objective-cjsonobjective-c-blocksgrand-central-dispatchnsurlconnectiondelegate

Objective-C - block loop from continuing until delegate method is called


In each loop, I initialize a connector class with an id that is used to perform a JSON call. The problem is, is that this loop continues to iterate before the connectionDidFinishLoading delegate method of the connector class completes, parses the JSON as needed then uses a delegate method with information that it retrieved.

for(NSDictionary *item in views){

   NSInteger myID = [[item valueForKey:@"id"] integerValue];

 //filter contains these two dictionaries
   NSDictionary *ownerDictionary = [filterDictionary valueForKey:@"owner"];
   NSString *ownerDisplayName = [ownerDictionary valueForKey:@"displayName"];

   self.projectName = projectName;
   self.ownerName = ownerDisplayName;


   //value inside dictionary for owner
   NSString *ownerDisplayName = [ownerDictionary valueForKey:@"displayName"];

   //I initialize the connector class here
   self.sprintConnector = [[SprintConnector alloc] initWithId:myID];
   [self.sprintConnector setDelegate:self];



//**I do not want to continue this loop until the delegate method that i implement is called**/
}

//implementation of delegate method 
-(void)didFinishLoadingStuff:(MyObject *)obj{

    Project *newProject = [[Project alloc] init];
    newProject.projectName = self.projectName;
    newProject.projectOwner = self.ownerName;
    newProject.sprint = sprint;
   //Ok now i have the information that i need, lets continue our loop above
}

//The method of connector class to set up the request is here:

-(void)retrieveSprintInfoWithId{

    NSURLConnection *conn;
    NSString *urlString = @"myJSONURL";
    NSURL *url = [NSURL URLWithString:[urlString stringByAppendingString:self.ID]];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//    conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
    conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
}

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
    NSLog(@"data coming from request: %@", data );
    [self.data appendData:data];

}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection{

    NSLog(@"we finished loading");
    NSError *error = nil;

    self.projectsDict = [[NSDictionary alloc] initWithDictionary:[NSJSONSerialization JSONObjectWithData:self.data options:NSJSONReadingMutableContainers error:&error]];

    NSLog(@"Our sprint array with id: %@ %@", self.ID, self.projectsDict);

//this is where we parse the JSON then use the delegate method that the above class will implement
    [self parseJSON];

}



-(void)parseJSON{

[self.delegate didFinishLoadingStuff:SomeObject];
}

I want to be able to force the connectionDidFinishLoading method to be called ->parseJSON->delegate method and for the implementation of that method as mentioned above to complete before the loop continues.

What are my options? Best practices? etc?


Solution

  • What you want to do is synchronously make the requests, I will show you how to do that, but you should not be doing that, so after I show you how to make a synchronous request I will show you how you should handle this

    1- To issue requests synchronously you can use the sendSynchronousRequest method of NSURLConnection, this will block until data is received and return the data, here is are the docs. You should not do this as you may block the main thread which would cause a bad user experience (also other reasons why this is bad practice)

    2- You should be issuing your requests async as you do in your sample code, in your callback you should fetch the appropriate object (which you should know by the item id), and then do whatever it is you need to do to that object... If you need everything to be loaded in order for some action to take place, then you should keep track of that (sent requests vs responses received)

    Hope that helps

    Daniel