【swift】JSONをDictionary/NSDictionaryで扱いたくないので、ちょっと検討してみたメモ

swiftにおいて、jsonの扱い方については、すでに、

http://qiita.com/yukihamada/items/9b0067f905418105a2c6
http://qiita.com/dankogai/items/e3d9882f4d25bc44cc03
http://qiita.com/g08m11/items/c3746cbdbdb4c7b71607
http://qiita.com/Ushio@github/items/c5f1127947d6740737f4

という記事で紹介されているように、
いくつかクラス、構造体、列挙型が紹介されてまして、基本的には
それらを使えばいいのかなというところですが、
せっかくなので、swiftでの実装の試しということで、これらのソースを眺めながら
プロトコルやらの扱いをやってみたかったので、個人的に考えてみた。


##目的

外部APIなどのレスポンスとしてJSONを扱う場合、
受け取った、NSDataを、NSJSONSerializationで変換する事が多いので、
それの代わりとしたい。

##ひとまず構造体として進める。


```swift
public struct JSONObject {

    private var _jsondata:AnyObject?;
    
    //newvalue などで利用することもあるので
    public var jsondata:AnyObject!{
        get{
            return _jsondata;
        }
    }
    
    //NSJSONSerialization.JSONObjectWithDataと同等の引数を用意
    //外部からのNSDataを利用する。
    public init(data:NSData, options opt: NSJSONReadingOptions = .AllowFragments, error: NSErrorPointer = nil) {
        _jsondata = NSJSONSerialization.JSONObjectWithData(data, options: opt, error: error);
    }
    
    //json内各々のデータを扱うため
    public init(_ jsondata: AnyObject!) {
        _jsondata = jsondata
    }

```



## indexやkeyを指定してのデータの取得を行いたい。

扱いとして、jsonのデータを扱う場合において、
json[0]["hoge"]

のような形で扱いたい。

その場合、

subscriptの実装が必要になります。
また、クラッシュしないようにも考慮したいと思います。

クラッシュうんぬんに関しては、optional chaining で回避したい。


Arrayの場合

```swift

    public subscript(index: Int) -> JSONObject {
        get {
            if index < _jsondata?.count {
                return JSONObject(_jsondata?[index])
            }
            return JSONObject(nil);
        }
        set {
            if index < _jsondata?.count {
                var array:[AnyObject]! = _jsondata as [AnyObject]
                if array != nil {
                    array[index] = newValue.jsondata
                    _jsondata = array
                }
            }
        }
    }

```

Dictionayの場合

```swift

    public subscript(key: String) -> JSONObject {
        get {
            if let val:AnyObject? = _jsondata?[key] {
                return JSONObject(val)
            } else {
                return JSONObject(nil);
            }
        }
        set {
            var dic:[String : AnyObject]! = _jsondata as [String : AnyObject]!
            if dic != nil {
                dic[key] = newValue.jsondata
                _jsondata = dic
            }
        }
    }

```

##データの出力

json[0]["hoge"]としてデータのアクセスができたとしても、
あくまでJSONObjectのため、printlnで出力させたとしても、
JSONObject
と表示される。

そこで、
Printableに準拠させて
出力を調整する。


```swift

extension JSONObject: Printable {
    public var description: String {
        return toString();
    }

    private func toString() -> String{
        if let value: AnyObject = _jsondata {
            var ret:String = "";
            switch value {
            case let number as NSNumber:
                ret = number.stringValue
            case let string as NSString:
                ret = string
            case let null as NSNull:
                ret = "NSNull"
            case let array as [AnyObject]:
                var data:NSData! = NSJSONSerialization.dataWithJSONObject(array,
                    options:NSJSONWritingOptions.PrettyPrinted,
                    error:nil)
                if data != nil {
                    ret = NSString(data: data!, encoding: NSUTF8StringEncoding)!
                }
            case let dic as [String : AnyObject]:
                var data:NSData! = NSJSONSerialization.dataWithJSONObject(dic,
                    options:NSJSONWritingOptions.PrettyPrinted,
                    error:nil)
                if data != nil {
                    ret = NSString(data: data!, encoding: NSUTF8StringEncoding)!
                }
            default:
                //unknown
                ret = "unknown";
            }
            return ret;
        } else {
            return "";
        }
    }
}

```



##データの取得

様々な型について考慮が必要ですが、
ひとまずString/Array/Dictionaryだけで。。


```swift

extension JSONObject {
    public var string:String?{
        get {
            if let value: AnyObject = _jsondata {
                switch(value) {
                case let string as NSString:
                    return string
                default:
                    return nil
                }
            }
            return nil;
        }
    }
    
    //string以外にも強制変換
    public var stringValue:String{
        get {
            return toString();
        }
    }


    public var array:[AnyObject]?{
        get {
            if let value: AnyObject = _jsondata {
                switch(value) {
                case let array as [AnyObject]:
                    return array as [AnyObject]?
                default:
                    return nil
                }
            }
            return nil;
        }
    }
    
    public var dictionary:[String : AnyObject]?{
        get {
            if let value: AnyObject = _jsondata {
                switch(value) {
                case let value as [String : AnyObject]:
                    return value as [String : AnyObject]?
                default:
                    return nil
                }
            }
            return nil;
        }
    }
}

```

##データの比較

Equatableを準拠させて、 == の実装を行う。


```swift


extension JSONObject:Equatable {

}

public func ==(lhs:JSONObject,rhs:JSONObject) -> Bool {
    //keyの並びなどを考えると、厳密性なし
    return lhs.stringValue ==  rhs.stringValue
}

```

色々と検討が中途半端ですが、この辺で

とりあえず、SwiftyJSONを使うのが手っ取り早そうですね！