programing

비속성 목록 개체를 NSUserDefaults로 설정하려고 합니다.

closeapi 2023. 5. 26. 20:58
반응형

비속성 목록 개체를 NSUserDefaults로 설정하려고 합니다.

저는 무엇이 이 오류를 유발하는지 알고 있다고 생각했지만, 제가 무엇을 잘못했는지 알 수가 없습니다.

다음은 전체 오류 메시지입니다.

비속성 목록 개체 설정 시도("<BC_인물: 0x8f3c140>") 주요 사용자 DataArray에 대한 NSUserDefaults 값으로 지정

나는 있습니다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;
}

앱의어시서에점느,서▁the▁at,에점▁app시,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];
}

이 코드가 제가 하려는 일에 대한 아이디어를 당신에게 줄 수 있는 충분한 코드이기를 바랍니다.BC_Person 클래스에서 속성을 인코딩하는 방법에 문제가 있다는 것을 다시 한 번 알고 있습니다. 제가 무엇을 잘못하고 있는지 알 수가 없습니다.

도와주셔서 감사합니다!

을 시한코사지개정체배합저니다고려에 .NSUserDefaults당신은 그 일을 하실 수 없어요.» NSCoding방법은 도움이 되지 않습니다.할 수 있는 은 저수있다장니항할습목만같은다와 같은 것들뿐입니다.NSArray,NSDictionary,NSString,NSData,NSNumber,그리고.NSDateNSUserDefaults.

를 개를다로변합야니다환으로 .NSData처럼) NSDataNSUserDefaults여러분은 저할수있다니를 .NSArrayNSData필요하다면,

어레이를 다시 읽을 때는 아카이브를 해제해야 합니다.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"];
}

어레이를 실행하고 개체를 직접 NSData로 인코딩하는 것은 다소 낭비적인 것 같습니다.의 오류 ㅠㅠㅠㅠㅠㅠBC_Person is a non-property-list object프레임워크가 사용자 객체를 직렬화하는 방법을 모른다는 것입니다.

따라서 필요한 것은 사용자 개체가 NS 코딩을 준수하는지 확인한 후 사용자 정의 개체 배열을 NSData로 변환하여 기본값으로 저장하는 것입니다.여기 놀이터가 있습니다.

편집: 쓰기 대상NSUserDefaultsXcode 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에 저장했습니다.

저장 방법:

NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:yourObject];
[currentDefaults setObject:data forKey:@"yourKeyName"];

받는 사람:

NSData *data = [currentDefaults objectForKey:@"yourKeyName"];
yourObjectType * token = [NSKeyedUnarchiver unarchiveObjectWithData:data];

제거용

[currentDefaults removeObjectForKey:@"yourKeyName"];

스위프트 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!)")
}

Swift- 4 Xcode 9.1

이 코드를 사용해 보세요.

NSUserDefault에는 매퍼를 저장할 수 없습니다. NSData, NSString, NSNumber, NSDate, NSRray 또는 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)

신속한 처리@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
}

예제 사용자 모델 코드화 가능 확인

struct User:Codable {
    let name:String
    let pass:String
}

사용방법

//Set value 
 GlobalSettings.user = User(name: "Ahmed", pass: "Ahmed")

//GetValue
print(GlobalSettings.user)

먼저, 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];
}

그래서 당신은 그것을 포장할 수 있습니다.NSCoding안에 있는 물건들NSArray또는NSDictionary아니면 뭐든...

사전을 저장하는 동안 문제가 발생했습니다.NSUserDefaults그게 저장되지 않은 이유는NSNull가치.그래서 저는 단지 사전을 가변 사전으로 복사했습니다. null을 제거하고 저장했습니다.NSUserDefaults

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

이 경우, 저는 어떤 키가NSNull가치.

Swift 5: NSKeyed Archiever 대신 Codable 프로토콜을 사용할 수 있습니다.

struct User: Codable {
    let id: String
    let mail: String
    let fullName: String
}

Prefstruct는 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)
            }
        }
    }
}

따라서 다음과 같은 방법으로 사용할 수 있습니다.

Pref.user?.name = "John"

if let user = Pref.user {...

https://developer.apple.com/reference/foundation/userdefaults

기본 개체는 속성 목록, 즉 NSData, NSString, NSNumber, NSDate, NSRray 또는 NSDictionary의 인스턴스(또는 인스턴스 조합)여야 합니다.

다른 유형의 개체를 저장하려면 일반적으로 이 개체를 아카이브하여 NSData 인스턴스를 만들어야 합니다.자세한 내용은 환경설정 및 설정 프로그래밍 안내서를 참조하십시오.

스위프트 5 아주 쉬운 방법

//MARK:- First you need to encoded your arr or what ever object you want to save in UserDefaults
//in my case i want to save Picture (NMutableArray) in the User Defaults in
//in this array some objects are UIImage & Strings

//first i have to encoded the NMutableArray 
let encodedData = NSKeyedArchiver.archivedData(withRootObject: yourArrayName)
//MARK:- Array save in UserDefaults
defaults.set(encodedData, forKey: "YourKeyName")

//MARK:- When you want to retreive data from UserDefaults
let decoded  = defaults.object(forKey: "YourKeyName") as! Data
yourArrayName = NSKeyedUnarchiver.unarchiveObject(with: decoded) as! NSMutableArray

//MARK: Enjoy this arrry "yourArrayName"

저는 이것과 마주쳤고 결국 그것이 제가 사용하려고 했기 때문이라는 것을 알았습니다.NSNumber사전 키로, 속성 목록은 문자열만 키로 허용합니다.의 설명서에서는 이 제한에 대해 언급하지 않았지만 링크되는 속성 목록 페이지에서는 다음 작업을 수행합니다.

관례에 따라 표 2-1에 나열된 각 Cocoa and Core Foundation 개체는 속성 목록 개체라고 합니다.개념적으로, "속성 목록"은 이러한 모든 클래스의 추상적인 슈퍼 클래스라고 생각할 수 있습니다.어떤 메소드 또는 함수로부터 속성 목록 개체를 수신하는 경우에는 해당 개체가 이러한 유형 중 하나의 인스턴스여야 한다는 것을 알고 있지만 어떤 유형인지 알 수 없는 선험적인 경우도 있습니다.속성 목록 개체가 컨테이너(즉, 배열 또는 사전)인 경우 해당 개체에 포함된 모든 개체도 속성 목록 개체여야 합니다.어레이 또는 사전에 속성 목록 개체가 아닌 개체가 포함된 경우 다양한 속성 목록 메서드 및 함수를 사용하여 데이터 계층을 저장 및 복원할 수 없습니다.NSDictionary 및 CFDictionary 개체는 키를 모든 유형의 개체로 만들 수 있지만 키가 문자열 개체가 아닌 경우 컬렉션이 속성 목록 개체가 아닙니다.

(광산 강조)

언급URL : https://stackoverflow.com/questions/19720611/attempt-to-set-a-non-property-list-object-as-an-nsuserdefaults

반응형