PLUB이라는 앱을 개발하면서 검색Input에 대해 최근검색어리스트가 존재할 경우 화면을 나갔다가 들어가더라도 유지되는 상황을 개발하여야했다
이 상황에서 UserDefaults를 이용해야겠다는 생각이 들었는데 그러면서 PropertyWrapper라는 것을 알게되었다, 이게 무엇일까 ??
var currentPage: Int {
get {
return self._currentPage
}
set {
if self._currentPage == newValue { return }
if newValue >= numberOfPages {
self._currentPage = numberOfPages - 1
}
else if newValue < 0 {
self._currentPage = 0
}
else {
self._currentPage = newValue
}
}
이때 필요한것이 @propertyWrapper이다
static var accessToken: String? {
get { return UserDefaults.standard.string(forKey: "accessToken") }
set { UserDefaults.standard.set(newValue, forKey: "accessToken") }
}
@propertyWrapper
struct UserDefaultsWrapper<T: Codable> {
private let key: String
init(key: String) {
self.key = key
}
var wrappedValue: T? {
get {
guard let data = UserDefaults.standard.object(forKey: self.key) as? Data,
let decodedData = try? JSONDecoder().decode(T.self, from: data) else {
return nil
}
return decodedData
}
set {
guard let data = try? JSONEncoder().encode(newValue)
else {
UserDefaults.standard.removeObject(forKey: key)
return
}
UserDefaults.standard.setValue(data, forKey: key)
}
}
}
@propertyWrapper로 선언해주면 반드시 wrappedValue를 구현해주어야하는데 여기다가 공통으로 작업하고싶은 get set에 대한 로직을 구현해주면 된다
UserDefaultsWrapper라는 말처럼 그대로 특정 역할을 위한 Wrapper를 만드는것이다
@UserDefaultsWrapper<[String]>(key: "accessToken")
private(set) var accessToken
위 코드에서 accessToken을 그대로 사용할 경우 nil이 되는데 디폴트 값이 필요한 경우에 nil은 추가코드를 유발하게 된다
이와 같은 경우는 어떻게 해야할까 ??
@propertyWrapper
struct UserDefaultWrapper<T> {
let key: String
let defaultValue: T
var wrappedValue: T {
get { UserDefaults.standard.object(forKey: self.key) as? T ?? self.defaultValue }
set { UserDefaults.standard.set(newValue, forKey: self.key) }
}
}
@UserDefaultWrapper(key: "accessToken", defaultValue: "")
static var accessToken: String