Attempt to insert non-property list object when trying to save a custom object in Swift 3
You need to create Data
instance from your JobCategory
model using JSONEncoder
and store that Data
instance in UserDefaults
and later decode using JSONDecoder
.
struct JobCategory: Codable {
let id: Int
let name: String
}
// To store in UserDefaults
if let encoded = try? JSONEncoder().encode(category) {
UserDefaults.standard.set(encoded, forKey: UserDefaultsKeys.jobCategory.rawValue)
}
// Retrieve from UserDefaults
if let data = UserDefaults.standard.object(forKey: UserDefaultsKeys.jobCategory.rawValue) as? Data,
let category = try? JSONDecoder().decode(JobCategory.self, from: data) {
print(category.name)
}
Old Answer
You need to create Data
instance from your JobCategory
instance using archivedData(withRootObject:)
and store that Data
instance in UserDefaults
and later unarchive using unarchiveTopLevelObjectWithData(_:)
, So try like this.
For Storing data in UserDefaults
let category = JobCategory(id: 1, name: "Test Category", URLString: "http://www.example-job.com")
let encodedData = NSKeyedArchiver.archivedData(withRootObject: category, requiringSecureCoding: false)
let userDefaults = UserDefaults.standard
userDefaults.set(encodedData, forKey: UserDefaultsKeys.jobCategory.rawValue)
For retrieving data from UserDefaults
let decoded = UserDefaults.standard.object(forKey: UserDefaultsKeys.jobCategory.rawValue) as! Data
let decodedTeams = NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(decoded) as! JobCategory
print(decodedTeams.name)
Cannot set non-property-list object in UserDefaults
The answer was to use keyedArchiver to convert the object to an NSData object. Here is the Swift 3 code for storing, and retrieving the object:
func saveGame() {
UserDefaults.standard.set(NSKeyedArchiver.archivedData(withRootObject: hero), forKey: HeroObjectKey)
}
func defaultExistsForGameData() -> Bool {
var gameData = false
if let heroObject = UserDefaults.standard.value(forKey: HeroObjectKey) as? NSData {
hero = NSKeyedUnarchiver.unarchiveObject(with: heroObject as Data) as! Hero
gameData = true
}
return gameData
}
Userdefault error with Attempt to set a non-property-list object
Please read the error message carefully, it's pretty clear.
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to insert non-property list object ( "(temperature: \"C\", measurement: \"mm\")" ) for key Current Weather Setting'
The list object is a tuple which is not property list compliant.
A reasonable solution is a custom struct and Codable
, the completion handler is pointless because UserDefaults
is synchronous.
struct WeatherUnit : Codable {
let temperature, measurement : String
}
var currentWeatherUnit = [WeatherUnit]()
func checkingForSetting() {
if let data = UserDefaults.standard.data(forKey: "Current Weather Setting") {
do {
currentWeatherUnit = try PropertyListDecoder().decode([WeatherUnit].self, from: data)
print("Current weather setting is exist")
} catch { print(error) }
} else {
currentWeatherUnit = [WeatherUnit(temperature: "C", measurement: "mm")]
let data = try? PropertyListEncoder().encode(currentWeatherUnit)
UserDefaults.standard.set(data, forKey: "Current Weather Setting")
print("Create new setting for current weather")
}
}
Attempt to insert non-property list object error while storing dictionary in userdefaults
User defaults is a property list. Property list dictionaries must have string keys.
You can always test the eligibility of something to be put directly into User Defaults like this:
let d : [Int:[Int]] = [1100110004 : [1,2,0,0]]
do {
let data = try PropertyListSerialization.data(
fromPropertyList: d, format: .binary, options: 0)
} catch { print(error) }
A simple and obvious solution: your d
is Codable, so encode it to a property list and store the resulting Data object in user defaults.
let d : [Int:[Int]] = [1100110004 : [1,2,0,0]]
do {
let data = try PropertyListEncoder().encode(d)
// and store `data` in user defaults
} catch { print(error) }
Attempt to set a non-property-list object as an NSUserDefaults
The code you posted tries to save an array of custom objects to NSUserDefaults
. You can't do that. Implementing the NSCoding
methods doesn't help. You can only store things like NSArray
, NSDictionary
, NSString
, NSData
, NSNumber
, and NSDate
in NSUserDefaults
.
You need to convert the object to NSData
(like you have in some of the code) and store that NSData
in NSUserDefaults
. You can even store an NSArray
of NSData
if you need to.
When you read back the array you need to unarchive the NSData
to get back your BC_Person
objects.
Perhaps you want this:
- (void)savePersonArrayData:(BC_Person *)personObject {
[mutableDataArray addObject:personObject];
NSMutableArray *archiveArray = [NSMutableArray arrayWithCapacity:mutableDataArray.count];
for (BC_Person *personObject in mutableDataArray) {
NSData *personEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:personObject];
[archiveArray addObject:personEncodedObject];
}
NSUserDefaults *userData = [NSUserDefaults standardUserDefaults];
[userData setObject:archiveArray forKey:@"personDataArray"];
}
Related Topics
Failed to Obtain a Cell from Its Datasource
Long Press Gesture on Uicollectionviewcell
Uigesturerecognizer and Uitableviewcell Issue
Why Is Main Window of Type Double Optional
Why Are Didbegincontact Called Multiple Times
Expandable Tableview in Iphone
Getting Local Notifications to Show While App Is in Foreground Swift 3
Uitextview That Expands to Text Using Auto Layout
Cannot Change Search Bar Background Color
Uibarbuttonitem in Navigation Bar Programmatically
How to Push and Present to Uiviewcontroller Programmatically Without Segue in iOS Swift 3
Custom Uitableview Section Index
Wkwebview Does Load Resources from Local Document Folder
Unable to Get the Access Token Through [Fbsdkaccesstoken Currentaccesstoken] in iPhone Sdk
iOS 8 Rotation Methods Deprecation - Backwards Compatibility