Home > OS >  Objective C - Problem trying to Parse json and building a model
Objective C - Problem trying to Parse json and building a model

Time:06-12

Hi guys I need help with * OBJECTIVE C * I am new to Objc - but not to swift. but I find myself struggling with simple json parse and building a model.

here is an example of the model I am trying to parse.

{
"success": true,
"data": {
    "memes": [
        {
            "id": "61579",
            "name": "One Does Not Simply",
            "url": "https://i.imgflip.com/1bij.jpg",
            "width": 568,
            "height": 335,
            "box_count": 2
        },
        {
            "id": "101470",
            "name": "Ancient Aliens",
            "url": "https://i.imgflip.com/26am.jpg",
            "width": 500,
            "height": 437,
            "box_count": 2
        }
        // probably a lot more memes here..
    ]
}

}

I want to create a "MemeModel" to this json object. and parse it on my viewController and then add to my dataSource Array... could anyone explain me or show me how should it be done.. all the old objc googling didn't help me tho. thank you!

QTMeme.h file

@interface QTMeme : NSObject

@property (nonatomic,strong) QTData *data;

@end

@interface QTData : NSObject

@property (nonatomic,copy) NSMutableArray<QTMemeResponse *> *memes;

@end

@interface QTMemeResponse : NSObject

@property (nonatomic,copy) NSString *url;
@property (nonatomic,copy) NSString *name;

-(instancetype) initMemesWithImage:(NSString *)url withTitle:(NSString *)name;

@end

And this is the QTMeme.m File ..

    @implementation QTMeme
@end

@implementation QTData
@end

@implementation QTMemeResponse

-(instancetype) initMemesWithImage:(NSString *)url withTitle:(NSString *)name {
    self = [super init];
    
    if (self) {
        self.url = url;
        self.name = name;
    }
    return self;
}

@end

CodePudding user response:

First, let's rename your classes, they are misleading:

QTMeme -> QTMemeResponse
QTData -> QTMemeResponseData
QTMemeResponse -> QTMeme

Now, since we decode objects dictionaries, let's add a initWithJSONDictionary: method for each of them.

@interface QTMeme : NSObject
@property (nonatomic,copy) NSString *url;
@property (nonatomic,copy) NSString *name;
-(instancetype)initWithJSONDictionary:(NSDictionary *)dict;
-(instancetype) initMemesWithImage:(NSString *)url withTitle:(NSString *)name;
@end

@interface QTMemeResponseData : NSObject
@property (nonatomic,copy) NSMutableArray<QTMeme *> *memes;
-(instancetype)initWithJSONDictionary:(NSDictionary *)dict;
@end

@interface QTMemeResponse : NSObject
@property (nonatomic,strong) QTMemeResponseData *data;
-(instancetype)initWithJSONDictionary:(NSDictionary *)dict;
@end

Implementation:

@implementation QTMemeResponse
-(instancetype)initWithJSONDictionary:(NSDictionary *)dict {
    self = [super init];
    if (self) {
        self.data = [[QTMemeResponseData alloc] initWithJSONDictionary:dict[@"data"]];
    }
    return self;
}
@end

@implementation QTMemeResponseData
-(instancetype)initWithJSONDictionary:(NSDictionary *)dict {
    self = [super init];
    if (self) {
        NSArray *jsonDicts = dict[@"memes"];
        _memes = [[NSMutableArray alloc] init];
        for (NSDictionary *aJSONDict in jsonDicts) {
            QTMeme *aMeme = [[QTMeme alloc] initWithJSONDictionary:aJSONDict];
            [_memes addObject:aMeme];
        }
    }
    return self;
}
@end

@implementation QTMeme

-(instancetype)initWithJSONDictionary:(NSDictionary *)dict {
    return [self initMemesWithImage:dict[@"name"] withTitle:dict[@"url"]];
}
-(instancetype) initMemesWithImage:(NSString *)url withTitle:(NSString *)name {
    self = [super init];

    if (self) {
        self.url = url;
        self.name = name;
    }
    return self;
}

@end

The decoding:

NSError *decodingError = nil;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data
                                                     options:kNilOptions
                                                       error:&decodingError];

if (decodingError) {
    NSLog(@"Error while decoding JSON: %@ with stringified data: %@", decodingError, [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
} else {
    QTMemeResponse *decoded = [[QTMemeResponse alloc] initWithJSONDictionary:json];
    NSLog(@"decoded: %@", decoded);
}

Output:

$>decoded: <QTMemeResponse: 0x600001764810>

You can see the values in the debugguer, but maybe let's add some useful logs by overriding description:

For QTMemeResponse:

-(NSString *)description {
    return [NSString stringWithFormat:@"%@ data: %@", [super description], self.data];
}

For QTMemeResponseData:

-(NSString *)description {
    return [NSString stringWithFormat:@"%@ memes: %@", [super description], self.memes];
}

For QTMeme:

-(NSString *)description {
    return [NSString stringWithFormat:@"%@ name: %@, url: %@", [super description], self.name, self.url];
}

Which output now:

$>decoded: <QTMemeResponse: 0x600001764810> data: <QTMemeResponseData: 0x6000017648b0> memes: (
    "<QTMeme: 0x6000015300e0> name: https://i.imgflip.com/1bij.jpg, url: One Does Not Simply",
    "<QTMeme: 0x600001530100> name: https://i.imgflip.com/26am.jpg, url: Ancient Aliens"
)

Note that's how you'd have parsed JSON into CustomModel in Swift too before Codable using (NS)JSONSerialization. Of course, the for loop, could be a compactMap(), you'd need to do a lot of as? [String: Any], etc but that's the same idea...

  • Related