Swift｜Tuple（タプル）型をDictionary（辞書）型に変換

#前提
環境
- Xcode 7.2.1
言語
- Swift 2.1


#やりたいこと

- Tuple型をDictionary型に変換
- NSUserDefaultsを使ってデータを保存
- データの取り出し

なぜ変換するかというと、
たとえば、
Tuple型はそのままNSUserDefaultsに保存できない。（詳しい理由は下に）

#Tuple Type （タプル）
ざっくりに説明すると、異なる型の値を括弧とコンマでまとめる型である.
##値に名前を付けずに宣言する
タプルは値に名前を付けて宣言することができるが、
名前を付けなくてもタプル型は、(0番, 1番,　2番)のように値を参照する。

```swift:
var tuple1 = ("str", 1234, true)

print(tuple1) // -->> ("str", 1234, true)

print(tuple1.0) // -->> str
print(tuple1.1) // -->> 1234

// Arrayもオッケー
var tuple2 = ("myArray1", 1, ["apple", "banana", "cherry"])

print(tuple2.2) // -->> ["apple", "banana", "cherry"]

//おまけ -->>　タプルの値の数をカウント
let count = Mirror(reflecting: tuple2).children.count // -->> 3

```

##値に名前を付けて宣言する

```swift:
var tuple3 = (name: "Andy", score: 1234, cheated: true)

print(tuple3.name) // -->> Andy
print(tuple3.score) // -->> 1234
```

#変換
##Dictionaryに変換

```swift:
typealias convertTuple = (name1: String, name2: Bool, name3: Int)
typealias convertDictionary = [String: Any]

let name1 = "name1"
let name2 = "name2"
let name3 = "name3"

func serializeTuple(xtuple: convertTuple) -> convertDictionary {
    return [
        name1 : xtuple.name1,
        name2 : xtuple.name2,
        name3 : xtuple.name3
    ]
}
```

##Tupleに戻す

```swift:
func deserializeDictionary(xdictionary: convertDictionary) -> convertTuple {
    return convertTuple(
        xdictionary[name1] as! String!,
        xdictionary[name2] as! Bool!,
        xdictionary[name3] as! Int!
    )
}
```

##使ってみる

```swift:
var tupleWantToConvert: convertTuple = (name1: "Hello", name2: false, name3: 1234)
let convertedDictionary = serializeTuple(tupleWantToConvert) 
// -->> ["name2": false, "name3": 1234, "name1": "Hello"]
let convertedTuple = deserializeDictionary(convertedDictionary)
// -->>> (.0 "Hello", .1 false, .2 1234)　順番戻る
```

##ちょっとまとめる

- かなり手間がかかる
- Tupleの名前が多いときは推奨できない
- Dictionary型に変換したときのデータの順番は保証できない -->> [公式ドキュメント](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html)

辞書型の順番は気にすることないと思うが、
問題はTupleの値の名前が多すぎると、上のコードのように値の名前と型を合わせる手間が多くなるので、初めから辞書型を使うといいかもしれない。

これについて、もっと良い変換方法があれば、是非コメントをお願いします！

#Tuple型のNSUserDefaults保存
Tuple型を変換せずにNSUserDefaultsを使って保存するとエラーが生じる。（理由は下）
解決策として、

- Tuple型をDictionary型に変換
- NSDataにエンコーディング
- ~~String型に変換~~（実用的ではない）

Tuple型は簡単にNSCoding使えないため、ちょっと手間がかかる。

##読み書き

```swift:
var tupleWantToConvert: convertTuple = (name1: "Hello", name2: false, name3: 1234)

// 書き込む
let convertedDictionary = serializeTuple(tupleWantToConvert)
NSUserDefaults.standardUserDefaults().setObject(myConvertedDictionary, forKey: "DATA")

// 読み込む
let fetchedDictionary = NSUserDefaults.standardUserDefaults().dictionaryForKey("DATA") as convertDictionary
// Tuple型で利用したいとき
let fetchedTuple = deserializeDictionary(fetchedDictionary)
```

##なぜ保存できないか
Appleの公式ドキュメント[Foundation Framework Reference](https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/)から一部抜粋
> The NSUserDefaults class provides convenience methods for accessing common types such as floats, doubles, integers, Booleans, and URLs. **A default object must be a property list, that is, an instance of (or for collections a combination of instances of): NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary.** If you want to store any other type of object, you should typically archive it to create an instance of NSData. For more details, see Preferences and Settings Programming Guide.

太字でマークした箇所を見ると、扱えるデータとして、
`NSData, NSString, NSNumber, NSData, NSArray, NSDictionary`がある。
さらに前の文に型として、
（複数の）Double, Float, Int, Boolean, URLを保存することができる。
これによるとNSUserDefaultsはTupleを扱うことができない。

解決方法は太字マークの後ろに、保存したいものをNSDataにすること。

今回はTuple型、クラスではないため、そのままエンコーディングすることはできない。方法としては、タプル内の値を一個一個抽出して、エンコーディングを行う。NSDataとしてNSUserDefaultsに保存する。

#GitHub
Download Zipでswiftのplaygroundがダウンロードされる
[convertTupleToDictionary](https://github.com/TouMotonori/ConvertTupleToDicionary)