반응형

Combine과 Property Wrapper를 이용해서 UserDefault를 쉽게 사용하기

UserDefault<Value>를 Property Wrapper로 선언하기 

import Combine

protocol AnyOptional {
    var isNil: Bool { get }
}
extension Optional: AnyOptional {
    public var isNil: Bool { self == nil }
}

/**
 UserDefault 간편사용
 
 ```
 // How to use
 UserDefaults.server = 2
 
 var subscribers = Set<AnyCancellable>()
 UserDefaults.$server.sink { server in
 print("New server: \(server)")
 }.store(in: &subscribers)
 ```
 */
@propertyWrapper
struct UserDefault<Value> {
    let key: String
    let defaultValue: Value
    var container = UserDefaults(suiteName: "group.com.bitmusa") ?? UserDefaults.standard
    private let publisher = PassthroughSubject<Value, Never>()
    
    var wrappedValue: Value {
        get {
            return container.object(forKey: key) as? Value ?? defaultValue
        }
        set {
            if let optional = newValue as? AnyOptional, optional.isNil {
                container.removeObject(forKey: key)
            } else {
                container.set(newValue, forKey: key)
                container.synchronize()
            }
            publisher.send(newValue)
        }
    }
    
    var projectedValue: AnyPublisher<Value, Never> {
        return publisher.eraseToAnyPublisher()
    }
}

extension UserDefault where Value: ExpressibleByNilLiteral {
    init(key: String, _ container: UserDefaults = .standard) {
        self.init(key: key, defaultValue: nil, container: container)
    }
}

 

UserDefault에 저장할 값을 변수로 선언해서 사용하기

// MARK: - UserDefaults
extension UserDefaults {
    /// 인증 토큰
    @UserDefault(key: "authToken")
    static var authToken: String?
}
    
// How to use
UserDefaults.authToken = "12345"
print(UserDefaults.authToken)
반응형
Posted by 까칠코더
,