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


JSONライブラリの紹介です。[cocoapods](http://cocoapods.org/?q=G3JSON)にも上がってます。

* https://github.com/KyoheiG3/G3JSON


## 概要
サーバから取得したjson文字列をクラスオブジェクトにマッピングするライブラリです。
他にも似たようなライブラリは存在しますが、軽量かつコアとなる機能が欲しかったので作りました。
ライブラリを更新した際は、こちらもできるだけ更新していきたいと思います。

## 基本的な使い方
### オブジェクトにマッピング

jsonデータのキー名と、クラスのプロパティ名を一致させておけば、データが自動的にマッピングされます。
例えば、以下のようなデータを取得したとします。

```json:user.json
{
	"name": "joe",
	"age": 30
}
```

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

```objectivec:User.h
@interface User : NSObject

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

@end
```

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

```objectivec
// jsonStringはuser.jsonの文字列
User *user = [G3JSON fromJSON:jsonString toClass:User.class];
NSLog(@"%@", user.name); // joe
NSLog(@"%d", user.age); // 30
NSLog(@"%@", user.address); // nil
```

オリジナルのクラスでもマッピング可能です。
例えば以下の社員情報のようなデータの場合。

```json:employ.json
{
	"id": 10,
	"pay": 10000,
	"user": {
		"name": "joe",
		"age": 30
	}
}
```

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

```objectivec:Employ.h
@interface Employ : NSObject

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

@end
```

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

```objectivec
Employ *employ = [G3JSON fromJSON:jsonString toClass:Employ.class];
NSLog(@"%d", employ.id); // 10
NSLog(@"%@", employ.pay); // 10000
NSLog(@"%@", employ.user.name); // joe
```

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

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

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

```json:product.json
{
	"product_name": "g3json",
	"product_code": "g3"
}
```

```objectivec:Product.h
@interface Product : NSObject

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

@end
```

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

```objectivec
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オブジェクトに変換することもできます。

```objectivec
NSDictionary *jsonObject = [G3JSON toJSONObject:employ];
NSLog(@"%@", jsonObject);
/*
{
    id = 5;
    pay = "<null>";
    user =     {
        address = Tokyo;
        age = 20;
        name = bob;
    };
}
*/
```

## 気をつけること

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

```json:ok.json
[
	{
		"id": 10,
		"pay": 10000,
		"user": {
			"name": "joe",
			"age": 30
		}
	}, {
		"id": 5,
		"pay": null,
		"user": {
			"name": "bob",
			"age": 20
		}
	}
]
```

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

```json:ng.json
[
	{
		"id": 10,
		"pay": 10000,
		"user": {
			"name": "joe",
			"age": 30
		}
	}, {
		"name": "bob",
		"age": 20
	}
]
```

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

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

```objectivec:Company.h
@interface Company : NSObject

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

@end
```

上記のような場合は、employの中のデータはすべて`NSDictionary`となります。
※今後、任意のクラスを設定できるように対応したいとは思っています。