일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- Codable
- Pod
- 프로그래머스
- JSON
- 정보처리기사 실기 요약본
- Xcode
- ios캡처방지
- Decodable
- UITableView
- JSONParser
- 2018 KAKAO BLIND RECRUITMENT
- 정보처리기사
- parse
- ios캡처감지
- avcapturesession
- 외부카메라감지
- 정보처리기사 실기
- 카메라유선연결
- IOS
- cocoapods
- cancelstouchesinview
- CustomCode
- swift
- programmers
- 위클리챌린지
- ios외부카메라연결
- usb카메라연결
- ios카메라유선연결
- AVFoundation
- ios외부디바이스연결
- Today
- Total
iOS 개발일기
[Swift] UIKit 환경에서 Property Wrapper 사용하기 본문
프로젝트에서 웹 서비스 통신을 할 때 몇 개의 값들이 필수로 존재해야 되는 경우가 존재했었다.
이럴 때마다 입력을 하거나 초기화에 값을 넣어주기에는 너무 불편한 것 같아서 생각을 하던 찰나에 생각하게 된 것이 Property Wrapper(프로퍼티 래퍼)였다.
Swift 5.1에서 Property Wrapper가 나왔을 때에는 SwiftUI에서는 자주 사용될 것 같았지만 UIKit에서는 자주 사용되지 않을 것이라 생각했었다. 현재까지 개발한 프로젝트는 모두 UIKit 환경에서 개발되었기 때문에 Property Wrapper를 적극적으로 사용할 기회가 별로 없었는데 이번 기회에 사용할 기회가 있어 어떻게 사용했는지 적어보고자 한다.
UserDefaults
UIKit 환경에서 Property Wrapper를 사용하는 예제들을 보면 UserDefaults를 Property Wrapper를 이용해서 사용하는 것 같다. 기본적으로 UserDefaults를 활용하여 데이터를 관리하려면 매번 UserDefaults 인스턴스를 직접 호출하여 값을 가져오거나 저장해야 하는데 이 과정은 반복적이고 가독성을 떨어트릴 수 있다.
var userId = UserDefaults.standard.string(forKey: "identifier")
print(userId) // nil
UserDefaults.standard.set("ABCD", forKey: "identifier")
userId = UserDefaults.standard.string(forKey: "identifier")
print(userId) // "ABCD"
Property Wrapper를 사용하여 UserDefaults를 관리하면 일일이 인스턴스를 사용하여 관리할 필요가 없어진다.
@propertyWrapper
struct UserDefault<T> {
enum Keys: String {
case identifier //아이디
case email //이메일
}
let key: Keys
let defaultValue: T
var wrappedValue: T {
get {
UserDefaults.standard.object(forKey: key.rawValue) as? T ?? defaultValue
}
set {
Userdefaults.standard.set(newValue, forKey: key.rawValue)
}
}
}
UserDefaults에 저장할 키 값을 열거형으로 관리하여, 각 데이터 항목에 대한 식별과 추적이 가능하도록 개선하였다. Property Wrapper를 적용하여 UserDefaults 접근을 캡슐화함으로써, 기존의 직접적인 UserDefaults 사용 방식에 비해 보다 효율적이고 안전하게 데이터를 저장하고 조회할 수 있고 좀 더 편리하게 사용할 수 있다.
@UserDefault<String>(forKey: .identifier, defaultValue: "") var userId: String
print(userId) // ""
userId = "ABCD"
print(userId) // "ABCD"
WebService 공통 파라미터 관리
프로젝트에서 WebService 통신을 하는데 요청 데이터에 자주 공통적으로 필요로하는 값들이 있어 어떻게 관리하면 좋을까 생각하다가 사용한게 Property Wrapper였다. 예를 들면, 요청 데이터에 사용자의 지역 정보가 공통으로 사용된다고 가정하면 인스턴스를 생성할 때마다 적어줘야했다.
struct RequestA: Encodable {
let a: String
let languageCode: String
}
struct RequestB: Encodable {
let b: String
let languageCode: String
}
struct RequestC: Encodable {
let c: String
let languageCode: String
}
let languageCode: String = {
if #available(iOS 16.0, *) {
value = Locale.current.language.languageCode?.identifier ?? ""
} else {
value = Locale.current.languageCode ?? ""
}
}()
let requestA = RequestA(a: "a", languageCode: languageCode)
let requestB = RequestB(b: "b", languageCode: languageCode)
let requestC = RequestC(c: "c", languageCode: languageCode)
이러한 작업을 조금이라도 줄이기 위해서 생각해낸게 공통으로 사용되는 파라미터에 대해서 Property Wrapper를 사용해서 값을 일일이 적어주지 않아도 사용할 수 있도록 만들었다.
@propertyWrapper
struct LanguageCode: Encodable {
private var value: String
init() {
if #available(iOS 16.0, *) {
value = Locale.current.language.languageCode?.identifier ?? ""
} else {
value = Locale.current.languageCode ?? ""
}
}
var wrappedValue: String {
return value
}
func encode(to encoder: any Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(value)
}
}
Property Wrapper에 Encodable을 채택하여 값이 인코딩될 수 있도록 설정해주어야 요청할 경우에 에러가 발생하지 않는다. 그리고 이렇게 초기화 메서드를 정의할 때에 값을 미리 넣어주게되면 변수를 선언할 때 따로 값을 넣어줄 필요가 없다.
protocol HasLanguageCode {
var languageCode: String { get }
}
struct RequestA: Encodable, HasLanguageCode {
let a: String
@LanguageCode var languageCode: String
}
struct RequestB: Encodable, HasLanguageCode {
let b: String
@LanguageCode var languageCode: String
}
struct RequestC: Encodable, HasLanguageCode {
let c: String
@LanguageCode var languageCode: String
}
let requestA = RequestA(a: "a")
let requestB = RequestB(a: "b")
let requestC = RequestC(a: "c")
Property Wrapper를 이용하여 공통된 파라미터를 인스턴스를 생성할 때마다 작성할 필요가 없도록 할 수 있다. 이 외에도 `Projected Value`를 사용하는 등 더 다양하게 사용할 수 있지만, UIKit 환경에서는 사용할 일이 별로 없어서 손이 잘 안가는 것 같다.
'iOS > Swift' 카테고리의 다른 글
[Swift] UITableView Dynamic Height (0) | 2024.12.26 |
---|---|
[Swift] UICollectionView 'didSelectItemAt' 함수가 호출되지 않는 이유 (2) | 2023.12.07 |
[Swift] Custom PageViewController (0) | 2022.03.22 |
[Swift] JSONParser - JSONSerialization (0) | 2022.03.16 |
[Swift] JSONParser - Decodable(2) (0) | 2022.03.15 |