Better JSON parsing implementation in Objective

I am receiving below JSON response for saving user preferences in core data.

preferences={
      1={
        children=({
          3=Samsung;4=Nokia;
        });id=1;name=Mobiles;
      };2={
        children=({
          5="Samsung Curve TV";
        });id=2;name=Electronics;
      };
    };

Here is my code snippet which is working fine. But I think this is much verbose code.

    NSLog(@"Preferences: %@", [response objectForKey:@"preferences"]);

    for (NSDictionary *dic in [response objectForKey:@"preferences"]) {
        NSLog(@"ID: %@", [[[response objectForKey:@"preferences"] objectForKey:dic] objectForKey:@"id"]);
        NSLog(@"NAME: %@", [[[response objectForKey:@"preferences"] objectForKey:dic] objectForKey:@"name"]);

        NSLog(@"Children DIC: %@", [[[[[response objectForKey:@"preferences"]
                                     objectForKey:dic] objectForKey:@"children"] objectAtIndex:0] objectForKey:@"3"]);

        for (NSDictionary *childDic in [[[[response objectForKey:@"preferences"]
                                          objectForKey:dic] objectForKey:@"children"] objectAtIndex:0]) {
            NSLog(@"Child Name: %@", [[[[[response objectForKey:@"preferences"]
                                        objectForKey:dic] objectForKey:@"children"] objectAtIndex:0] objectForKey:childDic]);
        }
    }

I have 3 questions.

  • How can I improve my code snippet? is there any shorter way to implement this?

  • Is this JSON response is good enough for mobile end parsing? is it good JSON format? Is there any JSON response format we should follow as Mobile developers in terms of using Core data (which simply reduces DB implementation as best practice)?

  • How do I construct a JSON string like this again from Objective-c?


  • Ok so, (Sorry for NOT deep analysis) first of all I'd modify your JSON not to contain dictionary for dynamic elements (samsung has key 3 and so on, it should be array, make sense?)

    I come up with imho better JSON structure:

    {  
       "preferences":[
          {
             "items":[
                {
                "id" : "3",
                "name" : "Samsung" 
                },
                {
                "id" : "3",
                "name" : "Nokia" 
                }
             ],
             "id":"1",
             "name":"Mobiles"
          },
          {  
             "items":[
               {
                "id" : "3",
                "name" : "Nokia" 
                }
             ],
             "id":"2",
             "name":"Electronics"
          }
    ]
    }
    

    It's really easy now to map it to objects with JSONModel and only one thing you should care about is mapping keys.

     NSString *JSONString = @"    {        "preferences":[        {            "items":[            {                "id" : "3",                "name" : "Samsung"            },            {                "id" : "3",                "name" : "Nokia"            }            ],            "id":"1",            "name":"Mobiles"        },        {            "items":[            {                "id" : "3",                "name" : "Nokia"            }            ],            "id":"2",            "name":"Electronics"        }        ]    }";
    
    
        NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:[JSONString dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
    
        NSError *mapError;
        GlobalPreferences *globalPreferences = [[GlobalPreferences alloc] initWithDictionary:dictionary error:&mapError];
        if (mapError) {
            NSLog(@"Something went wrong with mapping model %@", mapError);
        }
    
        NSLog(@"Your mapped model: %@", globalPreferences);
    

    Models:

    Kinda GlobalPreference, root model, in case if u decide to add something extra

     #import <JSONModel/JSONModel.h>
        #import "Preference.h"
    
        @interface GlobalPreferences : JSONModel
    
        @property (nonatomic, strong) NSArray<Preference> *preferences; // using protocol here you specifying to which model data should be mapped
        @property (nonatomic, strong) NSArray<Optional> *somethingElse; // some other settings may be here
    
        @end
    
        #import "GlobalPreferences.h"
    
        @implementation GlobalPreferences
    
        @end
    

    Preference

    #import <JSONModel/JSONModel.h>
      #import "PreferenceItem.h"
    
        @protocol Preference <NSObject>
    
        @end
    
        @interface Preference : JSONModel
    
        @property (nonatomic, strong) NSNumber *ID; // required
        @property (nonatomic, strong) NSString *name; // required
        @property (nonatomic, strong) NSArray<PreferenceItem> *items;
    
        @end
    
        #import "Preference.h"
    
        @implementation Preference
    
        #pragma mark - JSONModel
    
        + (JSONKeyMapper *)keyMapper {
            return [[JSONKeyMapper alloc] initWithDictionary:@{
                                                               @"id": @"ID",
                                                               }];
        }
    
        @end
    

    PreferenceItem

        #import <JSONModel/JSONModel.h>
    
        // This protocol just to let JSONModel know to which model needs to be parsed data in case if it's an array/dictionary
        @protocol PreferenceItem <NSObject>
        @end
    
    @interface PreferenceItem : JSONModel
    
    @property (nonatomic, strong) NSNumber *ID;
    @property (nonatomic, strong) NSString *name;
    
    @end
    #import "PreferenceItem.h"
    
    @implementation PreferenceItem
    
    #pragma mark - JSONModel
    
    + (JSONKeyMapper *)keyMapper {
        return [[JSONKeyMapper alloc] initWithDictionary:@{
                                                           @"id": @"ID",
                                                           }];
    }
    
    @end
    

    Should be ok for coreData .

    Maybe for you case all this is not necessary, but there are lot of things you need to care when u parsing/mapping network response such es data types , missing keys , error handling and so on. If u map it manually - you risk to have broken app some day.


    I know you asked best practices for Objective-C, but I would suggest switching to Swift and using SwiftyJSON. With Swift the code is much more readable than with Objective-C.

    let prefs = json["preferences"]
    let userName = prefs["id"].stringValue
    let name = prefs["name"].stringValue
    let child = prefs["children"].arrayValue[0].arrayValue[3]
    

    https://github.com/SwiftyJSON/SwiftyJSON

    You can easily build your own JSON structures and send them with Alamofire:

    let parameters: [String : AnyObject] = [
      "preferences": [
        "id": "123",
        "name": "John",
        "children": [
           ["3": "Three"]
        ]
      ]
    ]
    
    let urlReq = NSMutableURLRequest(url)
    urlReq.HTTPMethod = .POST
    
    let req = Alamofire.ParameterEncoding.JSON.encode(urlReq, parameters: parameters).0
    let request = Alamofire.request(req)
    

    https://github.com/Alamofire/Alamofire

    链接地址: http://www.djcxy.com/p/48076.html

    上一篇: 什么是REST API响应的正确方法?

    下一篇: Objective中更好的JSON解析实现