IT Share you

userDefaults에서 사용자 지정 개체 저장 및 검색 Swift 3

shareyou 2020. 11. 29. 12:39
반응형

userDefaults에서 사용자 지정 개체 저장 및 검색 Swift 3


Swift 3, Xcode 8.0을 사용하여 Playground에 있습니다.

import Foundation
class Person: NSObject, NSCoding {
    var name: String
    var age: Int
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    required convenience init(coder aDecoder: NSCoder) {
        let name = aDecoder.decodeObject(forKey: "name") as! String
        let age = aDecoder.decodeObject(forKey: "age") as! Int
        self.init(
            name: name,
            age: age
        )
    }
    func encode(with aCoder: NSCoder) {
        aCoder.encode(name, forKey: "name")
        aCoder.encode(age, forKey: "age")
    }
}

Person 배열 생성

let newPerson = Person(name: "Joe", age: 10)
var people = [Person]()
people.append(newPerson)

배열 인코딩

let encodedData = NSKeyedArchiver.archivedData(withRootObject: people)
print("encodedData: \(encodedData))")

userDefaults에 저장

let userDefaults: UserDefaults = UserDefaults.standard()
userDefaults.set(encodedData, forKey: "people")
userDefaults.synchronize()

검사

print("saved object: \(userDefaults.object(forKey: "people"))")

userDefaults에서 검색

if let data = userDefaults.object(forKey: "people") {
    let myPeopleList = NSKeyedUnarchiver.unarchiveObject(with: data as! Data)
    print("myPeopleList: \(myPeopleList)")
}else{
    print("There is an issue")
}

보관 된 데이터 만 확인

if let myPeopleList = NSKeyedUnarchiver.unarchiveObject(with: encodedData){
   print("myPeopleList: \(myPeopleList)")
}else{
   print("There is an issue")
}

userDefaults에 데이터 개체를 올바르게 저장할 수 없으며 하단의 검사에서 "치명적 오류 : 선택 값을 풀 때 예기치 않게 nil을 찾았습니다"라는 오류가 발생합니다. "check"행은 또한 저장된 객체가 nil임을 보여줍니다. 내 개체의 NSCoder에 오류가 있습니까?


스위프트 4 노트

플레이 그라운드에서 값을 다시 저장 / 테스트 할 수 있습니다.


스위프트 3

UserDefaults는 실제 프로젝트에서 테스트해야합니다. 참고 : 강제로 동기화 할 필요가 없습니다. 플레이 그라운드에서 코딩 / 디코딩을 테스트하려면 keyed archiver를 사용하여 문서 디렉토리의 plist 파일에 데이터를 저장할 수 있습니다. 또한 수업에서 몇 가지 문제를 해결해야합니다.

class Person: NSObject, NSCoding {
    let name: String
    let age: Int
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    required init(coder decoder: NSCoder) {
        self.name = decoder.decodeObject(forKey: "name") as? String ?? ""
        self.age = decoder.decodeInteger(forKey: "age")
    }

    func encode(with coder: NSCoder) {
        coder.encode(name, forKey: "name")
        coder.encode(age, forKey: "age")
    }
}

테스트 :

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // setting a value for a key
        let newPerson = Person(name: "Joe", age: 10)
        var people = [Person]()
        people.append(newPerson)
        let encodedData = NSKeyedArchiver.archivedData(withRootObject: people)
        UserDefaults.standard.set(encodedData, forKey: "people")

        // retrieving a value for a key
        if let data = UserDefaults.standard.data(forKey: "people"),
            let myPeopleList = NSKeyedUnarchiver.unarchiveObject(with: data) as? [Person] {
            myPeopleList.forEach({print( $0.name, $0.age)})  // Joe 10
        } else {
            print("There is an issue")
        }
    }
}

let age = aDecoder.decodeObject(forKey: "age") as! Int

이것은 Swift 3에서 변경되었습니다. 더 이상 값 유형에 대해 작동하지 않습니다. 이제 올바른 구문은 다음과 같습니다.

let age = aDecoder.decodeInteger(forKey: "age")

다양한 유형에 대한 관련 decode ... () 함수가 있습니다.

let myBool = aDecoder.decodeBoolean(forKey: "myStoredBool")
let myFloat = aDecoder.decodeFloat(forKey: "myStoredFloat")

편집 : Swift 3에서 가능한 모든 decodeXXX 기능의 전체 목록

편집하다:

Another important note: If you have previously saved data that was encoded with an older version of Swift, those values must be decoded using decodeObject(), however once you re-encode the data using encode(...) it can no longer be decoded with decodeObject() if it's a value type. Therefore Markus Wyss's answer will allow you to handle the case where the data was encoded using either Swift version:

self.age = aDecoder.decodeObject(forKey: "age") as? Int ?? aDecoder.decodeInteger(forKey: "age")

Try this:

self.age = aDecoder.decodeObject(forKey: "age") as? Int ?? aDecoder.decodeInteger(forKey: "age")

In Swift 4:

You can use Codable to save and retrieve custom object from the Userdefaults. If you're doing it frequently then you can add as extension and use it like below.

extension UserDefaults {

   func save<T:Encodable>(customObject object: T, inKey key: String) {
       let encoder = JSONEncoder()
       if let encoded = try? encoder.encode(object) {
           self.set(encoded, forKey: key)
       }
   }

   func retrieve<T:Decodable>(object type:T.Type, fromKey key: String) -> T? {
       if let data = self.data(forKey: key) {
           let decoder = JSONDecoder()
           if let object = try? decoder.decode(type, from: data) {
               return object
           }else {
               print("Couldnt decode object")
               return nil
           }
       }else {
           print("Couldnt find key")
           return nil
       }
   }

}

Your Class must follow Codable. Its just a typealias for both Encodable & Decodable Protocol.

class UpdateProfile: Codable {
  //Your stuffs
}

Usage:

let updateProfile = UpdateProfile()

//To save the object
UserDefaults.standard.save(customObject: updateProfile, inKey: "YourKey")

//To retrieve the saved object
let obj = UserDefaults.standard.retrieve(object: UpdateProfile.self, fromKey: "YourKey")

For more Encoding and Decoding Custom types, Please go through the Apple's documentation.

참고URL : https://stackoverflow.com/questions/37980432/swift-3-saving-and-retrieving-custom-object-from-userdefaults

반응형