2015-01-12 23 views
6

タプルを使用してこのようなものを保存しています。NSUserDefaultsにタプルを保存する

var accessLavels: (hasInventoryAccess: Bool, hasPayrolAccess: Bool) 
accessLavels = (hasInventoryAccess: true, hasPayrolAccess: false) 

ここではNSUserDefaultsに保存します。

NSUserDefaults.standardUserDefaults().setValue(accessLavels, forKey: "AccessLevelKey") 
NSUserDefaults.standardUserDefaults().synchronize() 

ただし、次のエラーが発生します。

タイプ '(hasInventoryAccess:ブール値、hasPayrolAccess:ブール値)' プロトコルに準拠していない 'ANYOBJECT'

どのように私はこの問題を解決することができますか?その不可能な場合は、タプルを保存するための他の提案は歓迎です。

ありがとうございます。

+0

どのようになるか、(私は完全にスウィフトやプログラミングにかなり新しいです)何かを得ることはありません'NSUserDefaults'で' synchronize'を呼び出すことはほとんど決して必要なことではなく、 "ちょうどいい"ということをAppleが推奨していません。 –

+0

NSUserDefaultsは、NSData、NSString、NSNumber、NSDate、NSArray、またはNSDictionaryのプロパティリストタイプのみをサポートしています。他のタイプのオブジェクトを保存する場合は、アーカイブしてNSDataのインスタンスを作成できます。 – Bobby

答えて

7

を私は類似したに遭遇しましたNSCoderでタプルをエンコードしようとしています。私が解決する方法は、タプルを手動でDictionaryに変換することです。タプルが変更された場合、キーをいくつかの場所で変更する必要があるため、これは素晴らしい解決策ではありません。

私はタプルに入れ子になった列挙型を持っていて、元の値を変換した基底型(String)を与えました。少し余分な仕事でしたが、ありがたいことに、あなたはプリミティブです。

# SerializeableTuple.swift 

typealias AccessTuple = (hasInventoryAccess: Bool, hasPayrolAccess: Bool) 
typealias AccessDictionary = [String: Bool] 

let InventoryKey = "hasInventoryAccess" 
let PayrollKey = "hasPayrollAccess" 

func serializeTuple(tuple: AccessTuple) -> AccessDictionary { 
    return [ 
     InventoryKey : tuple.hasInventoryAccess, 
     PayrollKey : tuple.hasPayrolAccess 
    ] 
} 

func deserializeDictionary(dictionary: AccessDictionary) -> AccessTuple { 
    return AccessTuple(
     dictionary[InventoryKey] as Bool!, 
     dictionary[PayrollKey] as Bool! 
    ) 
} 

# Encoding/Decoding 

var accessLavels: AccessTuple = (hasInventoryAccess: true, hasPayrolAccess: false) 

// Writing to defaults 
let accessLevelDictionary = serializeTuple(accessLavels) 
NSUserDefaults.standardUserDefaults().setObject(accessLevelDictionary, forKey: "AccessLevelKey") 

// Reading from defaults 
let accessDic = NSUserDefaults.standardUserDefaults().dictionaryForKey("AccessLevelKey") as AccessDictionary 
let accessLev = deserializeDictionary(accessDic) 
+1

素敵なトリック!それはうまくいく。キャスティングのように少し変更する必要がありましたが、 'AccessDictionary'を' deserializeDictionary() 'メソッドに渡すべきだと思います。変更を反映するようにコードを更新しました。希望は大丈夫です。とにかく驚くべき解決策に感謝します。 Appleが今後のバージョンのSwiftでこれをサポートしてくれることを願っています。 – Isuru

+0

ところで、 'NSUserDefaults'から値を保存して取り出す際に' objectForKey'の代わりに 'setValue'と' dictionaryForKey'の代わりに 'setObject'を使用する特別な理由はありますか? – Isuru

+1

@LucasHuangは 'setValue'は' NSKeyValueCoding'のものです。 'setValue'はその型として' id'/'AnyObject'を使います。したがって、コンパイル時に型の安全性を提供しません。 Dictionaryはクラスであり(Dictionaryのインスタンスがオブジェクトです)、最も適切な型メソッドです。あなたは 'dataForKey'メソッドを使用してDictionaryをNSDataに/から変換することができますが、これはちょっとした作業です。 – JoePasq

0

ドキュメントでは、どのメソッドも表示されません。-setValue ドキュメントに基づいて、NSUserDefaultsは、NSString、NSNumber、NSData、NSDictionary、NSArray、NSDataおよびNSDateのみを保存できます。ここにリンクがあります: NSUserDefaults Class Reference.

ここでタプルを保存することはできません。 -setValueは、NSKeyValueCodingプロトコルである。

0

Bool、Float、Int、Object、Double、またはURLは格納できますが、タプルは格納できません。だから、2つの のオプションがあり、2つののみhasPayrolAccessとhasPayrolAccessブール 値保存:

NSUserDefaults.standardUserDefaults().setBool(true, forKey: "hasInventoryAccess") 
NSUserDefaults.standardUserDefaults().setBool(false, forKey: "hasPayrolAccess") 
let hasInventoryAccess = NSUserDefaults.standardUserDefaults().boolForKey("hasInventoryAccess") 
println(hasInventoryAccess) 

let hasPayrolAccess = NSUserDefaults.standardUserDefaults().boolForKey("hasPayrolAccess") 
println(hasPayrolAccess) 

またはブールの配列を使用して、それを保存します。

var accessLavels = [true,false] 
println(accessLavels) 
NSUserDefaults.standardUserDefaults().setValue(accessLavels, forKey: "accessLavels") 
if let loadAccessLavels = NSUserDefaults.standardUserDefaults().arrayForKey("accessLavels") as? [Bool] { 
    if let hasInventoryAccess = loadAccessLavels.first { 
     println(hasInventoryAccess) 
    } 
    if let hasPayrolAccess = loadAccessLavels.last { 
     println(hasPayrolAccess) 
    } 
} 
+0

2つの別々のboolとして保存しますが、タプルの力を利用せず、データを分割します。 1つのアイテムしか格納されていないので、配列として格納するのが少し良いですが、キー(特に任意のタプル)のために辞書がより明確になります。 – JoePasq

1

私は3つの値を持つタプルを持っていました。

タプルの保存には次のコードを使用しました。基本的には、タプル(コンマで区切られたコンポーネント)から文字列を作成しました。

let defaultsLoad = NSUserDefaults.standardUserDefaults() 
if appSingleton.runwayDestShared != nil 
{ 
    // Creating a String from the tuple 
    let runwayDestString = appSingleton.runwayDestShared!.0 + "," + appSingleton.runwayDestShared!.1 + "," + appSingleton.runwayDestShared!.2 
    defaultsLoad.setObject(runwayDestString, forKey: "RunwayDest") 
} 

タプルを取得するために、私は、文字列を取得し、配列にそれを破ったと再作成タプルに配列を使用。あなただけboolsを保存する場合は

let accesLvl : [String:AnyObject] = ["hasInventoryAcces":true, "hasPayrolAccess":false] 
NSUserDefaults.standardUserDefaults().setObject(accesLvl, forKey: "accesLevel") 

let accesLvl : [String:Bool]は良いオプションです:歳の質問が、まだI'ts

let runwayDestString = defaultsLoad.stringForKey("RunwayDest") 
if let runwayDestString = runwayDestString 
{ 
    let runwayDestArray = runwayDestString.componentsSeparatedByString(",") 
    appSingleton.runwayDestShared = (runwayDestArray[0],runwayDestArray[1],runwayDestArray[2]) 
} 
0

場合、私はさておきとして、辞書上で「タプル」を使用することの利点、あるいは構造体

+0

タプルの作成と使用が簡単です。キーはこれ以上ありません。 – Glenn

関連する問題