Сохранить кортеж в NSUserDefaults

Я использую кортеж для хранения чего-то подобного.

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

Теперь я хочу сохранить его в NSUserDefaults,

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

Но я получаю следующую ошибку.

Тип '(hasInventoryAccess: Bool, hasPayrolAccess: Bool)' не соответствует протоколу 'AnyObject'

Как я могу решить эту проблему? Если это невозможно, тогда любые другие предложения по сохранению кортежа приветствуются.

Спасибо.

5 ответов

Решение

Я столкнулся с похожим сценарием, пытаясь закодировать кортеж с 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)

Вы можете хранить Bool, Float, Int, Object, Double или URL, но не Tuple. Таким образом, у вас есть два варианта, сохраните только два значения hasPayrolAccess и hasPayrolAccess Bool:

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)

Или сохраните его, используя Array of Bool:

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)
    }
}

У меня был кортеж с 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")
}

Чтобы извлечь кортеж, я извлек строку, разбил ее на массив и использовал массив для воссоздания кортежа.

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

Мне годовалый вопрос, но все же:

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

Если вы сохраняете только bools, let accesLvl : [String:Bool] это лучший вариант.

Если я что-то не получаю (я довольно новичок в Swift и программировании в целом), какая польза от использования "кортежа" над словарем или даже структуры

В документации я не вижу никакого метода -setValue, На основе документов NSUserDefaults может сохранять только NSString, NSNumber, NSData, NSDictionary, NSArray, NSData и NSDate. Вот ссылка: Ссылка класса NSUserDefaults.

Таким образом, вы не можете сохранить кортеж здесь. А также -setValue из NSKeyValueCodingпротокол.

Другие вопросы по тегам