공부 연습장 :-)

아카이빙, UserDefaults - 객체 저장방법

|

아카이빙: 객체의 아카이빙이란 그 객체의 프로퍼티를 모두 기록하고 파일 시스템에 그 내용을 저장한다는 뜻 https://medium.com/@felicity.johnson.mail/core-data-vs-nskeyedarchiver-vs-user-defaults-e660d541bb6e

아카이브 - NSCoding

  • 객체 아카이브는 객체 그래프를 따라 객체의 데이터 내용을 저장하는 방식이다.
  • 가변객체나 다중참조 관계를 원래대로 복원해야하는 경우 NSCoding프로토콜을 사용한다.
  • NSCoding프로토콜은 객체 인스턴스를 인코딩하거나 다시 객체로 디코딩하기위한 두개의 메서드만 있음
  • func encode(with aCoder: NSCoder)
  • required init?(coder aDecoder: NSCoder)
  • NSCoder클래스: 메모리상에 있는 객체 인스턴스 변수를 다른 형태로 변환하기위한 추상클래스
    • 실제로 NSKeyedArchiver,NSKeyedUnarchiver, NSPortCoder와 같은 하위 클래스 구현체를 사용함
  • NSKeyedArchiver,NSKeyedUnarchiver: 인스턴스 변수를 인코딩/디코딩할때 딕셔너리 타입처럼 변수에 대한 키값을 이름으로 지정해서 인코딩/디코딩할 수 있다.
  • NSKeyedUnarchiverfunc containsValue(forKey key: String) -> Bool로 해당 키의 반환값에 대한 데이터가 존재하는지 알 수 있음
class DataStorage<T> {

    class func load() -> T? {
        // 존재확인
        if UserDefaults.standard.object(forKey: String(describing: T.self)) != nil {
            // key값으로 데이터 가져옴
            guard let encodedData = UserDefaults.standard.data(forKey: String(describing: T.self)) else { return nil }
            guard let archivedMachine = NSKeyedUnarchiver.unarchiveObject(with: encodedData) as? FavoriteList else { return nil }
            return archivedMachine as? T
        }
        return nil
    }

    class func save(data: T) {
        UserDefaults.standard.set(NSKeyedArchiver.archivedData(withRootObject: data), forKey: String(describing: T.self))
    }
}

아카이빙

  • iOS앱은 기본적으로 사용자에게 데이터를 조작할 인터페이스를 제공한다.
    • 모델 객체: 사용자가 조작하는 데이터를 보관하는 역할 (저장과 로딩)
    • 뷰 객체: 단순히 그 데이터 반영
    • 컨트롤러 객체: 뷰와 모델 객체의 동기화 책임
  • 아카이빙은 iOS에서 모델 객체를 저장하는 가장 흔한 방법 중 하나임
  • 아카이빙: 객체의 아카이빙이란 그 객체의 프로퍼티를 모두 기록하고 파일 시스템에 그 내용을 저장한다는 뜻
  • 언아카이빙: 아카이브한 데이터로부터 객체를 다시 만든다.

  • (참고)
    • 스토리보드같은 인터페이스 파일에 객체를 추가할때 객체들은 아카이빙 된다.
    • 실행 중에 객체들은 인터페이스 파일에서 언아카이빙되어 메모리에 로드된다.
    • UIView와 UIVIewController들은 모두 NSCoding 프로토콜을 따른다.

NSCoding

  • 아카이빙/언아카이빙 할 클래스들은 반드시 NSCoding프로토콜을 따라야한다.
  • 어떤 객체의 속성이 또 다른 객체, 그 객체의 속성은 또 다른 객체...처럼 수직관계를 형성하는 구조라면 NSCoding이 저장 할 수 있는 스위프트기본 value type 단계까지 NSCoding프로토콜 구현을 해줘야한다.
  • 만약 아카이빙 할 필요는 없지만 수직구조 내에 위치해서 프로토콜 구현이 필요한 일부 속성(객체)은 NSCoding프로토콜을 준수하지만 메소드 선언만 해놓고 구현하지 않아도 된다.
class Robot: NSCoding {
 var name : String = ""
 var nemesis : Robot
 var model : Int

 func encode(with aCoder: NSCoder) {
   aCoder.encode(name, forKey: "name")
   aCoder.encode(nemesis, forKey: "nemesis")
   aCoder.encode(model, forKey: "model")
 }
 // 메시지를 받으면 인자로 전달된 NSCoder객체 안의 모든 프로퍼티들을 인코딩한다. 데이터 스트림은 키-값 쌍으로 구성되어 파일시스템에 저장된다.

 required init?(coder aDecoder: NSCoder) {
   name = aDecoder.decodeObject(forKey: "name") as! String
   nemesis = aDecoder.decodeObject(forKey: "nemesis") as! Robot?
   model = aDecoder.decodeInteger(forKey: model")
 }
}
  • aCoder.encode(저장할 객체속성, forKey: "인코딩 프로퍼티를 식별할 키값이 될 문자열")
  • 아카이브에서 언아카이브되면서 로드되는 객체들은 init(coder:)메서드가 실행된다. 이 메서드는 encode(with:)에서 인코딩된 모든 객체를 꺼내와 해당 프로퍼티를 할당해야한다.

UserDefaults

  • key-value 쌍으로 디바이스에 데이터를 저장하는 기능을 제공하는 인터페이스
  • 주로 앱의 설정값을 저장하고 나중에 읽기위한 용도로 사용됨
  • 스위프트에서 제공하는 기본 데이터 타입이면 별도의 작업 없이 저장
    • float, double, integer 및 boolean과 같은 공통 유형에 액세스하기위한 메소드를 제공할 뿐만아니라,
    • NSData, NSString, NSNumber, NSDate, NSArray 또는 NSDictionary 유형의 객체를 저장할 수도 있음!
    • (다른 객체 유형의 경우 NSKeyedArchiver를 사용하여 데이터를 저장하고 검색해야함)

확장과 함께 사용하는 법

  • UserDefaults는 저장한 value에 String타입 key로 접근해야하는 방식이기때문에, 오타가 나거나 하면 객체를 불러오지 못해 런타임에 에러가 발생할 수 있다. enum을 사용해서 실수를 줄이는 방법이 있겠지만 extension을 사용해서 좀 더 스위프트답게 사용하는 방법이 있다. (나중에 써봐야지..ㅋㅋㅋ)
  • 참고링크 - extension구현해서 UserDefaults사용하기

참고자료

Comments