[Ios] محاولة تعيين كائن غير خاصية قائمة كـ NSUserDefaults


Answers

يبدو لي مسرفًا للغاية في تشغيل الصفيف وترميز الكائنات في NSData بنفسك. BC_Person is a non-property-list object أن الإطار لا يعرف كيفية تسلسل كائن الشخص الخاص بك.

لذلك كل ما نحتاجه هو التأكد من أن كائن الشخص الخاص بك يتوافق مع 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")
}

و Voila ، قمت بتخزين مجموعة من الكائنات المخصصة في NSUserDefaults

Question

ظننت أنني أعرف ما الذي تسبب في هذا الخطأ ، لكنني لا أستطيع أن أفهم ما فعلته خطأ.

هذه رسالة الخطأ الكاملة التي أحصل عليها:

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

عند نقطة ما في التطبيق ، يتم تعيين BC_PersonClass في BC_PersonClass ، ولدي فئة DataSave التي أعتقد أنها تتعامل مع ترميز الخصائص في بلدي BC_PersonClass . إليك الشفرة التي DataSave فئة 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];
}

آمل أن يكون هذا رمزًا كافيًا لإعطائك فكرة عما أحاول القيام به. مرة أخرى ، أعرف أن مشكلتي تكمن في كيفية ترميز خصائصي في صف BC_Person الخاص بي ، ولا يمكنني أن أفهم ماذا أفعل الخطأ.

شكرا للمساعدة!




كان عندي هذه المشكلة في محاولة حفظ قاموس إلى NSUserDefaults . اتضح أنه لن يتم الحفظ لأنه يحتوي على قيم NSNull . لذلك أنا فقط نسخ القاموس إلى قاموس قابل للتغيير إزالة NSUserDefaults ثم حفظها إلى NSUserDefaults

NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithDictionary:dictionary_trying_to_save];
[dictionary removeObjectForKey:@"NullKey"];
[[NSUserDefaults standardUserDefaults] setObject:dictionary forKey:@"key"];

في هذه الحالة ، كنت أعرف أي المفاتيح قد تكون قيم NSNull .




سويفت 3 الحل

فئة فائدة بسيطة

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

}

فئة النموذج

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

    }
}

كيف تتصل

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