Runtime환경에 동작하면서 앱이 실행되는 동안 기본 저장소에 접근해 데이터를 기록하고 가져오는 역할을 하는 인터페이스
"키 - 밸류" 쌍으로 존재하며 앱 전체에 단 하나의 인스턴스만 존재하게됨
스위프트에서 제공되는 double, int, float, boolean와 NSdata, NSString, NSNumber, NSDictionary, NSArrary등 NS관련타입도 저장이 가능하다.
저장:
userDefaults.set(value: Any?, forKey: String)
value: Any? 에는 data를 넣어주고 forKey: String에는 data의 구분이되는 값을 넣어준다.
ex)
func saveTasks(){
let data = self.tasks.map{
[
"title": $0.title,
"done": $0.done
]
}
let userDefaults = UserDefaults.standard
userDefaults.set(data, forKey: "tasks")
}
함수를 정의하고 프로퍼티가 종료되기 직전에 호출되는 didSet 메서드에서 호출해준다.
로드:
userDefaults.standard.object(forKey: String)
String엔 저장했던 key를 넣어준다.
object메서드는 Any타입으로 리턴하기 때문에 저장할때의 타입으로 타입캐스팅을 해주어야한다. 또한 Any?타입은 nil이 리턴될 수 있기 때문에 옵셔널 바인딩을 해줘야한다.
ex)
func loadTasks(){
let userDefaults = UserDefaults.standard
guard let data = userDefaults.object(forKey: "tasks") as? [[String: Any]] else { return }
self.tasks = data.compactMap{
guard let title = $0["title"] as? String else{ return nil}
guard let done = $0["done"] as? Bool else { return nil }
return Task(title: title, done: done)
}
}
실행되기 전 데이터들을 불러와야하기 때문에 오버라이드된 viewDidLoad 메서드에서 호출해준다.
UserDefault는 우리가 임의대로 만들어 놓은 구조체를 이해하지 못한다.
구조체를 UserDefault로 저장하게 되면 프로퍼티 리스트형태로 저장되게 된다.
이는 데이터를 가져올 때 Decoding을 해줘야한다.
UserDefault는 우리가 임의대로 만들어 놓은 구조체를 이해하지 못한다. 따라서 JSON데이터처럼 Encoding, Decoding 해야한다.
guard let data = UserDefaults.standard.value(forKey: "alert") as? Data,
let alerts = try? PropertyListDecoder().decode([Alert].self, from: data) else { return [] }
UserDefaults의 standard(기본저장소).value(forKey: "alert")는 위에서 나온것과 동일.
Data 형식으로 다운캐스팅을 해주고 PropertyListDecoder()로 decode를 해준다. 형식은 Alert구조체 배열의 자기 자신이고 from은 옵셔널 바인딩 해준 data에서 Alert구조체배열로 가져온다는 뜻.
실패하면 return 한다.
UserDefault(내부저장소)는 우리가 임의로 만든 커스텀한 구조체를 이해하지 못한다.
불리언, Int, String들처럼 가장 기초적인 형만을 이해하고, 커스텀한 객체들은 넣고 뺄 때 인코딩 디코딩을 해주어야함.