ice*_*omo 185 encoding objective-c nsuserdefaults ios
我以为我知道是什么导致了这个错误,但我似乎无法弄清楚我做错了什么.
这是我得到的完整错误消息:
Attempt to set a non-property-list object ( "<BC_Person: 0x8f3c140>" ) as an NSUserDefaults value for key personDataArray
我有一个Person我认为符合NSCoding协议的类,我在这个类中有这两个方法:
- (void)encodeWithCoder:(NSCoder *)coder {
[coder encodeObject:self.personsName forKey:@"BCPersonsName"];
[coder encodeObject:self.personsBills forKey:@"BCPersonsBillsArray"];
}
- (id)initWithCoder:(NSCoder *)coder {
self = [super init];
if (self) {
self.personsName = [coder decodeObjectForKey:@"BCPersonsName"];
self.personsBills = [coder decodeObjectForKey:@"BCPersonsBillsArray"];
}
return self;
}
Run Code Online (Sandbox Code Playgroud)
在应用程序的某个时刻,NSString在BC_PersonClass设置中,我有一个DataSave类,我认为正在处理我的属性编码BC_PersonClass.这是我在DataSave课堂上使用的代码:
- (void)savePersonArrayData:(BC_Person *)personObject
{
// NSLog(@"name of the person %@", personObject.personsName);
[mutableDataArray addObject:personObject];
// set the temp array to the mutableData array
tempMuteArray = [NSMutableArray arrayWithArray:mutableDataArray];
// save the person object as nsData
NSData *personEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:personObject];
// first add the person object to the mutable array
[tempMuteArray addObject:personEncodedObject];
// NSLog(@"Objects in the array %lu", (unsigned long)mutableDataArray.count);
// now we set that data array to the mutable array for saving
dataArray = [[NSArray alloc] initWithArray:mutableDataArray];
//dataArray = [NSArray arrayWithArray:mutableDataArray];
// save the object to NS User Defaults
NSUserDefaults *userData = [NSUserDefaults standardUserDefaults];
[userData setObject:dataArray forKey:@"personDataArray"];
[userData synchronize];
}
Run Code Online (Sandbox Code Playgroud)
我希望这是足够的代码,让你知道我想做什么.我再次知道我的问题在于我如何在我的BC_Person类中编码我的属性,我似乎无法弄清楚虽然我做错了.
谢谢您的帮助!
rma*_*ddy 264
您发布的代码尝试将一组自定义对象保存到NSUserDefaults.你不能这样做.实现这些NSCoding方法没有帮助.只能存储之类的东西NSArray,NSDictionary,NSString,NSData,NSNumber,和NSDate在NSUserDefaults.
您需要将对象转换为NSData(就像您在某些代码中所拥有的那样)并将其存储NSData在其中NSUserDefaults.你甚至可以存储NSArray的NSData,如果你需要.
当您回读数组时,您需要取消归档NSData以取回BC_Person对象.
也许你想要这个:
- (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"];
}
Run Code Online (Sandbox Code Playgroud)
Dan*_*sko 66
我自己运行数组并将对象编码为NSData似乎相当浪费.您的错误BC_Person is a non-property-list object告诉您框架不知道如何序列化您的person对象.
因此,所需要的只是确保您的person对象符合NSCoding,然后您只需将自定义对象数组转换为NSData并将其存储为默认值.这是一个操场:
编辑:写入NSUserDefaults在Xcode 7上被破坏,因此操场将存档到数据并返回并打印输出.UserDefaults步骤包括在以后固定的情况下
//: Playground - noun: a place where people can play
import Foundation
class Person: NSObject, NSCoding {
let surname: String
let firstname: String
required init(firstname:String, surname:String) {
self.firstname = firstname
self.surname = surname
super.init()
}
//MARK: - NSCoding -
required init(coder aDecoder: NSCoder) {
surname = aDecoder.decodeObjectForKey("surname") as! String
firstname = aDecoder.decodeObjectForKey("firstname") as! String
}
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(firstname, forKey: "firstname")
aCoder.encodeObject(surname, forKey: "surname")
}
}
//: ### Now lets define a function to convert our array to NSData
func archivePeople(people:[Person]) -> NSData {
let archivedObject = NSKeyedArchiver.archivedDataWithRootObject(people as NSArray)
return archivedObject
}
//: ### Create some people
let people = [Person(firstname: "johnny", surname:"appleseed"),Person(firstname: "peter", surname: "mill")]
//: ### Archive our people to NSData
let peopleData = archivePeople(people)
if let unarchivedPeople = NSKeyedUnarchiver.unarchiveObjectWithData(peopleData) as? [Person] {
for person in unarchivedPeople {
print("\(person.firstname), you have been unarchived")
}
} else {
print("Failed to unarchive people")
}
//: ### Lets try use NSUserDefaults
let UserDefaultsPeopleKey = "peoplekey"
func savePeople(people:[Person]) {
let archivedObject = archivePeople(people)
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(archivedObject, forKey: UserDefaultsPeopleKey)
defaults.synchronize()
}
func retrievePeople() -> [Person]? {
if let unarchivedObject = NSUserDefaults.standardUserDefaults().objectForKey(UserDefaultsPeopleKey) as? NSData {
return NSKeyedUnarchiver.unarchiveObjectWithData(unarchivedObject) as? [Person]
}
return nil
}
if let retrievedPeople = retrievePeople() {
for person in retrievedPeople {
print("\(person.firstname), you have been unarchived")
}
} else {
print("Writing to UserDefaults is still broken in playgrounds")
}
Run Code Online (Sandbox Code Playgroud)
而且,您已将一系列自定义对象存储到NSUserDefaults中
jos*_*405 51
要保存:
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:yourObject];
[currentDefaults setObject:data forKey:@"yourKeyName"];
Run Code Online (Sandbox Code Playgroud)
要得到:
NSData *data = [currentDefaults objectForKey:@"yourKeyName"];
yourObjectType * token = [NSKeyedUnarchiver unarchiveObjectWithData:data];
Run Code Online (Sandbox Code Playgroud)
删除
[currentDefaults removeObjectForKey:@"yourKeyName"];
Run Code Online (Sandbox Code Playgroud)
Saz*_*han 32
class ArchiveUtil {
private static let PeopleKey = "PeopleKey"
private static func archivePeople(people : [Human]) -> NSData {
return NSKeyedArchiver.archivedData(withRootObject: people as NSArray) as NSData
}
static func loadPeople() -> [Human]? {
if let unarchivedObject = UserDefaults.standard.object(forKey: PeopleKey) as? Data {
return NSKeyedUnarchiver.unarchiveObject(with: unarchivedObject as Data) as? [Human]
}
return nil
}
static func savePeople(people : [Human]?) {
let archivedObject = archivePeople(people: people!)
UserDefaults.standard.set(archivedObject, forKey: PeopleKey)
UserDefaults.standard.synchronize()
}
}
Run Code Online (Sandbox Code Playgroud)
class Human: NSObject, NSCoding {
var name:String?
var age:Int?
required init(n:String, a:Int) {
name = n
age = a
}
required init(coder aDecoder: NSCoder) {
name = aDecoder.decodeObject(forKey: "name") as? String
age = aDecoder.decodeInteger(forKey: "age")
}
public func encode(with aCoder: NSCoder) {
aCoder.encode(name, forKey: "name")
aCoder.encode(age, forKey: "age")
}
}
Run Code Online (Sandbox Code Playgroud)
var people = [Human]()
people.append(Human(n: "Sazzad", a: 21))
people.append(Human(n: "Hissain", a: 22))
people.append(Human(n: "Khan", a: 23))
ArchiveUtil.savePeople(people: people)
let others = ArchiveUtil.loadPeople()
for human in others! {
print("name = \(human.name!), age = \(human.age!)")
}
Run Code Online (Sandbox Code Playgroud)
Vis*_*iya 12
试试这段代码
你不能在NSUserDefault中存储mapper,你只能存储NSData,NSString,NSNumber,NSDate,NSArray或NSDictionary.
let myData = NSKeyedArchiver.archivedData(withRootObject: myJson)
UserDefaults.standard.set(myData, forKey: "userJson")
let recovedUserJsonData = UserDefaults.standard.object(forKey: "userJson")
let recovedUserJson = NSKeyedUnarchiver.unarchiveObject(with: recovedUserJsonData)
Run Code Online (Sandbox Code Playgroud)
dim*_*mdy 11
斯威夫特与@propertyWrapper
将Codable对象保存到UserDefault
@propertyWrapper
struct UserDefault<T: Codable> {
let key: String
let defaultValue: T
init(_ key: String, defaultValue: T) {
self.key = key
self.defaultValue = defaultValue
}
var wrappedValue: T {
get {
if let data = UserDefaults.standard.object(forKey: key) as? Data,
let user = try? JSONDecoder().decode(T.self, from: data) {
return user
}
return defaultValue
}
set {
if let encoded = try? JSONEncoder().encode(newValue) {
UserDefaults.standard.set(encoded, forKey: key)
}
}
}
}
enum GlobalSettings {
@UserDefault("user", defaultValue: User(name:"",pass:"")) static var user: User
}
Run Code Online (Sandbox Code Playgroud)
示例用户模型确认可编码
struct User:Codable {
let name:String
let pass:String
}
Run Code Online (Sandbox Code Playgroud)
如何使用它
//Set value
GlobalSettings.user = User(name: "Ahmed", pass: "Ahmed")
//GetValue
print(GlobalSettings.user)
Run Code Online (Sandbox Code Playgroud)
Dan*_*ark 10
首先,rmaddy的答案(上图)是对的:实施NSCoding没有帮助.但是,你需要实现NSCoding使用NSKeyedArchiver和所有这些,所以它只是一步...转换通过NSData.
示例方法
- (NSUserDefaults *) defaults {
return [NSUserDefaults standardUserDefaults];
}
- (void) persistObj:(id)value forKey:(NSString *)key {
[self.defaults setObject:value forKey:key];
[self.defaults synchronize];
}
- (void) persistObjAsData:(id)encodableObject forKey:(NSString *)key {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:encodableObject];
[self persistObj:data forKey:key];
}
- (id) objectFromDataWithKey:(NSString*)key {
NSData *data = [self.defaults objectForKey:key];
return [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
Run Code Online (Sandbox Code Playgroud)
所以,你可以用你的NSCoding对象在一个NSArray或NSDictionary或任何...
我尝试保存字典时遇到了这个问题NSUserDefaults.事实证明它不会保存,因为它包含NSNull值.所以我只是将字典复制到一个可变字典中,删除了空值然后保存到NSUserDefaults
NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithDictionary:dictionary_trying_to_save];
[dictionary removeObjectForKey:@"NullKey"];
[[NSUserDefaults standardUserDefaults] setObject:dictionary forKey:@"key"];
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我知道哪些键可能是NSNull值.
\n\nhttps://developer.apple.com/reference/foundation/userdefaults
\n默认对象必须是属性列表\xe2\x80\x94,即 NSData、NSString、NSNumber、NSDate、NSArray 或 NSDictionary 的实例(或者对于集合,实例的组合)。
\n如果要存储任何其他类型的对象,通常应该将其存档以创建 NSData 的实例。有关更多详细信息,请参阅首选项和设置编程指南。
\n
Swift 5:可以使用Codable协议代替NSKeyedArchiever。
struct User: Codable {
let id: String
let mail: String
let fullName: String
}
Run Code Online (Sandbox Code Playgroud)
在县结构是围绕UserDefaults标准的对象定义包装。
struct Pref {
static let keyUser = "Pref.User"
static var user: User? {
get {
if let data = UserDefaults.standard.object(forKey: keyUser) as? Data {
do {
return try JSONDecoder().decode(User.self, from: data)
} catch {
print("Error while decoding user data")
}
}
return nil
}
set {
if let newValue = newValue {
do {
let data = try JSONEncoder().encode(newValue)
UserDefaults.standard.set(data, forKey: keyUser)
} catch {
print("Error while encoding user data")
}
} else {
UserDefaults.standard.removeObject(forKey: keyUser)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
所以你可以这样使用它:
Pref.user?.name = "John"
if let user = Pref.user {...
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
142944 次 |
| 最近记录: |