NSKeyedArchiver
오브젝트의 데이터를 key로 참조해서 기록하는 encoder다.
NSKeyedUnarchiver
key로 참조해서 오브젝트의 데이터를 복원하는 decoder다.
UserDefaults와 차이점
나는 지금까지 데이터를 저장할 때 UserDefaults를 이용했지만 이 아카이버의 역할은 무엇일까??
NSKeyedArchiver | UserDefaults | |
저장 방식 | Key - Value | |
데이터 타입 매핑 여부 | O | |
상위 하위 관계 매핑 여부 | O | X |
공통점이 많은 인터페이스 가지만 큰 차이점이 존재한다.
바로 상속과 같은 복잡한 데이터의 관계를 같이 저장하는데 차이가 있다.
흠.. 상하 관계가 있다는 것은 상속을 쓴다는 것이고 NSKeyedArchiver는 클래스를 저장할 때 많이 쓰이는군.. 으로 예상된다.
한번 예시 코드와 함께 사용법을 익혀보자.
전제 조건
루트와 하위 모든 클래스 타입에서 NSCoding과 NSObject 을 채택, 상속해야한다.
애플에서 NScoding을 직접 채택하는것보다 NSSecureCoding을 채택하는게 좋다고하니 그 방식으로 진행해보자.
위 두 내용에 대한 포스팅은 아래를 참고하자
1. 클래스 정의
a.encode(with:)
말그대로 어떤 key로 어떤 value로 저장할지 명시한다.
위 사진과 같이 타입별로 정말 많은 api들이 제공된다.
b.init?(coder:)
반대로 key를 통해 저장할 값을 decode하는 과정을 겪는다.
다음 예는 Canvas란 root를 두고 Circle과 Triangle을 갖고 있는 구조이다.
다음 과정을 통해 저장과 복원과정을 살펴보자
import Foundation
final class Triangle : NSObject, NSSecureCoding {
static var supportsSecureCoding: Bool {
return true
}
let width: Double
let height: Double
init(width: Double, height: Double){
self.width = width
self.height = height
print(#file, #function)
}
func encode(with coder: NSCoder) {
// encode(value:, forKey:) value 값을 해당 key로 인코딩
coder.encode(width, forKey: "width")
coder.encode(height, forKey: "height")
print(#file, #function)
}
init?(coder: NSCoder) {
// 디코딩
width = coder.decodeDouble(forKey: "width")
height = coder.decodeDouble(forKey: "height")
print(#file, #function)
}
}
====================================================================================
import Foundation
final class Circle : NSObject, NSSecureCoding {
static var supportsSecureCoding: Bool {
return true
}
let radius : Double
init(radius: Double){
self.radius = radius
print(#file, #function)
}
func encode(with coder: NSCoder) {
// encode(value:, forKey:) value 값을 해당 key로 인코딩
coder.encode(radius, forKey: "radius")
print(#file, #function)
}
init?(coder: NSCoder) {
// 디코딩
radius = coder.decodeDouble(forKey: "radius")
print(#file, #function)
}
}
====================================================================================
import Foundation
final class Canvas: NSObject, NSSecureCoding {
static var supportsSecureCoding: Bool {
return true
}
let circle: Circle
let triangle: Triangle
init(circle: Circle, triangle: Triangle, owner: String) {
self.circle = circle
self.triangle = triangle
print(#file, #function)
}
required init?(coder: NSCoder) {
print(#file, #function)
guard let circle = coder.decodeObject(of: Circle.self, forKey: "circle"),
let triangle = coder.decodeObject(of: Triangle.self, forKey: "triangle")
else { assert(false) }
self.circle = circle
self.triangle = triangle
}
func encode(with coder: NSCoder) {
print(#file, #function)
coder.encode(circle, forKey: "circle")
coder.encode(triangle, forKey: "triangle")
}
}
2. archiver and unarchiver interface 이용
func archvie(rootObject: Canvas) -> Data {
do {
let data = try NSKeyedArchiver.archivedData(withRootObject: rootObject, requiringSecureCoding: true)
return data
} catch {
fatalError("Encoing Error")
}
}
func unArchive(data: Data) -> Canvas {
do {
let unArchiver = try NSKeyedUnarchiver(forReadingFrom: data)
unArchiver.requiresSecureCoding = true
guard let object = unArchiver.decodeObject(of: Canvas.self , forKey: NSKeyedArchiveRootObjectKey) else { fatalError("Decode Error")}
return object
} catch {
fatalError("Decoding Eror")
}
}
결과
let data = archvie(rootObject: canvas)
let object = unArchive(data: data)
print("Data: \(data)")
print("object: \(object)")
참고
'iOS > UIKit' 카테고리의 다른 글
UIEditMenuInteraction (3) | 2024.10.12 |
---|---|
UISearchController (1) | 2024.10.06 |
NSCoding , NSSecureCoding (0) | 2024.09.10 |
NSObject (1) | 2024.09.10 |
UIGraphics (0) | 2024.09.06 |