2015-01-12 21 views
6

Tôi đang sử dụng một bộ dữ liệu để lưu trữ một cái gì đó như thế này.Lưu một bộ dữ liệu vào NSUserDefaults

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

Bây giờ tôi muốn lưu nó trong NSUserDefaults.

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

Nhưng tôi nhận được lỗi sau.

Loại '(hasInventoryAccess: Bool, hasPayrolAccess: Bool)' không phù hợp với giao thức 'AnyObject'

Làm thế nào tôi có thể giải quyết vấn đề này? Nếu nó không thể, sau đó bất kỳ đề xuất khác để lưu một tuple được chào đón.

Cảm ơn bạn.

+0

Là một sang một bên , gọi 'synchronise' trên' NSUserDefaults' gần như không bao giờ cần thiết và gọi nó là "chỉ trong trường hợp" không được khuyến cáo bởi Apple. –

+0

NSUserDefaults chỉ hỗ trợ các loại danh sách thuộc tính: NSData, NSString, NSNumber, NSDate, NSArray hoặc NSDictionary. Nếu bạn muốn lưu trữ bất kỳ loại đối tượng nào khác, bạn có thể lưu trữ nó để tạo một thể hiện của NSData. – Bobby

Trả lời

7

tôi gặp phải một tương tự kịch bản cố gắng mã hóa một tuple với NSCoder. Cách tôi giải quyết nó bằng cách chuyển đổi thủ công bộ tuple thành Dictionary. Đây không phải là một giải pháp tuyệt vời vì các phím cần phải được thay đổi ở một vài nơi nếu tuple thay đổi.

Tôi đã có một lồng nhau enum trong tuple của tôi và đã cho nó một loại cơ sở (String) mà từ đó tôi chuyển đổi giá trị thô. Đó là một chút công việc nhưng may mắn là của bạn chỉ là nguyên thủy.

# 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

Mẹo gọn gàng! Nó hoạt động tốt. Mặc dù tôi đã phải thực hiện một số thay đổi nhỏ như đúc và tôi nghĩ rằng bạn nên vượt qua trong 'AccessDictionary' để' deserializeDictionary() 'phương pháp. Tôi đã cập nhật mã của bạn để phản ánh các thay đổi. Hy vọng không sao. Dù sao cảm ơn cho các giải pháp aweseome. Tôi hy vọng Apple sẽ hỗ trợ cho điều này trong các phiên bản sắp tới của Swift. – Isuru

+0

Nhân tiện, có lý do cụ thể nào để sử dụng 'setObject' thay vì' setValue' và 'dictionaryForKey' thay vì' objectForKey' trong việc lưu và lấy các giá trị từ 'NSUserDefaults' không? – Isuru

+1

Vì @LucasHuang ghi chú 'setValue' là từ' NSKeyValueCoding'. 'setValue' sử dụng' id'/'AnyObject' làm loại của nó và do đó không cung cấp nhiều loại an toàn tại thời điểm biên dịch khi có sẵn. Từ điển là một lớp (và một thể hiện của từ điển là một đối tượng) và là các kiểu phương thức thích hợp nhất. Bạn * có thể * sử dụng các phương thức 'dataForKey' và chuyển đổi từ điển sang/từ NSData nhưng đó chỉ là công việc phụ. – JoePasq

0

Trong tài liệu, tôi không thấy bất kỳ phương thức nào -setValue. Dựa trên tài liệu, NSUserDefaults chỉ có thể lưu NSString, NSNumber, NSData, NSDictionary, NSArray, NSData và NSDate. Đây là liên kết: NSUserDefaults Class Reference.

Vì vậy, bạn không thể lưu tuple tại đây. Và -setValue là từ giao thức NSKeyValueCoding.

0

Bạn có thể lưu trữ Bool, Float, Int, Object, Double hoặc URL nhưng không phải là Tuple. Vì vậy, bạn có hai lựa chọn, tiết kiệm hai chỉ hasPayrolAccess và hasPayrolAccess Bool giá trị:

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) 

Hoặc lưu nó sử dụng một mảng của 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) 
    } 
} 
+0

Lưu trữ dưới dạng hai công cụ tách riêng biệt nhưng không tận dụng được sức mạnh của bộ dữ liệu và phân tách dữ liệu. Lưu trữ như một mảng là tốt hơn một chút bởi vì chỉ có một mục được lưu trữ, nhưng từ điển rõ ràng hơn vì các phím (đặc biệt là cho các bộ dữ liệu tùy ý). – JoePasq

1

Tôi đã có một tuple với 3 giá trị.

Mã sau được sử dụng để lưu bộ dữ liệu. Về cơ bản, tôi đã tạo một chuỗi từ tuple (với các thành phần được phân tách bằng dấu phẩy).

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

Để truy xuất bộ dữ liệu, tôi đã truy xuất chuỗi, chia nhỏ mảng và sử dụng mảng để tạo lại bộ tuple.

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

I'ts một câu hỏi cũ năm nhưng vẫn:

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

Trong trường hợp bạn chỉ lưu bools, let accesLvl : [String:Bool] là một lựa chọn tốt hơn.

Trong trường hợp tôi không nhận được một cái gì đó (tôi khá mới để Swift và lập trình hoàn toàn), điều gì sẽ là lợi ích của việc sử dụng một "tuple" trên một từ điển, hoặc thậm chí một struct

+0

Tuple dễ thực hiện và sử dụng hơn. Không còn khóa nữa. – Glenn

Các vấn đề liên quan