Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I have a Data class that inherits from NSObject.
In this class I handle my data requests.
After this I want to send the data that it holds in an NSMutableArray to my UITableViewController.

How can I fix this?

@interface Data : NSObject

@property(nonatomic,strong) NSMutableArray *data;

-(NSMutableArray *) loadData;

-(id)init;

@end


@implementation Data

@synthesize data;

-(id)init {

    self = [super init];

    if(self){
        self.data = [[NSMutableArray alloc]init];
    }

    return self;

}

- (NSMutableArray *)loadData {


    NSString *url = @"http://localhost/xampp/flashbackapi/";

    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    [manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {


        [data addObject:responseObject];


    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"Error %@",error);
    }];

    return data;

}

@end


#import <UIKit/UIKit.h>
#import "Club.h"
#import "Data.h"

@interface ClubsTableViewController : UITableViewController

@property(nonatomic,strong) Data *holderData;
@property(nonatomic,strong) NSMutableArray *teams;



@end

#import "AFNetworking.h"

@implementation ClubsTableViewController


    - (void)viewDidLoad
    {
        [super viewDidLoad];

        self.holderData = [[Data alloc]init];
        self.teams = [[NSMutableArray alloc]init];

        self.teams = self.holderData.loadData;

        NSLog(@"%@",self.teams); //this array is empty.. why? 



    }
share|improve this question
add comment

2 Answers 2

up vote 0 down vote accepted

Your loadData method is returning a data property that will never contain the contents of your responseObject. This is because your loadData method contains an asynchronous call (to manager GET:parameters:success:). When the asynchronous call returns, the data property/ivar is being populated, which, in your case is far too late. One solution would be to make loadData an asynchronous method too.

So, something like:

- (void)loadDataWithCompletionBlock:(void (^)(NSMutableArray *data))completionBlock {

    NSString *url = @"http://localhost/xampp/flashbackapi/";

    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    [manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {


        [data addObject:responseObject];
        completionBlock(data);


    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"Error %@",error);
        // TODO: Return completionBlock with empty array (or error?)
    }];
};

Invoked like this:

ClubsTableViewController __weak *weakSelf = self; 
[self loadDataWithCompletionBlock:^(NSMutableArray *data) {
    weakSelf.teams = data;
}];

Also, you don't seem to be using the NSMutableArray as an array as it seems that it will always only contain one element.

share|improve this answer
    
thank u soo much, im a beginner (as you can see hahah) so things are a little bit weird to for me. –  Navid Jun 15 at 21:34
    
No problem. Just added weakSelf to ensure no retain cycle occurs. –  gavdotnet Jun 16 at 4:48
    
i call the [self loadDataWithCompletionBlock] method in the ViewDidLoad of the TableViewController, so i guess i don't need to hold the ClubsTableViewController refrence. Actually i had a onother question, is this the correct way of doing it? because i always learned to hold the data sepparate of the controller and the view. But when i implement the loadDataWithCompletionBlock in the ClubsTableViewController i wouldn't need the callback, but is that the correct way of doing it? –  Navid Jun 16 at 7:17
    
Just a side note: Always check if a block is set before calling it: if (completionBlock) { completionBlock(data); } –  Cornelius Jun 16 at 9:31
    
@Navid The answer to these sort of questions is always "it depends". But if all you want to do is retrieve some simple data from the cloud, store it in an array/dictionary and display it to the user, then I wouldn't bother with a separate class (ie. model layer). For more complex data management (such as retrieving, storing and displaying nested JSON), you might want to create some classes to help manage your data. –  gavdotnet Jun 16 at 19:58
show 2 more comments

The AFNetworking GET method fetches the data asynchronously. In your loadData method you only start the network call, the response is set to the array property when the network request is done. Your loadData method returns before that happens, so the array is still empty.

You should pass a block to the loadData method as a parameter and call this block once AFNetworking finished the network request.

share|improve this answer
    
i knew the async was the main issue of this problem, but what i dont get is after the success callback i add the response object to my array An returning this array soo in which part of the source am i late? i don't want a simple source solution but if someone can give me a hint i would be thankfull. –  Navid Jun 15 at 21:29
    
@gavdotnet was faster ;) –  Cornelius Jun 16 at 9:28
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.