티스토리 뷰
1편 글에 이어서 2편 글을 이어나갈게요!
SwiftUI에서 UI 업데이트하기
SwiftUI의 View에서 프로퍼티 값을 변경할 경우, @State를 마킹해서 "변경이 필요한 상태 값"이라는 것을 표시해요.
UIKit의 경우 특정 객체의 상태를 변경해주기 위해 그 객체에 접근해서 메서드를 통하거나 직접 그 프로퍼티의 값을 변경했었어요.
이 과정에서 타이밍에 따라 의도하지 않은 결과가 나오거나 버그가 발생하는 등의 문제가 발생하기 쉬워서 고려해야 할 게 많아요.
SwiftUI의 경우 @State로 마킹된 프로퍼티의 값이 변경될 경우, 그 뷰를 무효화(invalidate)하여 숨겼다가 body를 다시 계산해서 보여줘요.
UIKit의 경우 어떤 값을 보여주다가 그 값을 갱신할 경우 기존의 UI에서 reload 하는 동작을 추가했어야 했고, 이 과정에서 문제가 발생할 수 있었지만 SwiftUI에서는 이 무효화를 통해 값 경신을 보다 편리하게 만들었다고 보면 될 것 같아요.
예를 들어, 앱 시작시 보여주고 싶은 화면에서 변경될 프로퍼티 값을 가져야 한다면 아래와 같이 표현할 수 있어요.
struct ContentView: View {
@State var game = Game()
@State var guess: RGB
...
}
코드 편집기 활용하기
SwiftUI에서 코드 편집기를 사용하면 스토리보드처럼 편하게 개발할 수 있어요.
스토리보드와 다른 점은 SwiftUI의 경우 코드 편집기를 사용하면 그 변경사항이 코드에 바로 변경된다는 거예요!
코드 편집기는 Control + Option + 클릭으로 열 수 있어요.
바인딩(Binding)
바인딩이라는 용어는 RxSwift나 Combine처럼 Reactive Programming을 경험했다면 익숙한 용어예요!
SwiftUI에서는 Stream을 만들어 바인딩을 하는 것이 아니라 "$" 표시를 통해 바인딩해요.
프로퍼티 guess가 있을 때, guess가 가진 요소 red에 접근한 guess.red는 단순히 읽기 전용이에요.
guess.red 그 자체는 단순한 특정 값을 의미해요.
하지만 $guess.red는 읽기 및 쓰기가 가능해요.
즉, $를 붙임으로써 단순 읽기 전용 프로퍼티가 쓰기도 가능하게 만들어주고, 이를 통해 변화를 감지할 수 있는 바인딩을 해준다고 할 수 있어요!
예를 들어, 입력받은 값을 단순히 출력만 해주는 로직의 경우에는 $가 필요 없어요!
read만으로 충분하기 때문이죠.
...
Text(
"Color: \(guess.red)"
)
...
하지만 guess라는 프로퍼티가 가진 red값을 변경할 수 있기 위해서는 아래와 같이 $를 표기해요.
...
Slider(value: $guess.red)
.accentColor(.red)
...
여기서 중요한 것은 위에서 guess.red를 읽기 및 쓰기로 넘겨받고 있는 객체 Slider에서 value를 어떻게 정의하는지에요.
struct Slider: View {
@Binding var value: Double
}
Slider라는 객체가 value를 직접 소유하고 있는 개념이 아니라 외부에서 읽기 및 쓰기로 주입받고 있는 구조이기 때문에 value 앞에 @Binding을 마크해줘요.
즉, 바인딩이 표시된 프로퍼티는 이 객체가 상태로서 직접 가지고 있는 프로퍼티가 아니라 외부에서 주입받고, 이 객체 내부에서의 변화가 외부에 전달됨을 알 수 있어요.
Subview 추출하기
SwiftUI의 편리한 기능 중 하나는 Subview 추출이에요.
IntelliJ의 경유 특정 메서드에서 부분 메서드를 추출(Extract)하는 기능이 잘 되어있어 자주 사용했지만, Xcode의 경우 잘 안 되는 경우가 많아 직접 구현했었어요.
SwiftUI의 View에서 특정 부분을 편리하게 Extract 하는 기능은 Command-클릭을 통해 할 수 있어요.
Modifier의 순서
Modifier는 이름 그대로 변경, 혹은 수정을 위한 코드예요.
어떤 요소의 값을 바꿔주는 역할을 하는 것으로 예를 들면 아래와 같은 코드가 있어요!
Text(guess.intString)
.padding()
.border(Color.purple)
어떤 Text가 있을 때, 그 텍스트에 패딩을 주고 경계 색깔을 바꿔주기 때문에 .padding과 .border는 Text의 Modifier라고 할 수 있어요.
그 결과물은 아래와 같아요.
하지만 만약 순서를 변경하면 어떻게 될까요?
Text(guess.intString)
.border(Color.purple)
.padding()
당연할 수 있지만 결과가 바뀌어요.
위의 코드와 다르게 Padding을 주기 전 border color를 주기 때문에 Padding은 그 border 바깥에 정의되는 것이죠.
그래서 경우에 따라 순서가 중요하지 않은 케이스도 있을 수 있지만, 대부분의 경우 Modifier의 적용 순서는 중요해요.
순서에 따라 의도하지 않은 UI 결과물이 나올 수 있어요.
Group
HStack, VStack을 이야기하며 잠시 Group 이야기를 한 적이 있어요!
Group 역시 HStack, VStack과 마찬가지로 SwiftUI의 컨테이너예요.
요소들을 묶는다는 측면에서 H, V Stack과 같지만, Layout을 수행하지 않는다는 점이 달라요.
쉽게 말하면, HStack의 경우 Group과 마찬가지로 컨테이너 역할을 수행하지만 사용 즉시 요소들을 UI에 수평(Horizontal)이 되도록 배치시키는 반면(VStack의 경우 Vertical로 수직) Group은 요소들을 묶어주지만 그 요소들의 UI 배치에 영향을 주지는 않아요.
Preview 아이폰 사이즈 설정하기
1편 글에서 Preview를 통해 화면을 미리 볼 수 있다는 언급을 했었어요!
UI 작업을 할 때에 보통 여러 기기의 화면을 체크해봐야 하기 때문에 시뮬레이터를 변경하며 번거롭게 일일이 빌드를 했어야 했어요.
SwiftUI에서는 Preview의 기기 화면을 변경함으로써 쉽게 UI를 확인할 수 있어요!
struct ContentView_Previews : PreviewProvider {
static var previews: some View {
ContentView()
.previewDevice("iPhone 8") // preview device 추가
}
}
이름도 직관적으로 previewDevice이므로 가독성도 매우 좋은 것 같아요 :)
Device이름이 String이기 때문에 오류의 가능성이 있겠죠?
제가 사용한다면 enum으로 타입을 만들어서 사용할 것 같아요.
저 이름은 run destination menu에 있는 그대로를 사용해야 해요.
예를 들어, "iPhone SE"는 오류가 발생하기 때문에 "iPhone SE (2nd generation)"으로 설정해야 해요.
GeometryReader
UIKit으로 작업할 때 고민되었던 포인트 중 하나는 어떤 View의 사이즈를 파악하는 것이었어요.
명시적으로 사이즈를 지정해주는 경우도 있지만 intrinsic size처럼 코드 상에서 사이즈를 파악하기 힘든 경우도 있었어요.
SwiftUI에서는 GeometryReader를 통해 size와 frame 값들을 파악할 수 있어요.
GeometryReader에 대한 이야기는 추후에 더 자세히 다룰 예정이니 이번 글에서는 이런 게 있구나 정도로 넘어갈게요.
ContentView에서, ZStack을 Container에 넣으면 코드가 아래와 같이 돼요.
GeometryReader { proxy in
ZStack {
...
GeometryReader는 GeometryProxy 객체를 제공하는데 이 객체는 frame 메서드들과 size, safeAreaInset 프로퍼티를 제공해요.
이 정보들을 위에서 proxy라는 이름으로 명명했어요.
일반적인 클로저의 지역 변수처럼 정의되어 있기 때문에 아래와 같이 사용할 수 있어요.
(NeuButtonStyle(
width: proxy.size.width * buttonWidth,
height: proxy.size.height * labelHeight))
...
3편에서 이어갈게요!
'iOS 앱개발 > iOS' 카테고리의 다른 글
[iOS] - XCTest 놓치고 있던 내용 가벼운 정리 (0) | 2022.09.12 |
---|---|
[iOS] File System 이해하기 (0) | 2022.06.12 |
[iOS] - SwiftUI 이해하기(1) (0) | 2022.05.29 |
[iOS] ReactorKit 개념 이해하기(feat.README of ReactorKit) (0) | 2022.04.07 |
[iOS] Coordinator Pattern(feat. Swift)이란? (0) | 2022.01.29 |
- Total
- Today
- Yesterday
- filter#isalnum#lower
- NumberofDiscIntersections#Codility#Sort#Python
- Distinct#Codility#Python
- Brackets#Stacks and Queues#Codility#Python
- 파이썬알고리즘인터뷰#4장
- Swift#Tuples#Range
- PassingCars#Codility#Python
- 날짜 계산#BOJ#완전탐색#Python
- 텀 프로젝트#백준알고리즘#Python
- 순열사이클#BOJ#Python
- 반복수열#백준알고리즘#Python
- 랜선자르기#이분탐색#BOJ#Python
- 배열합치기#분할정복#BOJ#Python
- 종이자르기#분할정복#BOJ#Python
- 미로 탐색#백준알고리즘#Python
- 병든 나이트#BOJ#탐욕법#Python
- 리모컨#완전탐색#BOJ#Python
- django
- 암호코드#dp#BOJ#Python
- API#lazy#
- 나무자르기#BOJ#이분탐색#Python
- 쿼드트리#BOJ#분할정복#Python
- 섬의개수#백준알고리즘#Python
- 토마토#백준알고리즘#Python
- Triangle#Sorting#Codility#Python
- 터틀비치#리콘#xbox#controller
- 백준 알고리즘#BackTracking
- django#slicing
- 공유기 설치#BOJ#이분탐색#Python
- N으로 표현#DP#Programmers#Python
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |