1

I have a function that pings ebay and returns JSON to the iOS app. What I want to do is populate my UITableView with the JSON being returned. I've set up the code to the best of my understanding of how this should work, however the table loads without any data. I think this may be because the table is loading before the JSON is returned, not sure how to fix that though.

MatchCenterViewController.h

#import <UIKit/UIKit.h>
#import <Parse/Parse.h>
#import "AsyncImageView.h"
#import "SearchViewController.h"

@interface MatchCenterViewController : UIViewController <UITableViewDataSource>

@property (nonatomic) IBOutlet NSString *itemSearch;
@property (nonatomic, strong) NSArray *imageURLs;

@property (strong, nonatomic) NSString *matchingCategoryCondition;
@property (strong, nonatomic) NSString *matchingCategoryLocation;
@property (strong, nonatomic) NSNumber *matchingCategoryMaxPrice;
@property (strong, nonatomic) NSNumber *matchingCategoryMinPrice;


@property (strong, nonatomic) NSArray *matchCenterArray;


@end

MatchCenterViewController.m:

#import "MatchCenterViewController.h"
#import <UIKit/UIKit.h>

@interface MatchCenterViewController () <UITableViewDataSource, UITableViewDelegate>
@property (weak, nonatomic) IBOutlet UITableView *matchCenter;
@end

@implementation MatchCenterViewController



- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{

    [super viewDidLoad];


    //perform search with criteria just submitted
    [PFCloud callFunctionInBackground:@"MatchCenterTest"
                       withParameters:@{
                                        @"test": @"Hi",
                                        }
                                block:^(NSDictionary *result, NSError *error) {




                                    if (!error) {
                                        self.matchCenterArray = [result objectForKey:@"Top 3"];

                                        NSLog(@"Test Result: '%@'", result);
                                    }
                                }];

    self.matchCenterArray = [[NSArray alloc] init];
}

- (void)viewDidAppear:(BOOL)animated
{


    [PFCloud callFunctionInBackground:@"MatchCenterTest"
                       withParameters:@{
                                        @"test": @"Hi",
                                        }
                                block:^(NSDictionary *result, NSError *error) {

                                    if (!error) {
                                        NSLog(@"Test Result: '%@'", result);
                                    }
                                }];



}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [self.matchCenterArray count];
}



- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{


    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    NSDictionary *matchCenterDictionary= [self.matchCenterArray objectAtIndex:indexPath.row];

    cell.textLabel.text = [matchCenterDictionary objectForKey:@"Title"];

    if([matchCenterDictionary objectForKey:@"Price"] != NULL)
    {
        cell.detailTextLabel.text = [NSString stringWithFormat:@"$%@",[matchCenterDictionary   objectForKey:@"Price"]];
    }

    return cell;


}


- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}




/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end

JSON being returned:

{
    "Top 3" =     (
                {
            "Item 1" =             (
                                {
                    Title = "Apple iPhone 5s (Latest Model) - 16GB - Silver (AT&T) Smartphone";
                },
                                {
                    Price = "400.0";
                },
                                {
                    "Image URL" = "http://thumbs2.ebaystatic.com/m/mewfVG0QbBiu1nZytMuAlZw/140.jpg";
                },
                                {
                    "Item URL" = "http://www.ebay.com/itm/Apple-iPhone-5s-Latest-Model-16GB-Silver-AT-T-Smartphone-/181431570117?pt=Cell_Phones";
                }
            );
        },
                {
            "Item 2" =             (
                                {
                    Title = "Apple iPhone 5c (Latest Model) - 16GB - Pink (Verizon) Smartphone";
                },
                                {
                    Price = "350.0";
                },
                                {
                    "Image URL" = "http://thumbs4.ebaystatic.com/m/mMPAT67KjfCZF9oorbTf3uw/140.jpg";
                },
                                {
                    "Item URL" = "http://www.ebay.com/itm/Apple-iPhone-5c-Latest-Model-16GB-Pink-Verizon-Smartphone-/191204844039?pt=Cell_Phones";
                }
            );
        },
                {
            "Item 3" =             (
                                {
                    Title = "Apple iPhone 5 \U2013 16GB, White, works with Virgin Mobile US \U2013 NEW";
                },
                                {
                    Price = "359.99";
                },
                                {
                    "Image URL" = "http://thumbs3.ebaystatic.com/m/m5x1uj1iSS2fr691tifrvrw/140.jpg";
                },
                                {
                    "Item URL" = "http://www.ebay.com/itm/Apple-iPhone-5-16GB-White-works-Virgin-Mobile-US-NEW-/141227441998?pt=Cell_Phones";
                }
            );
        }
    );
}

enter image description here enter image description here

2 Answers 2

2

Reload your table on the main thread after your data is loaded.

In your completion block:

[PFCloud callFunctionInBackground:@"MatchCenterTest"
                   withParameters:@{
                                    @"test": @"Hi",
                                    }
                            block:^(NSDictionary *result, NSError *error) {

                                if (!error) {
                                    dispatch_async(dispatch_get_main_queue(), ^{
                                        self.matchCenterArray = [result objectForKey:@"Top 3"];
                                        [matchCenter reloadData];
                                    });
                                    NSLog(@"Test Result: '%@'", result);
                                }
                            }];

Edit1: Also, I would recommend adapting to your protocols in one place. Right now you're using UITableViewDataSource in your header file, and then both UITableViewDataSource and UITableViewDelegate in your implementation file. Stick to one location for best practices.


Edit2: Relocated line to set the matchCenterArray contents onto the main thread dispatch per @Rob's suggestion in the comments


Edit3: Based on comments, you have the ability to change your JSON. Your current structure listed above is quite cumbersome, so I would suggest something more concise (and more easily parse-able) like this:

    {
    "Top 3" : [
        {
            "Title" : "Apple iPhone 5s (Latest Model) - 16GB - Silver (AT&T) Smartphone",
            "Price" : "400.0",
            "Image URL" : "http://thumbs2.ebaystatic.com/m/mewfVG0QbBiu1nZytMuAlZw/140.jpg",
            "Item URL" : "http://www.ebay.com/itm/Apple-iPhone-5s-Latest-Model-16GB-Silver-AT-T-Smartphone-/181431570117?pt:Cell_Phones"
        },
        {
            "Title" : "Apple iPhone 5c (Latest Model) - 16GB - Pink (Verizon) Smartphone",
            "Price" : "350.0",
            "Image URL" : "http://thumbs4.ebaystatic.com/m/mMPAT67KjfCZF9oorbTf3uw/140.jpg",
            "Item URL" : "http://www.ebay.com/itm/Apple-iPhone-5c-Latest-Model-16GB-Pink-Verizon-Smartphone-/191204844039?pt:Cell_Phones"
        },
        {
            "Title" : "Apple iPhone 5 16GB, White, works with Virgin Mobile US NEW",
            "Price" : "359.99",
            "Image URL" : "http://thumbs3.ebaystatic.com/m/m5x1uj1iSS2fr691tifrvrw/140.jpg",
            "Item URL" : "http://www.ebay.com/itm/Apple-iPhone-5-16GB-White-works-Virgin-Mobile-US-NEW-/141227441998?pt:Cell_Phones"
        }
    ]
}

Now you can access your values like so:

// In your completion block:
self.matchCenterArray = [result objectForKey:@"Top 3"];

...
[[self.matchCenterArray objectAtIndex:0] objectForKey:@"Title"] // title of the first object
[[self.matchCenterArray objectAtIndex:2] objectForKey:@"Image URL"] // image URL of the last item
Sign up to request clarification or add additional context in comments.

10 Comments

This gives me an error stating that Property tableview not found on object of type MatchCenterViewController. Is this a property I'm supposed to add to the header? If so, how is it formatted?
Ah- your tableView is set up under a different variable name. Check the edited code.
+1 BTW, you probably want to put the self.matchCenterArray assignment in the dispatch block to the main queue, otherwise you could end up in race conditions in which the background changed matchCenterArray while the main queue was busy using that array to respond to UI events, like scroll events. You generally want to synchronize updates of model objects used by the main thread, and simply dispatching those updates to the main queue is the easiest way to do that.
Hmm. The solution makes sense, but it still doesn't seem to be populating. Correct me if I'm wrong, but I think it's because I have a view controller that contains a table within it, and the table isn't subclassed properly. I've added two screenshots to my question to clarify.
@Ghobs You're looking for the Title value at [[[result objectForKey:@"Top 3"] objectAtIndex:0] objectForKey:@"Title"]; When it's really at [[[[[result objectForKey:@"Top 3"] objectAtIndex:0] objectForKey:@"Item 1"] objectAtIndex:0] objectForKey:@"Title"]; which will be different for "Item 2" (the second cell in your table) and "Item 3" because it has a different key for those dictionaries. Are you saying that you have the ability to change the structure of your JSON? Because if so, I could make a suggestion on how to format it differently.
|
0

Just reload your table view in the block when you receive data from the cloud.

- (void)viewDidLoad
{

[super viewDidLoad];

self.matchCenterArray = [[NSArray alloc] init];
//perform search with criteria just submitted
[PFCloud callFunctionInBackground:@"MatchCenterTest"
                   withParameters:@{
                                    @"test": @"Hi",
                                    }
                            block:^(NSDictionary *result, NSError *error) {




                                if (!error) {
                                    self.matchCenterArray = [result objectForKey:@"Top 3"];
[yourTableView reloadData];
                                    NSLog(@"Test Result: '%@'", result);
                                }
                            }];


}

Also include UITableViewDelagete in your .h file. And init your array before the block.

2 Comments

That matters for the web service call but as the table is reloading so it does not required. I think.
Completion blocks execute on background threads. Updating the table is a UI operation, so it needs to be done on the main thread.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.