2

i'm quite a beginner at cocoa an objective-c - so please forgive me a possibly trivial question.

I'm currently working on an XCODE-Project which is fetching some data via NSJSONSerialization and store it for further work.

At this step I'm going to encapsulate the progress of fetching the data into an class which has some setter for the needed parameters (url to fetch from and the layer which should be parsed into an array). In order to use this procedure im creating the method inside this class which creates a connection and a request and returns the array which should contain the data. After some tests I tried to create an instance of this class and called the method which starts to fetch the data.

My problem is, that after calling the method data_array from my new instance "block_stats" and store the data in an array of the same type - the array is empty

table_data = [block_stats data_array];

The reason of this behavior is that the usage of the methods in (didReceiveResponse,didReceiveData,connectionDidFinishLoading) are working asynchron and the return of the data_array was done before the download was finished.


the method inside the class which contains the downloading part:

- (NSMutableArray *)data_array
{
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    if(data_array)
    {
        [data_array removeAllObjects];
    } else {
        data_array = [[NSMutableArray alloc] init];
    }

    NSURLRequest *request = [NSURLRequest requestWithURL:data_url];
    connection = [NSURLConnection connectionWithRequest:request delegate:self];
    if(connection)
    {
        webdata = [[NSMutableData alloc]init];
    }
    return data_array;    
}

the IBAction in another view which creates the instance and calls the method to fetch the data

- (IBAction)refresh:(UIBarButtonItem *)sender {
    KDJSONparser *block_stats = [[KDJSONparser alloc]init];
    [block_stats setURL:[NSURL URLWithString:@"*JSONDATA_URL*"]];
    [block_stats setLayer:@"blocks"];
    table_data = [block_stats data_array];
}

I would be very glad if anyone could give some advice. It would be very nice if it would be as easy as possible to understand for me. Thanks in advance!

KDon
  • 23
  • 1
  • 7

1 Answers1

2

The solution to your problem lies in delegation (As the word suggests you will be appointing some one else to take action when a situation presents itself.)

You have already used this in the following piece of your code.

NSURLRequest *request = [NSURLRequest requestWithURL:data_url];

connection = [NSURLConnection connectionWithRequest:request delegate:self];

Here when you have set self as the delegate for your NSURLConnection you are telling the compiler to send you any appropriate messages related to the connection. These messages include didReceiveResponse,didReceiveData,connectionDidFinishLoading.

So let's implement these methods in your class and they will look something like this.

KDJSONParser.m

- (NSMutableArray *)fetchData
{
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

    NSURLRequest *request = [NSURLRequest requestWithURL:data_url];
    connection = [NSURLConnection connectionWithRequest:request delegate:self];
    if(connection)
    {
        webdata = [[NSMutableData alloc]init];
    }    
}


- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    // This method is called when the server has determined that it
    // has enough information to create the NSURLResponse.

    // It can be called multiple times, for example in the case of a
    // redirect, so each time we reset the data.

    // receivedData is an instance variable declared elsewhere.
    [webdata setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    // Append the new data to receivedData.
    // receivedData is an instance variable declared elsewhere.
    [webdata appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    [connection release];

    //Parse the webdata here. Your array must be filled now.
    [self parseTheJSONData];
}

-(void)parseTheJSONData
{
  //Do your parsing here and fill it into data_array
  [self.delegate parsedArray:data_array];
}

And in your other class add this line in you refresh method

block_stats.delegate = self;

and implement

-(void)parsedArray:(NSMutableArray *)data_array;
Suhas
  • 1,500
  • 11
  • 15
  • thank you for that fast solution. I will check this as soon as possible. – KDon Mar 08 '13 at 15:10
  • there is a problem with the .delegate part. XCode is telling me that the following `-(void)parseTheJSONData { //Do your parsing here and fill it into data_array [self.delegate parsedArray:data_array]; }` and in the refresh method: `block_stats.delegate = self;` both of them don't now the property 'delegate' – KDon Mar 08 '13 at 19:04
  • could you give me further help ? Thanks in advance – KDon Mar 09 '13 at 09:29
  • Yes because it has to be declared in the header file. Add the line @property(nonatomic, assign) id delegate; in the KDJSONParser.h file and @synthesize delegate in the KDJSONParser.m file. You can fing more info on properties in the following doc. http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html – Suhas Mar 11 '13 at 01:51
  • thank you for your answer. It just ended in an exception: `-[ViewController parsedArray:]: unrecognized selector sent to instance 0x8a87bf0 2013-03-11 17:19:29.170 SlushStat[2608:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ViewController parsedArray:]: unrecognized selector sent to instance 0x8a87bf0' ` – KDon Mar 11 '13 at 16:25
  • I guess these are the basics of programming. You need to declare and implement the parsedArray method in the .h and .m files of the class which you are setting as the delegate. The proper way however would be to implement a protocol. – Suhas Mar 12 '13 at 02:14
  • okay, sorry for that. I implemented it in the wrong file. In the .m file of my class and not in the viewcontroller which was the target for this method. You're right - those problems are based on the basics of the programming.. i'm at the beginning of this language and I like to learn on some more difficult examples to 'have something done' ;) Thank you for your patience and your help! – KDon Mar 12 '13 at 21:49
  • You are welcome and hope you have fun learning this awesome language. Please accept my answer if I've helped solve your problem effectively. :) – Suhas Mar 13 '13 at 01:43