Jason
Jason

Reputation: 15

How to display JSON data seperated correctly in UITableview cells?

I've been able to get data from a local JSON file to display in a tableview

but it's displaying like this:

.......................cell1...............................

Biscuits

3 cups All-purpose Flour

2 Tablespoons Baking Powder

1/2 teaspoon Salt

.......................cell2...............................

12 whole Dinner Rolls Or Small Sandwich Buns (I Used Whole Wheat)

1 pound Thinly Shaved Roast Beef Or Ham (or Both!)

......................................................

And I need it to display each ingredient separated into its own cell like this:

.......................cell1...............................

Biscuits

.......................cell2...............................

3 cups All-purpose Flour

.......................cell3...............................

2 Tablespoons Baking Powder

.......................cell4...............................

1/2 teaspoon Salt

.......................cell5...............................

12 whole Dinner Rolls Or Small Sandwich Buns (I Used Whole Wheat)

.......................cell6...............................

1 pound Thinly Shaved Roast Beef Or Ham (or Both!)

...........................................................

What code would I need to display the data correctly? Heres my current code:

   /////////locations.json/////////////////////////////
    {
      "locations": [

    { "ingredients" : "Biscuits\n3 cups All-purpose Flour\n2 Tablespoons Baking Powder\n1/2 teaspoon Salt\nShortened for example” },

    { "ingredients" : "12 whole Dinner Rolls Or Small Sandwich Buns (I Used Whole Wheat)\n1 pound Thinly Shaved Roast Beef Or Ham (or Both!)\nShortened for example” },  
    //many more records.  only included 2 for example                            
      ]
    }
    /////////Location.h/////////////////////////////////////////
    #import <Foundation/Foundation.h>

    @interface Location : NSObject

    - (id)initWithJSONDictionary:(NSDictionary *)jsonDictionary;

    @property (readonly) NSString *ingredients;

    @end


    ////////Location.m////////////////////////////////////
    #import "Location.h"

    @implementation Location

    // Init the object with information from a dictionary
    - (id)initWithJSONDictionary:(NSDictionary *)jsonDictionary {
    if(self = [self init]) {
        // Assign all properties with keyed values from the dictionary

        _ingredients = [jsonDictionary objectForKey:@"ingredients"];
    }
    return self;
    }
    @end


    ////////JSONLoader.h////////////////////////////////////
    #import <Foundation/Foundation.h>

    @interface JSONLoader : NSObject

    // Return an array of Location objects from the json file at location given by url
    - (NSArray *)locationsFromJSONFile:(NSURL *)url;
    @end


    ////////JSONLoader.m////////////////////////////////////
    #import "JSONLoader.h"
    #import "Location.h"

    @implementation JSONLoader

    - (NSArray *)locationsFromJSONFile:(NSURL *)url {
    // Create a NSURLRequest with the given URL
    NSURLRequest *request = [NSURLRequest requestWithURL:url
                                             cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
                                         timeoutInterval:30.0];

    // Get the data
    NSURLResponse *response;
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response  error:nil];

    // Now create a NSDictionary from the JSON data
    NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];

    // Create a new array to hold the locations
    NSMutableArray *locations = [[NSMutableArray alloc] init];

    // Get an array of dictionaries with the key "locations"
    NSArray *array = [jsonDictionary objectForKey:@"locations"];
    // Iterate through the array of dictionaries
    for(NSDictionary *dict in array) {
        // Create a new Location object for each one and initialize it with information in the dictionary
        Location *location = [[Location alloc] initWithJSONDictionary:dict];
        // Add the Location object to the array
        [locations addObject:location];
    }

    // Return the array of Location objects
    return locations;
}
@end

////////TableViewController.h////////////////////////////////////
#import <UIKit/UIKit.h>
#import "Location.h"

@interface FilterViewController : UITableViewController

@property (weak, nonatomic) Location *location;

@end


////////TableViewController.m////////////////////////////////////
#import "FilterViewController.h"
#import "LocationsViewController.h"
#import "Location.h"
#import "JSONLoader.h"

@implementation FilterViewController {
    NSArray *_locations;   
}
- (void)viewDidLoad {
    [super viewDidLoad];

    // Create a new JSONLoader with a local file URL
    JSONLoader *jsonLoader = [[JSONLoader alloc] init];
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"locations" withExtension:@"json"];

    // Load the data on a background queue...
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        _locations = [jsonLoader locationsFromJSONFile:url];
        // Now that we have the data, reload the table data on the main UI thread
        [self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];

        });
}
// Just before showing the LocationDetailViewController, set the selected Location object
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    LocationsViewController *vc = segue.destinationViewController;
    NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
    vc.location = [_locations objectAtIndex:indexPath.row];
}

#pragma mark - Table View Controller Methods

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"FilterCell"];

    Location *location = [_locations objectAtIndex:indexPath.row];
    cell.textLabel.text = location.ingredients;
    cell.imageView.image = [UIImage imageNamed:@"ingredientsicon3232.png"];
    return cell;   
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [_locations count];
}
@end

Note: I'm unable to change the JSON data format as it's from an outside source and there's a lot more "ingredients" keys than I posted in the example.

Upvotes: 0

Views: 117

Answers (2)

JingJingTao
JingJingTao

Reputation: 1790

Edit:

Some sample code for you to get a working.

// JSONLoader.m 

- (NSArray *)locationsFromJSONFile:(NSURL *)url {
    // Existing code .......

    // Get an array of dictionaries with the key "locations"
    NSArray *array = [jsonDictionary objectForKey:@"locations"];
    // Iterate through the array of dictionaries
    for(NSDictionary *dict in array) {
        NSString *string = [dict objectForKey:@"ingredients"];
        NSArray *brokenIntoParts = [string componentsSeparatedByString:@"\n"];
        for (NSString *ingredient in brokenIntoParts) {
            [locations addObject:ingredient];
        }
    }

    // Return the array of Location objects
    return locations;
}

// FilterViewController.m

#pragma mark - Table View Controller Methods

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"FilterCell"];

    cell.textLabel.text = [_locations objectAtIndex:indexPath.row];
    cell.imageView.image = [UIImage imageNamed:@"ingredientsicon3232.png"];
    return cell;   
}

Original:

Your code looks fine, actually just change your data,

{
  "locations": [ { "ingredients" : "Biscuits"}, 
                 { "ingredients" : "3 cups All-purpose Flour"},
                 { "ingredients" : "Tablespoons Baking Powder"}
.
.
.                                                               
]}

This should solve your problem, basically you want key:value of "keyword":ingredient, please comment if it does not, good luck.

Upvotes: 1

vadian
vadian

Reputation: 285069

This code extracts the ingredients from the dictionary using the key-value coding method valueForKey and converts the newline separated strings to an array.

NSDictionary *jsonDictionary =  @{@"locations" : @[@{ @"ingredients" : @"Biscuits\n3 cups All-purpose Flour\n2 Tablespoons Baking Powder\n1/2 teaspoon Salt\nShortened for example" },
                                                   @{ @"ingredients" : @"12 whole Dinner Rolls Or Small Sandwich Buns (I Used Whole Wheat)\n1 pound Thinly Shaved Roast Beef Or Ham (or Both!)\nShortened for example" }]};


NSArray* locations = jsonDictionary[@"locations"];
NSMutableArray *ingredients = [NSMutableArray array];
NSArray *jsonIngredients = [locations valueForKey:@"ingredients"];
for (NSString *ingredient in jsonIngredients) {
    [ingredients addObjectsFromArray:[ingredient componentsSeparatedByString:@"\n"]];
}
NSLog(@"%@", ingredients);

The result ingredients can be used directly as the data source array.

Edit:

Your model class Location is actually incompatible with the JSON data format

To try the code you have to assign the result ingredients to your data source array _locations

_locations = ingredients;

Then in cellForRowAtIndexPath replace the lines

Location *location = [_locations objectAtIndex:indexPath.row];
cell.textLabel.text = location.ingredients;

with

NSString *ingredient = _locations[indexPath.row];
cell.textLabel.text = ingredient;

PS: If you are also responsible for the JSON on the server side consider to use a more convenient data format.

Upvotes: 0

Related Questions