본문 바로가기
Swift

[iOS] About Property Wrapper

by dsungc 2024. 8. 4.

지금까지 써오던 UserDefaultManager 코드 개선해보려고합니다

제가 구현한 코드부터 보여드릴게요!

final class UserDefaultManager {

    private enum UserDefaultKey: String {
        case userNickname
        case userId
        case profile
    }
    
    
    static let shared = UserDefaultManager()
    
    private init() {}
   
    
    var userNickname: String {
        get {
            UserDefaults.standard.string(forKey: UserDefaultKey.userNickname.rawValue) ?? ""
        }
        set {
            UserDefaults.standard.setValue(newValue, forKey: UserDefaultKey.userNickname.rawValue)
        }
    }
    
    var userId: String {
        get {
            UserDefaults.standard.string(forKey: UserDefaultKey.userId.rawValue) ?? ""
        }
        set {
            UserDefaults.standard.setValue(newValue, forKey: UserDefaultKey.userId.rawValue)
        }
    }
    var profileImage: String {
        get {
            UserDefaults.standard.string(forKey: UserDefaultKey.profile.rawValue) ?? ""
        }
        set {
            UserDefaults.standard.setValue(newValue, forKey: UserDefaultKey.profile.rawValue)
        }
    }
    
    func removeAll() {
        for key in UserDefaults.standard.dictionaryRepresentation().keys {
            UserDefaults.standard.removeObject(forKey: key.description)
        }
    }
}

 

제가 지금까지 프로젝트를 진행하면서 UserDefaults를 사용하기 위해

위의 코드와 같이 UserDefaultManager를 만들어 관리해주었습니다.

 

그런데 저장해야할 값들이 많아지고, 값을 읽고 쓰는 get, set 로직이 매 값마다 구현되어 있기 때문에 코드를 좀 더 보완해야할 필요성을 느꼈고 이를 보완해 보고자 @propertyWrapper를 사용해봤습니다!

 

우선 첫번째로 UserDefault라는 propertyWrapper를 정의합니다.

@propertyWrapper
struct UserDefault<T> {
    
    let key: String
    let defaultValue: T
    
    var wrappedValue: T {
        get {
            UserDefaults.standard.string(forKey: key) as? T ?? defaultValue
        }
        set {
            UserDefaults.standard.setValue(newValue, forKey: key)
        }
    }
}

 

이 코드 중 wrappedValue는  @propertyWrapper를 사용할 때 필수로 구현해야 하는데요, 세부적인 부분을 살펴보면

 

  • 값을 가져오는 로직 (Getter): wrappedValue의 get 부분은 Property Wrapper가 적용된 속성에 접근할 때 호출됩니다. 즉, 사용자가 값을 읽을 때마다 wrappedValue의 get 로직이 실행되어 값을 반환합니다.
  • 값을 설정하는 로직 (Setter): wrappedValue의 set 부분은 값을 설정할 때 호출됩니다. 사용자가 속성에 새로운 값을 할당하면, 이 로직을 통해 값을 저장하거나 추가적인 처리를 할 수 있습니다.

UserDefault부분을 구현했으니 다음은 UserDefaultManager 를 수정해보았습니다.

final class UserDefaultManager {
    
    private enum UserDefaultKey: String {
        case userNickname
        case userId
        case profile
    }
    
    
    static let shared = UserDefaultManager()
    
    private init() {}
    
    @UserDefault(key: UserDefaultKey.userNickname.rawValue, defaultValue: "")
    static var userNickname
    
    @UserDefault(key: UserDefaultKey.userId.rawValue, defaultValue: "")
    static var userId
    
    @UserDefault(key: UserDefaultKey.profile.rawValue, defaultValue: "")
    static var profileImage
}

 

저는 처음에 이 형태가 굉장히 생소했는데요..

그런데 확실히 활용하는 면에 있어서는 훨씬 편하더군요.. 

 

예를 들어, 기존의 코드를 사용하기 위해선 UserDefaultManager.shared.userNickname 과 같이 값을 다뤘다면 수정 후엔

UserDefaultManager.userNickname 으로 사용 가능합니다.

또한 값을 추가하거나 삭제할 때도 이전이었다면 값마다 get,set 코드구문을 추가해주거나 삭제해줬어야하는데 이제는 키값과 @UserDefaut 구문 한 줄 정도를 수정하는 선에서 값 수정이 가능합니다. 

코드 유지보수에 굉장히 효과적이더라구요!

.

.

.

 

이렇게 @propertyWrapper를 사용하여 UserDefaultManager를 개선한 결과, 코드가 더욱 간결해지고 유지보수가 훨씬 쉬워졌습니다. 특히, 여러 값을 저장하고 관리하는 로직에서 중복을 줄이고, 코드의 가독성을 높일 수 있었습니다.

앞으로 더 많은 값들을 UserDefaults에 저장할 때도 유사한 방식으로 간편하게 확장할 수 있을 것 같아요!

이번 게시글은 여기까지이고~~

.

.

.

.

'Swift' 카테고리의 다른 글

[iOS] About RxSwift  (0) 2024.08.11
[iOS] About 램 모델클래스 > 구조체  (0) 2024.08.08
[iOS] About FsCalendar - 2  (0) 2024.07.20
[iOS] About SnapKit  (2) 2024.07.17
[iOS] About FSCalendar - 1  (0) 2024.07.14