Take the 2-minute tour ×

I'm in the process of trying to move code from a UITableViewController class to a "helper" class.

The code utilizes NSURLConnection to grab and parse JSON and then populate an NSMutableArray.

What I'd like to do is call a method in my helper class that returns a NSMutableArray. What I don't understand is how to return the array from the connectionDidFinishLoading delegate class of NSURLConnection (where the array is actually built) as though it was from the originally called method that started the connection. In other words, how does the method that calls NSURLConnection get control back so it can return a value from the whole operation?

Here are the relevant methods from the helper class. How do I get the getMovies method to return the listOfMovies that is built in the connectionDidFinishLoading delegate class?

-(NSMutableArray)getMovies:(NSURL*)url {

responseData = [[NSMutableData data] retain];       

NSURLRequest *request = [NSURLRequest requestWithURL:url];
//NSURLRequest* request = [NSURLRequest requestWithURL: url cachePolicy: NSURLRequestUseProtocolCachePolicy timeoutInterval: 30.0];

connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];



[responseData setLength:0];

[responseData appendData:data];

//TODO error handling for connection

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

//---initialize the array--- 

listOfMovies = [[NSMutableArray alloc] init];

tmdbMovies = [[NSArray alloc] init];
posters = [[NSArray alloc] init];
thumbs = [[NSDictionary alloc] init];

NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];

SBJsonParser *json = [[SBJsonParser new] autorelease];

tmdbMovies = [json objectWithString:responseString];

// loop through all the top level elements in JSON
for (id movie in tmdbMovies) {

    // 0 - Name
    // 1 - Meta
    // 2 - Url

    if ((NSNull *)[movie objectForKey:@"name"] != [NSNull null]) {

        if (![[movie objectForKey:@"name"] isEqualToString:@""]) {
            name = [movie objectForKey:@"name"];


    if ((NSNull *)[movie objectForKey:@"info"] != [NSNull null]) {

        if (![[movie objectForKey:@"info"] isEqualToString:@""]) {
            meta = [movie objectForKey:@"info"];


    if ((NSNull *)[movie objectForKey:@"thumb"] != [NSNull null]) {

        if (![[movie objectForKey:@"thumb"] isEqualToString:@""]) {
            thumbUrl = [movie objectForKey:@"thumb"];


    NSLog(@"Name: %@", name);
    NSLog(@"Info: %@", meta);
    NSLog(@"Thumb: %@", thumbUrl);

    NSMutableArray *movieData = [[NSMutableArray alloc] initWithObjects:name,meta,thumbUrl,nil];

    // add movieData array to listOfJMovies array
    [listOfMovies addObject:movieData];

    [movieData release];

//FIXME: Connection warning
if (connection!=nil) { 
    [connection release]; 

[responseData release]; 
[responseString release];

share|improve this question
Either use protocol or NSNotificationcenter –  Vjy Jan 5 '11 at 19:45
add comment

4 Answers

up vote 10 down vote accepted

What you really need to do here is create a @protocol that creates a delegate for your helper class. Then change -(NSMutableArray)getMovies:(NSURL*)url to -(void)getMovies:(NSURL*)url

The class that is calling your helper method needs to implement your helper method's delegate.

Then - (void)connectionDidFinishLoading:(NSURLConnection *)connection calls the delegate method(s). It's best to have a one for success and one for failure.

=Update Begin=

You will need to also define an id delegate in your helper file which the calling class sets to self after init but before calling -(void)getMovies:(NSURL*)url. That way the helper file knows where to call back to.

getMovies *movieListCall = [[getMovies alloc] init];
movieListCall.delegate = self;
[movieListCall getMovies:<your NSURL goes here>];

You will see some additional lines for the inclusion of a delegate in both the getMovies.h and getMovies.m files.

=Update End=

in your getMovies.h file add:

@protocol getMoviesDelegate

- (void)getMoviesSucceeded:(NSMutableArray *)movieArray;
- (void)getMoviesFailed:(NSString *)failedMessage;


@interface getMovies : NSOBject {
id delegate;

@property (nonatomic, assign) id delegate;

in your getMovies.m file add:

@synthesize delegate;

    //TODO error handling for connection
    if ([delegate respondsToSelector:@selector(getMoviesFailed:)]) {
        [delegate getMoviesFailed:[error localizedDescription]];

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

//finishes with
    if ([delegate respondsToSelector:@selector(getMoviesSucceeded:)]) {
        [delegate getMoviesSucceeded:listOfMovies];

update your calling class .h file to use getMoviesDelegate:

@interface MoviesView : UIViewController <getMoviesDelegate>{

add the getMoviesDelegate methods to your calling class .m file

- (void)getMoviesSucceeded:(NSMutableArray *)movieArray {
//deal with movieArray here

- (void)getMoviesFailed:(NSString *)failedMessage {
//deal with failure here

This is not tested but hopefully gives you a road map to work with.

Protocols are nice because you can make both required and optional delegate methods and it helps in refining your helper methods to become very reusable across projects. The compiler will also warn you if you have implemented a protocol but not implemented the protocol's required delegate methods. If you follow this path be sure to use conformsToProtocol: and respondsToSelector:

share|improve this answer
This looks like a great approach. Will give it a shot and report back. Thanks all for your input. –  user558096 Jan 5 '11 at 20:46
I'm getting a delegate undeclared error when calling [delegate getMoviesSucceeded:listOfMovies]; Btw, is there a way to post code in the comments? Would like to post my Movies.h file to see if I've incorrectly declared the methods. –  user558096 Jan 6 '11 at 1:14
Actually the error is happening at the if condition and is the following: 'delegate' undeclared (first use in this function) –  user558096 Jan 6 '11 at 1:35
Sry, I assumed the helper had a delegat defined which is my fault. getMovies will need an id delegate defined in the .h file. I will update my answer. –  dredful Jan 6 '11 at 1:39
Thanks. Compiles now, but i'm crashing at runtime at this line: movieListCall.delegate = self; The error is [Movies setDelegate:]: unrecognized selector sent to instance. Btw, "Movies" is the class name and getMovies is the method name. Any ideas? –  user558096 Jan 6 '11 at 2:15
show 3 more comments

Fundamentally, what's happening is that you're starting an asynchronous network load (asynchronous is the right way to do this, almost assuredly), and then you need some way to resume whatever operation you were doing before the load began. You have a few options:

  • Create your own delegate protocol. Your UITableViewController would then set itself as the helper's delegate, and the helper would call helperDidLoad or whatever you named that method. There's more information on writing delegates in the Cocoa Programming Guide.

  • Use blocks and continuation passing style. This is a bit more advanced but I like it. In your UITableViewController you'd write something like this:

     [helper doSomething:^ (id loaded) { 
         [modelObject refresh:loaded]; // or whatever you need to do

    And then in your helper you'd write:

     - (void)doSomething:(void ^ (id))continuation {
         _continuation = continuation;
         //kick off network load
     - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
  • Use notifications. Read the NSNotificationCenter docs.
  • Use KVO. The KVO programming guide has a lot of good info on Key-Value Observing.
share|improve this answer
hi, I know this is a very old post but, in a case where there are more than one connection started at almost the same time, how do we determine which result comes from which connection? Thank you. –  tyegah123 2 days ago
add comment

How to i get the getMovies method to return the listOfMovies that is built in the connectionDidFinishLoading delegate class?

I'm going to argue that you should not do that.

Network requests should be made asynchronously. If your getMovies were to make a synchronous request and return only when it had data you would block that entire thread while you waiting for a network connection to finish. This is a bad idea in general and a terrible idea if your main thread is calling getMovies. Blocking the main thread will prevent you from responding to touches or updating the UI, your app will appear frozen, and the OS will terminate it if your users don't quit in frustration first.

Instead have the helper class notify the caller when data is available (or when it failed to retrieve data) through a delegate call back, notification, KVO, or whatever mechanism you prefer.

share|improve this answer
add comment

Here are the steps, pseudocode like style:

  1. [helperInstance setDelegate:self]; // where self is your UITableViewController class

  2. in your helper class, in the connectionDidFinishLoading do something like this:

    [delegate finishedLoadingData:JSONData];

Also you can define a protocol for your delegate, and the declare the delegate like this in your helper class:

@property (nonatomic, assign) id<YourProtocol> delegate;

Hope this helps, Moszi

share|improve this answer
add comment

Your Answer


