[iOS] Project - BuyOrNot

[iOS] propertyWrapper를 활용한 UserDefaults 캡슐화

ungQ 2024. 4. 28. 23:39

프로젝트를 진행하다보니, UserDefaults 값을 이곳 저곳 쓸일이 많았고 반복되는 코드들에 불편함을 느껴
@propertyWrapper 속성을 사용하여 코드의 간결함, 유지보수에 보탬이 되도록 개선해보려 합니다.

기존 방식

enum UserDefaultsKey: String {
    case userId
    case email
    case password
    case accessToken
    case refreshToken
    case nick
    case profileImage
    case autoLogin


    var key: String {
        return self.rawValue
    }
}

UserDefaults.standard.set("user@example.com", forKey: UserDefaultsKey.email.key)

let email = UserDefaults.standard.string(forKey: UserDefaultsKey.email.key) ?? "error"
  • 위와 같이 UserDefaults를 사용할 때마다 .standard .set .string 등의 코드가 추가적으로 필요합니다.
  • @propertyWrapper 속성으로 UserDefaults 값들을 더 깔끔하고 간결하게 캡슐화하는 방법으로 개선해보았습니다.
@propertyWrapper
struct MyDefaults<T> {
    let key: String
    let defaultValue: T

    var wrappedValue: T {
        get {
            UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
        }
        set {
            UserDefaults.standard.setValue(newValue, forKey: key)
        }
    }
}

@propertyWrapper 속성을 적용한 MyDefaults 구조체 생성

  • get : UserDefaults.standard.object(forKey:)
  • set : UserDefaults.standard.set(newValue, forKey:)
enum UserDefaultsManager {

    enum Key: String {
        case userId
        case email
        case password
        case accessToken
        case refreshToken
        case nick
        case profileImage
        case autoLoginEnabled
    }

    @MyDefaults(key: Key.userId.rawValue, defaultValue: "")
    static var userId: String

    @MyDefaults(key: Key.email.rawValue, defaultValue: "이메일 없음")
    static var email: String

    @MyDefaults(key: Key.password.rawValue, defaultValue: "")
    static var password: String

    @MyDefaults(key: Key.accessToken.rawValue, defaultValue: "")
    static var accessToken: String

    @MyDefaults(key: Key.refreshToken.rawValue, defaultValue: "")
    static var refreshToken: String

    @MyDefaults(key: Key.nick.rawValue, defaultValue: "닉네임 없음")
    static var nick: String

    @MyDefaults(key: Key.profileImage.rawValue, defaultValue: "")
    static var profileImage: String

    @MyDefaults(key: Key.autoLoginEnabled.rawValue, defaultValue: false)
    static var autoLoginEnabled: Bool

}

UserDefaultsManager 정의

  • @Mydefaults propertyWrapper를 사용하여, 키와 값을 관리하는 UserDefaultsManager를 정의합니다.

개선된 코드 (주석: 기존 코드)

    let myId = UserDefaultsManager.userId
// UserDefaults.standard.string(forKey: UserDefaultsKey.userId.key) ?? ""
    HTTPHeader.authorization.rawValue: UserDefaultsManager.accessToken,
// UserDefaults.standard.string(forKey: UserDefaultsKey.accessToken.key) ?? "",
    HTTPHeader.refresh.rawValue: UserDefaultsManager.refreshToken
// UserDefaults.standard.string(forKey: UserDefaultsKey.refreshToken.key) ?? ""
    static let imageDownloadRequest = AnyModifier { request in
        var requestBody = request
        requestBody.setValue(UserDefaultsManager.accessToken,
//            UserDefaults.standard.string(forKey: UserDefaultsKey.accessToken.key) ?? "",
                             forHTTPHeaderField: HTTPHeader.authorization.rawValue)
        requestBody.setValue(APIKey.sesacKey.rawValue, forHTTPHeaderField: HTTPHeader.sesacKey.rawValue)

        return requestBody
    }
    UserDefaultsManager.accessToken = accessTokenModel.accessToken
//    UserDefaults.standard.set(accessTokenModel.accessToken, forKey: UserDefaultsKey.accessToken.key)
                UserDefaultsManager.nick = loginModel.nick
                UserDefaultsManager.userId = loginModel.user_id
                UserDefaultsManager.accessToken = loginModel.accessToken
                UserDefaultsManager.refreshToken = loginModel.refreshToken
//                UserDefaults.standard.set(loginModel.nick, forKey: UserDefaultsKey.nick.key)
//                UserDefaults.standard.set(loginModel.user_id, forKey: UserDefaultsKey.userId.key)
//                UserDefaults.standard.set(loginModel.accessToken, forKey: UserDefaultsKey.accessToken.key)
//                UserDefaults.standard.set(loginModel.refreshToken, forKey: UserDefaultsKey.refreshToken.key)

결론

  • UserDefaults를 캡슐화하여, 상용구 코드를 줄이고 가독성을 높였습니다.
  • UserDefaults 값을 한 곳에서 관리하여 유지보수를 향상시켰습니다.