Posted at

objective-cのjsonデータのマッピング

More than 5 years have passed since last update.

JSONライブラリの紹介です。cocoapodsにも上がってます。


概要

サーバから取得したjson文字列をクラスオブジェクトにマッピングするライブラリです。

他にも似たようなライブラリは存在しますが、軽量かつコアとなる機能が欲しかったので作りました。

ライブラリを更新した際は、こちらもできるだけ更新していきたいと思います。


基本的な使い方


オブジェクトにマッピング

jsonデータのキー名と、クラスのプロパティ名を一致させておけば、データが自動的にマッピングされます。

例えば、以下のようなデータを取得したとします。


user.json

{

"name": "joe",
"age": 30
}

マッピングしたいクラスを作成しておきます。


User.h

@interface User : NSObject

@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, copy) NSString *address;

@end


マッピングさせたいデータと型を指定してマッピングします。

// jsonStringはuser.jsonの文字列

User *user = [G3JSON fromJSON:jsonString toClass:User.class];
NSLog(@"%@", user.name); // joe
NSLog(@"%d", user.age); // 30
NSLog(@"%@", user.address); // nil

オリジナルのクラスでもマッピング可能です。

例えば以下の社員情報のようなデータの場合。


employ.json

{

"id": 10,
"pay": 10000,
"user": {
"name": "joe",
"age": 30
}
}

クラス構造をjsonにマッピングできる状態で定義しておく。


Employ.h

@interface Employ : NSObject

@property (nonatomic, assign) NSInteger id;
@property (nonatomic, strong) NSNumber *pay; // 数値はNSNumberでもOK
@property (nonatomic, strong) User *user;

@end


あとは、Userクラスの時と同じようにマッピングすることができます。

Employ *employ = [G3JSON fromJSON:jsonString toClass:Employ.class];

NSLog(@"%d", employ.id); // 10
NSLog(@"%@", employ.pay); // 10000
NSLog(@"%@", employ.user.name); // joe

また、取得したjson文字列をNSDictionaryなどに自分でシリアライズしている場合は、構造が同じであれば、そのオブジェクトをマッピングすることも可能です。

Employ *employ = [G3JSON fromJSONObject:serializedObject toClass:Employ.class];

それから、プロパティ名をキャメルケースで定義している場合、サーバから取得したjsonデータのキーがスネークケースでもマッピングが可能となります。


product.json

{

"product_name": "g3json",
"product_code": "g3"
}


Product.h

@interface Product : NSObject

// どちらもマッピングOK
@property (nonatomic, copy) NSString *productName;
@property (nonatomic, copy) NSString *product_code;

@end



オブジェクトを文字列に変更

任意のオブジェクトをjson文字列に変換することができます。

User *user = [[User alloc] init];

user.name = @"bob";
user.age = 20;
user.address = @"Tokyo";

Employ *employ = [[Employ alloc] init];
employ.id = 5;
employ.user = user;

NSString *jsonString = [G3JSON toJSON:employ];
NSLog(@"%@", jsonString); // {"id":5,"pay":null,"user":{"age":20,"name":"bob","address":"Tokyo"}}

jsonオブジェクトに変換することもできます。

NSDictionary *jsonObject = [G3JSON toJSONObject:employ];

NSLog(@"%@", jsonObject);
/*
{
id = 5;
pay = "<null>";
user = {
address = Tokyo;
age = 20;
name = bob;
};
}
*/


気をつけること


トップレベルオブジェクトが配列

jsonのトップレベルオブジェクトが配列の際は、配列の中身がすべてマッピング対象クラスの形式になっている必要があります。


ok.json

[

{
"id": 10,
"pay": 10000,
"user": {
"name": "joe",
"age": 30
}
}, {
"id": 5,
"pay": null,
"user": {
"name": "bob",
"age": 20
}
}
]

以下のような場合は、正常にマッピングされません。


ng.json

[

{
"id": 10,
"pay": 10000,
"user": {
"name": "joe",
"age": 30
}
}, {
"name": "bob",
"age": 20
}
]


jsonの途中に配列のデータが含まれる

jsonの値が配列の場合、その中にあるデータはすべてNSDictionaryに変換されます。


company.json

[

{
"name": "example",
"address": "Tokyo",
"employ": [{
"name": "joe",
"age": 30
}, {
"name": "bob",
"age": 20
}]
}
]


Company.h

@interface Company : NSObject

@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *address;
@property (nonatomic, copy) NSArray *employ;

@end


上記のような場合は、employの中のデータはすべてNSDictionaryとなります。

※今後、任意のクラスを設定できるように対応したいとは思っています。