티스토리 뷰
SwiftUI에는 @State 값을 기반으로 뷰의 상태를 조절할 수 있다. 단순히 몇가지 값을 기반으로 표현하는 뷰의 경우 이 값 바인딩이 사용하기 편리하며 가독성을 높여준다. 그러나 Picker나 Toggle등의 값 변화에 동작을 추가하고 싶을 때는 번거로운 작업이 예상되는 경우가 많다. 이럴 땐 기존의 델리게이트 방식을 사용하는 것이 편리한 것 같다.
다행히 SwiftUI의 바인딩은 Get, Set 동작을 커스텀할 수 있도록 해준다. 이를 통해 애플이 제작한 바인딩 기반 뷰들이 방출하는 값을 관찰하거나 뷰가 표시될 시점을 조절할 수 있다.
바인딩 Get 커스텀하기
Bool 바인딩 기반 뷰를 표시하고 싶지만 State가 Bool이 아닐 때
struct ContentView: View {
@State private var currentUser = "default"
var body: some View {
TextField("Username", text: $currentUser)
.alert("User Error", isPresented: .init(
get: { currentUser.isEmpty },
set: { _ in }
)) {
Button("Ok") {}
} message: {
Text("Enter username.")
}
}
}
currentUser가 빈 문자열인 경우에 경고창을 띄우게 된다.

바인딩 Set 커스텀하기
바인딩 기반 뷰가 방출하는 값을 관찰하고 싶을 때
struct ContentView: View {
@State private var flip = false
@State private var flipCount = 0
var body: some View {
VStack {
Text("Flip Count: \(flipCount)")
Toggle("Flip!", isOn: .init(
get: { flip },
set: { newValue in
flip = newValue
flipCount += 1
}
))
}
}
}
위와 같이 바인딩을 커스텀하면 스위치가 토글될 때마다 flipCount를 증가시킬 수 있다.
파일 정렬 Picker 메뉴 예제
struct File: Identifiable {
var name: String
var size: Int
var id: String { name }
}
File을 갖는 배열을 Picker 선택에 따라 정렬하는 코드를 짤 것이다.
@State private var orderBy: OrderBy = .name
var body: some View {
VStack {
Picker("Order By", selection: $orderBy) {
ForEach(OrderBy.allCases) { order in
Text(order.rawValue)
}
}
List(sortedFiles) { file in
HStack {
Text(file.name)
Spacer()
Text("\(file.size)").font(.caption)
}
}
}
}
Picker는 selection 바인딩에 사용자가 선택한 값(뷰의 태그 또는 뷰의 순서)을 자동적으로 Set해준다. 그러면 변경된 orderBy에 맞춰 정렬된 리스트를 불러와 표시한다.

Picker 항목을 다시 선택했을 때 오름차순과 내림차순을 전환하고싶다면?
@State private var ascending: Bool = true
우선 오름차순 내림차순 여부를 확인할 상태값을 생성한다.
Picker("Order By", selection: .init(
get: { orderBy },
set: { newValue in
if orderBy == newValue {
ascending.toggle()
} else {
orderBy = newValue
ascending = true
}
}
)) {
ForEach(OrderBy.allCases) { order in
Text(order.rawValue)
}
}
바인딩을 커스텀하여 다시 선택됨을 감지하게 작성한다. 이제 다시 선택되면 정렬 순서를 뒤집는다.

전체 코드
struct File: Identifiable {
var name: String
var size: Int
var id: String { name }
}
import SwiftUI
struct ContentView: View {
private var files = [
File(name: "Apple Myeongdong.jpg", size: 3_034_579),
File(name: "Be Kind.mp3", size: 7_048_172),
File(name: "Code.swift", size: 13_667)
]
enum OrderBy: String, CaseIterable, Identifiable {
case name = "Name"
case size = "Size"
var id: OrderBy { self }
}
@State private var orderBy: OrderBy = .name
@State private var ascending: Bool = true
private var sortedFiles: [File] {
switch orderBy {
case .name:
return ascending ?
files.sorted { $0.name < $1.name } :
files.sorted { $0.name > $1.name }
case .size:
return ascending ?
files.sorted { $0.size < $1.size } :
files.sorted { $0.size > $1.size }
}
}
var body: some View {
VStack {
Picker("Order By", selection: .init(
get: { orderBy },
set: { newValue in
if orderBy == newValue {
ascending.toggle()
} else {
orderBy = newValue
ascending = true
}
}
)) {
ForEach(OrderBy.allCases) { order in
Text(order.rawValue)
}
}
List(sortedFiles) { file in
HStack {
Text(file.name)
Spacer()
Text("\(file.size)").font(.caption)
}
}
}
}
}'가이드' 카테고리의 다른 글
| SwiftUI에서 구글로그인 띄우기 (0) | 2022.07.30 |
|---|---|
| SwiftUI 프로젝트에서 커스텀 Scheme 또는 파일 연결 처리하기 (0) | 2022.04.13 |
| SwiftUI fileImporter 파일선택기 사용하기 (UIDocumentPicker) (0) | 2022.04.12 |
| 그림으로 알아보는 핀터레스트 스타일 Collection View 만들기 (Swift) (0) | 2022.03.28 |
| Multipart form-data로 파일 업로드하기 (Swift, URLSession) (0) | 2022.03.28 |
