1

I have the following json file and I am trying to parse it from my iOS app. I defined a method to parse the file but I don't know how to handle the integers, which are the IDs. I want to put the data in an array (promotions) which contains a title and an array of products (explained better below). Any suggestion or good reference?

Json file:

 "promotions": {
    "1": {
        "title": "promotion title",
        "product": {
            "1": {
                "title": "product title",
                "description": "this is the description"
            },
            "2": {
                "title": "product title",
                "description": "this is the description"
            }
          }
      },
    "2": { "3": {
                "title": "product title",
                "description": "this is the description"
            },
            "4": {
                "title": "product title",
                "description": "this is the description"
            }
         }
      } 
   }

These are my data classes:

Promotion { NSString *title; NSArray *products;}
Product { NSString *title; NSString *description;}

And my function to load the json and add all the objects in an array of promotions which contains, for each promotion, an array of products.

- (NSArray *) infoFromJSON{
    NSURL *url=[NSURL URLWithString:urlJSON];

    NSURLRequest *request = [NSURLRequest requestWithURL:url
                                             cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
                                         timeoutInterval:30.0];
    NSURLResponse *response;
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];

    NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];

    NSMutableArray *promotions = [[NSMutableArray alloc] init];

    NSArray *array = [jsonDictionary objectForKey:@"promotions"];
    NSLog(@"array: %@", array);
    NSLog(@"items en array %d", [array count]);
    NSLog(@"object 1 en array: %@", [array objectAtIndex:1]);

    // Iterate through the array of dictionaries
    for(NSDictionary *dict in array) {
        Promotion *promotion= [[Promotion alloc] initWithJSONDictionary:dict];
        // Add the promotion object to the array
        [promotions  addObject:promotions];

        //Add the products to each promotion??
    }

    // Return the array of promotion objects
    return promotions;

}
4
  • First off (and this is NOT nit-picking) that is NOT a JSON file. You omitted the VERY CRITICAL leading { (and possibly the trailing } -- I haven't counted). Every character in a JSON file has meaning, and you must learn how to read them correctly. Commented Mar 12, 2014 at 18:01
  • As to the JSON itself, it is ugly, and was probably produced by someone who doesn't really understand JSON. Likely the simplest way to deal with it (if you can't get it corrected) is to copy the elements of each "object" (NSDictionary) into a corresponding array -- relatively straight-forward. Commented Mar 12, 2014 at 18:05
  • I forgot to copy the leading { and trailing } but the json file is correct, I validated with an online json validator. Commented Mar 12, 2014 at 18:05
  • What is "promotions"? I don't see that in the JSON. Commented Mar 12, 2014 at 18:07

3 Answers 3

6

Your JSON is not well defined, you must try to use something like:

[{"promotion_id": 1
  "title": "promotion title", 
  "products": [{"product_id": 1, 
                "title": "product title", 
                "description": "this is the description"
               },
               {"product_id": 2, 
                "title": "product title", 
                "description": "this is the description"
               },
               ...
              ]
 },
 {"promotion_id": 2
  "title": "promotion title", 
  "products": [{"product_id": 3, 
                "title": "product title", 
                "description": "this is the description"
               },
               {"product_id": 4, 
                "title": "product title", 
                "description": "this is the description"
               },
               ...
              ]
 },
 ...
]

Then, to parse the JSON dictionaries into custom objects I would recommend you to use the category NSObject+Motis I've been working recently. It is very useful to map JSON dictionaries into your custom Objective-C objects.

Mainly, you must do:

@interface Promotion : NSObject
@property (nonatomic, assing) NSInteger promotionId; 
@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) NSArray *products;
@end

@implementation Promotion
- (NSDictionary*)mjz_motisMapping
{
    return @{@"promotion_id" : @"promotionId",
             @"title" : @"title",
             @"products" : @"products",
            };
}

- (NSDictionary*)mjz_arrayClassTypeMappingForAutomaticValidation
{
    return @{"products": [Product class]};
}

@end

@interface Product : NSObject
@property (nonatomic, assing) NSInteger productId; 
@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) NSArray *productDescription;
@end

@implementation Promotion
- (NSDictionary*)mjz_motisMapping
{
    return @{@"product_id" : @"productId",
             @"title" : @"title",
             @"description" : @"productDescription",
            };
}
@end

and then perform the parsing by doing:

- (void)parseTest
{
    NSData *data = jsonData; // <-- YOUR JSON data 

    // Converting JSON data into array of dictionaries.
    NSError *error = nil;
    NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];

    if (error)
        return; // <--- If error abort.

    NSMutableArray *promotions = [NSMutableArray array];
    for (NSDictionary *dict in jsonArray)
    {
        Promotion *promotion = [[Promotion alloc] init];
        [promotion mjz_setValuesForKeysWithDictionary:dict];
        [promotions addObject:promotion];
    }
}

You can read how it works in this post: http://blog.mobilejazz.cat/ios-using-kvc-to-parse-json

Hoping it helps you as much it helped me.

Sign up to request clarification or add additional context in comments.

Comments

1

That's nasty JSON. If you can, get it changed. At the moment you have a number of dictionaries, where the keys in the dictionaries are numbers. These dictionaries should be arrays.

You have written your code as if they are arrays.

If you need to keep the JSON, read the dictionaries out and then iterate the key, or, if you can (because you aren't using the keys for sorting) just get all of the values as an array from the dictionary and iterate that.

Ideally, change the JSON and use RestKit...

4 Comments

when you say change the json, do you mean only removing the IDs? I can try to ask if they can change the json but the easiest & faster solution is try to parse it without making changes in the json.
Then use allValues on the promotions dictionary. The more I look at the JSON the worse it is, you should really have it changed...
No. He means talk to the people who designed the JSON output, tell them that some clueful people on stackoverflow are shaking their heads in disbelief about the JSON they produce, and ask them to please please please change it.
I can't get the JSON changed, could you give me an example of how to parse allValues and add each string in my arrays?
0

I finally ended up changing the json for:

{
    "promotions": [
        {
            "id": "1",
            "title": "promotion title",
            "products": [
                {
                    "id": "1",
                    "title": "product title",
                    "description": "description"
                },
                {
                    "id": "2",
                    "title": "product title",
                    "description": "description"
                }
            ]
        },
        {
            "id": "2",
            "title": "promotion title",
            "products": [
                {
                    "id": "6",
                    "title": "product title",
                    "description": "description"
                }
            ]
        }
    ]
}

And this is how I parse the json:

- (NSArray *) infoFromJSON{
    // Create a NSURLRequest with the given URL
    NSURL *url=[NSURL URLWithString:urlJSON];

    NSURLRequest *request = [NSURLRequest requestWithURL:url
                                             cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
                                         timeoutInterval:30.0];
    // Get the data
    NSURLResponse *response;
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];

    //Create an array to hold all the information
    NSMutableArray *info = [[NSMutableArray alloc] init];

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

    NSArray *arrayPromotions = [jsonDictionary objectForKey:@"promotions"];

    for(NSDictionary *dictCategories in arrayPromotions) {
        Block *promotion = [[Block alloc] initWithJSONDictionary:dictCategories];

        NSArray *arrayProducts = [dictCategories objectForKey:@"products"];

        promotion.questions = [[NSMutableArray alloc] init];
        for(NSDictionary *dictProducts in arrayProducts) {
            Product *product = [[Product alloc] initWithJSONDictionary:dictProducts];
            NSLog(@"product title %@", product.title);
            [promotions.product addObject:product];
        }

        [info addObject:promotion];
        NSLog(@"Promotion: %@ product 2: %@", promotion.title, [[promotion.products objectAtIndex:1] title]);
    }

    // Return the array of Location objects
    return info;

}

I defined and implemented the method initWithJSONDictionary in both data classes (Promotion and Product)

- (id)initWithJSONDictionary:(NSDictionary *)jsonDictionary {    
    if(self = [self init]) {
        self.title = [jsonDictionary objectForKey:@"title"];
    }
    return self;
}

Comments

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.