Property wrapper는 일반적으로 공통되는 부분을 묶고 같은 보일러 플레이트가 작성 될 여지가 있을 때 Property wrapper를 사용하면 좀 더 직관적이고 클린한 코드를 작성할 수 있다.
💫 프로젝트에서 사용할 UserDefault를 PropertyWrapper를 사용해 관리해보자
Before
class Settings {
static let shared = Settings()
private init() {}
var isDarkMode: Bool {
get { UserDefaults.standard.bool(forKey: "isDarkMode") }
set { UserDefaults.standard.set(newValue, forKey: "isDarkMode") }
}
}
isDarkMode라는 프로퍼티는 UserDefault에 저장되어 있는 "isDarkMode" key의 값을 불러온다. 이러한 프로퍼티가 여러개가 필요할 때 같은 코드를 여러번 작성하는 불필요한 작업이 필요하다. 이 때 PropertyWrapper를 사용해 프로퍼티의 get, set 부분을 보일러플레이트로 묶어 쉽게 구현이 가능하다.
After
@propertyWrapper
struct UserDefault<T> {
let key: String
let defaultValue: T
var wrappedValue: T {
get { UserDefaults.standard.object(forKey: key) as? T ?? defaultValue }
set { UserDefaults.standard.set(newValue, forKey: key) }
}
}
@propertyWrapper를 사용하면 쉽게 프로퍼티 래퍼를 구현할 수 있다.
class Settings {
static let shared = Settings()
private init() {}
var isDarkMode: Bool {
get { UserDefaults.standard.bool(forKey: "isDarkMode") }
set { UserDefaults.standard.set(newValue, forKey: "isDarkMode") }
}
// 👇 UserDefault Property Wrapper를 사용
@UserDefault(key: "isSilentMode", defaultValue: false)
var isSilentMode: Bool
}
print("\(Settings.shared.isSilentMode)") // false
Settings.shared.isSilentMode.toggle()
print("\(Settings.shared.isSilentMode)") // true
이제 위에서 만든 UserDefault property wrapper를 적용할 변수의 앞 or 상단에 추가하여 작성하면 해당 프로퍼티에 프로퍼티 래퍼가 적용된다.
+) Apple swift-evolution에서 소개 된 COW PropertyWrapper 예제
protocol Copyable: AnyObject {
func copy() -> Self
}
@propertyWrapper
struct CopyOnWrite<Value: Copyable> {
init(wrappedValue: Value) {
self.wrappedValue = wrappedValue
}
private(set) var wrappedValue: Value
var projectedValue: Value {
mutating get {
if !isKnownUniquelyReferenced(&wrappedValue) {
wrappedValue = wrappedValue.copy()
}
return wrappedValue
}
set {
wrappedValue = newValue
}
}
}
@CopyOnWrite var storage: MyStorageBuffer
// Non-modifying access:
let index = storage.index(of: …)
// For modification, access $storage, which goes through `projectedValue`:
$storage.append(…)
'iOS > Swift' 카테고리의 다른 글
UserDefaults / Keychain / Core Data (0) | 2022.08.17 |
---|---|
Swift에서 DI/DIP 이해하기 (0) | 2022.06.21 |
Swift CommonCrypto로 AES 암/복호화 하기! (without CryptoSwift) (0) | 2022.05.26 |
UserDefaults에서 .value(forKey:)와 .object(forKey:)는 뭐가 다른 건가요? (0) | 2022.05.13 |
논리 게이트를 Swift로 구현해 보자! (0) | 2022.05.13 |