일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- base64 변환
- pod install
- swift
- swift #swift keychain #keychain 사용법
- url 추적
- GeometryReader
- 스크롤 탭
- ios
- UIPresentationController
- 기존 앱
- scrolling tab
- Swift Package Manager
- oberve url
- transformation.map
- Tuist
- DataBinding
- convert base64
- url 관찰
- Side Menu
- DevelopmentRegion
- 개발자 면접
- notifychanged
- UIViewControllerTransitioningDelegate
- SwiftUI
- detect url
- List
- ViewBuilder
- development language
- 상단 탭바
- Android
- Today
- Total
버그 잡이
Swift에서 Property Wrapper 시작하기 #UserDefaults # projectedValue 본문
www.avanderlee.com/swift/property-wrappers/
위 글을 보고 정리한 내용임을 밝힙니다.
Property Wrapper란 무언인가?
property wrapper는 property가 저장되고 계산되는 것을 정의하는 하나의 층으로 볼 수 있습니다.
이는 getter와 setter에 사용되는 반복적인 코드를 대체하는데 유용하게 쓰일 수 있습니다.
가장 일반적인 예로는 user-default를 property-wrapper로 custom 해서 쓰는 예제가 있습니다.
Property wrapper와 UserDefaults
아래 코드르 보면 알 수 있듯이 UserDefault 객체에서 wrapper를 만들고 있습니다.
이로써 string key를 복사 붙여넣기 할 필요없이 해당 property를 사용할 수 있습니다.
extension UserDefaults {
public enum Keys {
static let hasSeenAppIntroduction = "has_seen_app_introduction"
}
/// Indicates whether or not the user has seen the onboarding.
var hasSeenAppIntroduction: Bool {
set {
set(newValue, forKey: Keys.hasSeenAppIntroduction)
}
get {
return bool(forKey: Keys.hasSeenAppIntroduction)
}
}
}
UserDefaults.standard.hasSeenAppIntroduction = true
guard !UserDefaults.standard.hasSeenAppIntroduction else { return }
showAppIntroduction()
이것은 좋은 해결책으로 보이지만 정의된 key와 property가 많은 경우 이는 좋은 해결책이 아닙니다.
(UserDefault의 내부 코드가 관리하기 힘들 정도로 늘어날 수 있지요)
@propertyWrapper는 이 문제를 해결하는데 도움을 줍니다.
불필요한 코드를 줄이기 위해서 Property Wrapper 사용하기
우리는 property Wrapper를 사용해서 반복된 코드를 없앤 UserDefault를 만들 수 있습니다.
@propertyWrapper
struct UserDefault<Value> {
let key: String
let defaultValue: Value
var container: UserDefaults = .standard
var wrappedValue: Value {
get {
return container.object(forKey: key) as? Value ?? defaultValue
}
set {
container.set(newValue, forKey: key)
}
}
}
wrapper는 아직 값이 등록되지 않아도 default 값을 넘겨줄 수 있게 해줍니다.
우리는 어떤 값이든 generic 값인 Value를 통해서 넘겨줄 수 있습니다.
이를 통해 우리는 이전 코드를 아래와 같이 수정할 수 있습니다.
extension UserDefaults {
@UserDefault(key: "has_seen_app_introduction", defaultValue: false)
static var hasSeenAppIntroduction: Bool
}
위 코드를 보면 prppertyWrapper로 정의된 이니셜라이저로 property를 생성하고 default value를 넘겨줄 수 있음을 확인할 수 있습니다.
UserDefaults.hasSeenAppIntroduction = false
print(UserDefaults.hasSeenAppIntroduction) // Prints: false
UserDefaults.hasSeenAppIntroduction = true
print(UserDefaults.hasSeenAppIntroduction) // Prints: true
위와 같이 간단하게 사용할 수 있습니다.
같은 wrapper를 활용해서 프로퍼티들을 더 추가할 수 있습니다.
extension UserDefaults {
@UserDefault(key: "has_seen_app_introduction", defaultValue: false)
static var hasSeenAppIntroduction: Bool
@UserDefault(key: "username", defaultValue: "Antoine van der Lee")
static var username: String
@UserDefault(key: "year_of_birth", defaultValue: 1990)
static var yearOfBirth: Int
}
projectedValue와 Property Wrapper
property wrapper는 wrapped value에 다른 프로퍼티를 추가할 수 있는 기능이 있습니다.
이는 projectedValue라는 속성을 통해서 가능합니다.
즉, wrappedValue 뿐만 아니라 추가적인 하나의 Value를 더 가질 수 있는 것이죠.
@propertyWrapper
struct SampleFile {
let fileName: String
var wrappedValue: URL {
let file = fileName.split(separator: ".").first!
let fileExtension = fileName.split(separator: ".").last!
let url = Bundle.main.url(forResource: String(file), withExtension: String(fileExtension))!
return url
}
var projectedValue: String {
return fileName
}
}
struct SampleFiles {
@SampleFile(fileName: "sample-image.png")
static var image: URL
}
print(SampleFiles.image) // Prints: "../resources/sample-image.png"
print(SampleFiles.$image) // Prints: "sample-image.png"
// $ 기호를 앞에 붙여주면 projectedValue 값을 가져올 수 있습니다.
위처럼 "projectedValue" 를 통해서 wrappedValue 뿐만 아니라 다른 추가적인 값도 관리할 수 있습니다.
이 기능은 initial value가 알고 싶을 때,
'$' 와 같은 접두사, 접미사를 붙이고 싶을 때 유용합니다.
정리
1. property wrapper는 불필요한 코드를 줄여주는 하나의 층이다.
2. 이 층에서는 get, set과 관련된 로직 처리가 들어가 wrapping된 property는 get, set 함수를 하나하나 구현할 필요가 없다.
3. projectedValue를 통해서 하나 추가적인 property를 관리할 수 있다.
'Swift' 카테고리의 다른 글
swift - image button inset (이미지 버튼 inset 주기) (0) | 2021.01.23 |
---|---|
swift - guard let self = self vs self?. (0) | 2020.12.08 |
Swift - 스크롤뷰(scorllView)를 구현하기 위한 2가지 방법 (0) | 2020.11.01 |
Swift - Attributed String으로 특정 글자만 색상 바꾸기 (0) | 2020.10.06 |
Swfit - 객체를 포함한 json 을 string으로 변환하기 (0) | 2020.10.05 |