#前提
環境
- Xcode 7.2.1
言語 - Swift 2.1
#やりたいこと
- Tuple型をDictionary型に変換
- NSUserDefaultsを使ってデータを保存
- データの取り出し
なぜ変換するかというと、
たとえば、
Tuple型はそのままNSUserDefaultsに保存できない。(詳しい理由は下に)
#Tuple Type (タプル)
ざっくりに説明すると、異なる型の値を括弧とコンマでまとめる型である.
##値に名前を付けずに宣言する
タプルは値に名前を付けて宣言することができるが、
名前を付けなくてもタプル型は、(0番, 1番, 2番)のように値を参照する。
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
##値に名前を付けて宣言する
var tuple3 = (name: "Andy", score: 1234, cheated: true)
print(tuple3.name) // -->> Andy
print(tuple3.score) // -->> 1234
#変換
##Dictionaryに変換
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に戻す
func deserializeDictionary(xdictionary: convertDictionary) -> convertTuple {
return convertTuple(
xdictionary[name1] as! String!,
xdictionary[name2] as! Bool!,
xdictionary[name3] as! Int!
)
}
##使ってみる
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型に変換したときのデータの順番は保証できない -->> 公式ドキュメント
辞書型の順番は気にすることないと思うが、
問題はTupleの値の名前が多すぎると、上のコードのように値の名前と型を合わせる手間が多くなるので、初めから辞書型を使うといいかもしれない。
これについて、もっと良い変換方法があれば、是非コメントをお願いします!
#Tuple型のNSUserDefaults保存
Tuple型を変換せずにNSUserDefaultsを使って保存するとエラーが生じる。(理由は下)
解決策として、
- Tuple型をDictionary型に変換
- NSDataにエンコーディング
-
String型に変換(実用的ではない)
Tuple型は簡単にNSCoding使えないため、ちょっと手間がかかる。
##読み書き
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から一部抜粋
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