μ§λ ν¬μ€ν μμ UserDefaults, Onboarding νμ΄μ§μ λν΄μ μμ±νμκ³ , Onboarding νμ΄μ§λ₯Ό ꡬννκΈ° μν΄ UserDefaults λ₯Ό μ΄μ©νμμ΅λλ€. μ€ν°λνμλ λΆ μ€μμ Property Wrapper λ₯Ό μ΄μ©νλ©΄ ν¨μ¨μ μΌλ‘ μ¬μ©ν μ μλ€κ³ ν΄μ 곡λΆλ₯Ό νμ΅λλ€. βοΈ κ°μ¬ν©λλ€!
π‘ Property Wrapper λ?
Property Wrapper λ Property μ λν΄ νΉμ ν κΈ°λ₯μ μ μν μ μλ κΈ°λ₯μ λλ€. Swift5.1 μμ μΆκ°λ κΈ°λ₯μ΄λΌκ³ ν©λλ€.
Property wrapper λ Property κ° μ μ₯λλ λ°©μμ κ΄λ¦¬νλ μ½λμ Property λ₯Ό μ μνλ μ½λ μ¬μ΄μ λΆλ¦¬ κ³μΈ΅μ μΆκ°ν΄μ€λλ€. μ λ Property κ° μ μλκ³ , μ μ₯λκΈ° μ μ Wrapper λ₯Ό κ±°μ³κ°λ κ²μ΄λΌκ³ μ΄ν΄νμ΅λλ€.
κΈ°μ‘΄μλ Thread-safety check λ₯Ό μ 곡νκ±°λ, DBμ μ μ₯νλ property κ° μ¬λ¬κ° νμν κ²½μ°, κ°κ°μ property λ§λ€ μμ±ν΄μΌ νμ§λ§, Property wrapper λ₯Ό μ΄μ©νλ©΄ ν λ²λ§ μμ±ν μ μμ΅λλ€.
DB μ μ μ₯νλ λ±μ management code λ₯Ό Property wrapper λ₯Ό μ μνλ λΆλΆμμ νλ²λ§ μμ±νλ©΄ λ©λλ€. μ΄νμ μ¬λ¬ property μμ Property wrapper λ₯Ό λͺ μν΄ μ¬μ¬μ©νλ κ²μ λλ€!
βοΈ Property Wrapper μ¬μ©νκΈ°
Property wrapperλ₯Ό μ μνκΈ° μν΄μλ
- structure, enumeration νΉμ class λ₯Ό μ μνκ³ @propertyWrapper λ₯Ό λͺ μν΄μ€λλ€.
- μ€μ μ μ₯λλ κ°μ wrappedValue μμ±μΌλ‘ μ μν©λλ€. * νμλ‘ κ΅¬νν΄μΌν©λλ€.
Property wrapper μ ννλ computed property μ getter, setter λ₯Ό μ€μ νλ λͺ¨μ΅κ³Ό κ°μ΅λλ€. setter μμ μλ‘κ² λ€μ΄μ€λ κ°μ newValue λΌκ³ ν©λλ€. Property warpper λ λ°λ³΅λλ computed property λ₯Ό νλμ struct λ‘ μ μνλ μν μ νλ€κ³ μκ°ν μ μμ΅λλ€.
μλ μμ μμ TwelveOrLess ꡬ쑰체λ number κ° νμ 12λ³΄λ€ μκ±°λ κ°μμ 보μ₯ν©λλ€. wrappedValue λ₯Ό μ΄ν΄λ³΄λ©΄, setter μμ 12λ³΄λ€ ν° μλ 12κ° λμ λλλ‘ κ΅¬νλμ΄μκΈ° λλ¬Έμ λλ€.
@propertyWrapper
struct TwelveOrLess {
private var number: Int
init() { self.number = 0 }
var wrappedValue: Int {
get { return number }
set { number = min(newValue, 12) }
}
}
μμ ꡬ쑰체λ₯Ό μ΄μ©ν μμ λ μλ μ½λμ λλ€. SmallRectangle ꡬ쑰체μ height, width μμ±μ΄ μκ³ , @TwelveOrLess (wrapper) λ₯Ό μμ±ν΄μ€μΌλ‘ Property wrapper λ₯Ό μ μ©ν μ μμ΅λλ€.
struct SmallRectangle {
@TwelveOrLess var height: Int
@TwelveOrLess var width: Int
}
var rectangle = SmallRectangle()
print(rectangle.height)
// Prints "0"
rectangle.height = 10
print(rectangle.height)
// Prints "10"
rectangle.height = 24
print(rectangle.height)
// Prints "12"
βοΈ UserDefaults μ½λμ Property Wrapper λ₯Ό μ μ©νκΈ°
μ‘°μΈμ λ£κ³ νλ‘μ νΈμ μ½λλ₯Ό 보λ, UserDefaults κ΄λ ¨ μ½λλ€μ΄ key κ°λ§ λ€λ₯΄κ³ μ λΆ κ°μ μ½λλ₯Ό λ°λ³΅ν΄ μμ±νκ³ μμμ΅λλ€. Propery Wrapper λ₯Ό μ΄μ©ν΄ λ°λ³΅λλ μ½λλ₯Ό μ€μ¬λ³΄λλ‘ νκ² μ΅λλ€.
- @propertyWrapper λ₯Ό λͺ μν ꡬ쑰체 UserDefault λ₯Ό μ μν΄μ€λλ€.
- ꡬ쑰체μ property λ₯Ό μ μν©λλ€.
- property μ μ΄κΈ°νλ₯Ό μν΄ init ν¨μλ₯Ό μ μν©λλ€.
- wrappedValue λ₯Ό μ μν©λλ€. * νμ ꡬν property μ λλ€.
wrappedValue μ getter λ UserDefaults λ₯Ό ν΅ν΄ object λ₯Ό κ°μ Έμ λ°ννκ³ , setter λ UserDefaults λ₯Ό ν΅ν΄ κ°μ μ μ₯ν©λλ€.
μ°Έκ³ λ‘, μ¬κΈ°μ <T> λ νμ μΈμ(Type Parameters)λ‘ ν¨μμ μΈμλ λ°ν νμ μΌλ‘ μ¬μ©ν μ μμ΅λλ€. νμ μΈμλ ν¨μκ° νΈμΆλ λ μ€μ νμ μΌλ‘ λ체λλλ‘ νμλ©λλ€.
@propertyWrapper
struct UserDefault<T> {
private let key: String
private let defaultValue: T
init(key: String, defaultValue: T) {
self.key = key
self.defaultValue = defaultValue
}
var wrappedValue: T {
get {
// Read value from UserDefaults
return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
}
set {
// Set value to UserDefaults
UserDefaults.standard.set(newValue, forKey: key)
}
}
}
μ μν UserDefault ꡬ쑰체λ₯Ό μ΄μ©νκΈ° μν μ½λμ λλ€. User ꡬ쑰체μμλ @UserDefault wrapperκ° λͺ μλ isApplicationLaunch property λ₯Ό κ°μ΅λλ€. property μ μ μμ ν¨κ» wrapper μ΄κΈ°νλ μ§ννμ΅λλ€. μ±μ΄ μ²μ μ€νλλ κ²½μ°μ μ μλ κ²μ΄λ―λ‘ μ΄κΈ°κ°μ true λ‘ μ€μ μ ν΄μ€¬μ΅λλ€.
key κ°μ μ§μ νκΈ° μν΄μ κΈ°μ‘΄μλ "~~" ννλ‘ λ°λ‘ μμ±νλλ°, μ€ν°λμμ μ°Έκ³ λ‘ λ³΄λ΄μ£Όμ μ½λμ enum μ΄ μκΈΈλ μ΄μ©μ ν΄λ΄€μ΅λλ€. ν΄λΉ μ½λμμλ constant string μ νννκΈ° μν΄ μ¬μ©λ κ² κ°μ΅λλ€.
struct User {
@UserDefault(key: keyEnum.isAppFirstLaunch.rawValue, defaultValue: true)
static var isAppFirstLaunch: Bool
}
enum keyEnum: String {
case isAppFirstLaunch = "isAppFirstLaunch"
}
μ¨λ³΄λ© νμ΄μ§ μμ μ SceneDelegate extension μ½λμμ μλ ν¨μλ§ μμ ν΄μ£Όμμ΅λλ€. if ꡬ문과 property κ°μ μ€μ νλ λΆλΆμ μ½λκ° λ¬λΌμ‘μ΅λλ€ π κΈ°μ‘΄κ³Ό λμΌνκ² μλνλ κ²μ νμΈνμ΅λλ€.
λ¨μν property μ κ°μ λμ νλ μ½λλ§μΌλ‘ DB μ κ°μ μ μ₯ν μ μκ² λμλ€μ. DB μμ κ°μ κ°μ Έμ€λ κ²μ λμ± κ°λ¨ν΄μ‘κ³ μ.
extension SceneDelegate {
private func setRootViewController(_ scene: UIScene){
if User.isAppFirstLaunch {
User.isAppFirstLaunch = false
setRootViewController(scene, name: "Onboarding",
identifier: "OnboardingViewController")
} else {
setRootViewController(scene, name: "Main",
identifier: "TodoViewController")
}
}
// ...
}
μ κ° μμ±νλ μμ λ UserDefaults μ νλμ κ°λ§ μ μ₯νκ³ μμ§λ§, λ λ§μ κ°μ μ μ₯νλ€λ©΄ μ μ©ν κ±°λΌκ³ μμλ©λλ€. π
μ°Έκ³ λ¬Έμ λ° λ§ν¬
- Swift 곡μ κ°μ΄λ - Property Wrapper (μμ΄)
- Swift 곡μ κ°μ΄λμ λ²μ ν¬μ€ν
- Property Wrapper μ¬μ©λ²μ΄ μμΈν ν¬μ€ν
κ΄λ ¨λ λ΄μ©