아카이빙, UserDefaults - 객체 저장방법
30 Mar 2018 | iOS NSCoding NSKeyedArchiver Archive아카이빙: 객체의 아카이빙이란 그 객체의 프로퍼티를 모두 기록하고 파일 시스템에 그 내용을 저장한다는 뜻 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
: 인스턴스 변수를 인코딩/디코딩할때 딕셔너리 타입처럼 변수에 대한 키값을 이름으로 지정해서 인코딩/디코딩할 수 있다.NSKeyedUnarchiver
의func 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