SwiftyUserDefaults
SwiftyUserDefaults copied to clipboard
Attempt to insert non-property list object
I just updated to version 5 from version 3 and I'm getting an "Attempt to insert non-property list object"-error.
Code used in version 3:
extension DefaultsKeys {
static let userColors = DefaultsKey<[String: UIColor]>("userColors")
}
extension UserDefaults {
subscript(key: DefaultsKey<[String: UIColor]>) -> [String: UIColor] {
get { return unarchive(key) ?? [:] }
set { archive(key, newValue) }
}
}
Code used for version 5:
extension UIColor: DefaultsSerializable {}
extension DefaultsKeys {
var userColors: DefaultsKey<[String: UIColor]> { .init("userColors", defaultValue: [:]) }
}
This gives me the error mentioned above though, am I missing something?
Hey @pepejeria, we do not support dictionary objects other than the [String: WhateverIsAbleToBeStoredByPlists]
. So basically UIColor
is not ready yet to be stored in a dictionary in User Defaults. There is a ground work for it being implemented there, but it's not implemented yet. It would require checking the type of the value and use serializing (similar to how we observe keys). Though I'm not sure if it will be implemented soon since I don't have much time for new additions to the library - maybe you would like to contribute?
For now you can create a custom object that holds the dictionary and specify archive bridges for encoding/decoding the type.
I created a custom object that holds the dictionary, based on the example provided in the documentation:
struct UserColors: DefaultsSerializable {
static var _defaults: DefaultsBridge<UserColors> { DefaultsKeyedArchiverBridge() }
static var _defaultsArray: DefaultsBridge<[UserColors]> { DefaultsKeyedArchiverBridge() }
let colorsDic: [String: UIColor] = [:]
}
But this won't compile, nor does the FrogCustomSerializable
example compile.
@pepejeria what’s the compile error?

@pepejeria ah sorry about that, seems like some parts of the docs are not updated. Here’s a source code for one of our test cases, you would specify a specific type and return it like that: https://github.com/sunshinejr/SwiftyUserDefaults/blob/38441153885b660da10d3ff742b7e4fe8e8f11cc/Tests/SwiftyUserDefaultsTests/TestHelpers/TestHelper.swift#L106
Also here’s a archive bridge you would probably use for your type.
Let me know if it helps.
How would I be able to support something like this? (I'm upgrading from version 3)
subscript(key: DefaultsKey<[CKRecordZone.ID: CKServerChangeToken?]>) -> [CKRecordZone.ID: CKServerChangeToken?] {
get { return unarchive(key) ?? [:] }
set { archive(key, newValue) }
}
Would it look something like this?
struct CKServerchangeTokenSerializable: DefaultsSerializable {
static var _defaults: DefaultsKeyedArchiverBridge<[CKRecord.ID: CKServerChangeToken?]> { return DefaultsKeyedArchiverBridge() }
static var _defaultsArray: DefaultsKeyedArchiverBridge<[[CKRecord.ID: CKServerChangeToken?]]> { return DefaultsKeyedArchiverBridge() }
let changeTokens: [CKRecord.ID: CKServerChangeToken] = [:]
}
and instead of accessing it like a dictionary from user defaults, It would be like Defaults[\.serverChangeTokens].changeTokens[record.ID]
?
hey @MaxHasADHD, if you used archiving then yes, you could use the DefaultsKeyedArchiverBridge
👍 in terms of usage you're correct (given . serverChangeTokens
is a DefaultsKey<CKServerchangeTokenSerializable>
), depending on your Swift version you could also try using Defaults.serverChangeTokens
since we have the support for this syntax too.
import UIKit
class ViewController: UIViewController {
@IBOutlet var notesTextView: UITextView!
@IBOutlet var titleTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func saveButton(_ sender: Any) {
UserDefaults.standard.set(titleTextField, forKey: "Title")
UserDefaults.standard.set(notesTextView, forKey: "Body")
}
@IBAction func loadNote(_ sender: Any) {
let title = titleTextField.text
print("my title is: \(title!)")
let notes = notesTextView.text
print("my body is: \(notes!)")
titleTextField.text =
UserDefaults.standard.object(forKey:
"Title") as? String
notesTextView.text =
UserDefaults.standard.object(forKey:
"Body") as? String
}
} i am having the same issue please help