editor 오른쪽에 canvas가 표시됨
Canvas
- View 코드를 미리 보여줌
- 캔버스에서 선택이 코드에도 반영됨 = 반대도 동일
- 코드 편집과 학습에 도움
Text("표시할 내용")
SwiftUI의 일반적인 Layout Cotainer
Stack = 원하는 View를 배치할 수 있는 Container
- VStack : View를 세로로 쌓을 수 있음
- HStack : View를 가로로 쌓을 수 있음
추가하고 싶은 뷰 코드에 command + 클릭 + Embed in 컨테이너
로 간단하게 컨테이너를 추가할 수 있음
이미지 - Image(systemName: "photo")
command + 클릭 + show SwiftUI Inspector...
으로 속성 지정 가능control + option + 클릭
하면 바로 나옴)VStack(alignment: .leading) {
command + 클릭 + show SwiftUI Inspector...
으로 속성 지정 가능Text("3 ingredients")
.font(.subheadline)
.font(.subheadline)
와 같은 메서드를 modifire라고 하며 뷰 또는 동작 방식을 지정할 때 사용.foregroundColor(.secondary)
command + 클릭 + Embed in List
하여 List Container에 넣으면 테이블 형식으로 만들어짐 List(0 ..< 5){ item in
//..
}
❕뷰에 큰 변화가 있을 때 캔버스는 일시정지 함
-> 재개 버튼 또는command + option + P
로 다시 활성화할 수 있음
NavigationView
- 앱의 다른 부분으로 navigating할 수 있음
- Navigation Bar를 표시하고 Navigation 스택으로 push
>
가 표시됨command + 클릭 + Extract SubView
하면 분리해줌ForEach
로 분리해서 데이터 전달 List(sandwiches) { sandwich in
⬇️
List() {
ForEach(sandwiches) { sandwich in
Spacer
- SwiftUI의 Layout 요소
- toolbar의 flexible space 처럼 공간을 채우도록 확장
View
와 PreviewProvoder
가 제공된 파일을 만들어줌resizable
수정자로 변경aspectRatio
수정자를 이용이미지를 확대해서 볼 수 있도록 fill
<-> fit
을 왔다 갔다 하고 싶음 🤔
SwiftUI에서 뷰는 UIView와 같은 클래스를 상속하는 클래스가 아닌 View
프로토콜을 준수하는 구조체
-> 상속받지 않고 스택에 쌓이고 값으로 전달됨
-> 참조 카운팅 없음
=> 뷰 계층 구조를 렌더링하기 위한 효율적인 데이터 구조로 축소
View
프로토콜은 body
프로퍼티만 required프레임워크는 UI를 정의하는 것 외에도 뷰의 종속성을 정의하기 때문에 렌더링할 시기를 알고 있음
zoomed
- 프레임워크에 의해 유지 @State private var zoomed = false
Image(systemName: "photo")
.resizable()
.aspectRatio(contentMode: zoomed ? .fill : .fit)
.onTapGesture {
withAnimation {
zoomed.toggle()
}
}
State 프로퍼티
는 SwiftUI가 읽고 쓸 때 관찰할 수 있음
-> 뷰의 렌더링이 확대 변수(= zoomed = State 프로퍼티)에 의존함을 알고 있음
-> 확대 변수가 변경되면 프레임워크는 렌더링을 변경하기 위해 body를 다시 요청
aspectRatio
호출이 뷰를 만든다 -> contentMode 속성은 zoomed 변수에서 파생상태 변수 = Source of Truth
오래된 속성 = Derived Value
Binding
도 발명이벤트 핸들러 콜백의 어떤 순서에서도 UI가 일관된 상태인지 확인해야 함
이미지를 확대 및 향상하는 이벤트 순서
1) zoom -> enhance -> zommout -> completion
2) zoom -> enhance -> completion -> zoomout
3) ...
이런 에러는 Source of Truth를 변경하고 이벤트 핸들러 콜백에서 직접 뷰를 변경하는 경우 쉽게 발생
4개의 이벤트 핸들러가 호출되는 순서의 경우는 24가지 (실제로는 두 번 이상 발생할 수 있으니 더 많음)
=> UI 프로그래밍.. 어렵다... 😟
뷰는 대부분 4개 이상의 이벤트를 처리해야 함
- Model Notification
- Target Action
- Delegate Methods
- Lifecyle Checkpoints
- Completion Handlers...
우리는 Human이라 너무 복잡한 걸 할 수가 없다!
기능이 추가 -> 요청이 폭발적으로 증가 -> 버그 증가
대부분 하나의 메서드에서 뷰의 업데이트를 수행하도록 작성
-> 순서가 고정되어 복잡성이 줄음
-> 이것에서 SwiftUI가 영감을 받음
edgesIgnoringSafeArea
수정자로 가장자리에서 safeArea를 무시하도록 변경onTapGesture
에서 zoomed를 토글하는 코드를 withAnimation
으로 래핑Label
사용Label("Spicy", systemImage: "flame.fill")
- 텍스트와 이미지를 함께 표시if
로 매운지 확인하고 배너 표시transition
모든 플랫폼에서 동일한 코드를 사용할 수 있음
class SandwichStore: ObservableObject {
@Published var sandwiches: [Sandwich]
init(sandwiches: [Sandwich] = []) {
self.sandwiches = sandwiches
}
}
ObservableObject
준수@Published
로 관찰하려는 속성을 표시@State
로 값에 대한 truth of value를 만든 것처럼 @StateObject
를 사용해 truth of mutable object를 만들 수 있음@StateObject
객체를 관찰하여 변경될 때 자동으로 뷰를 업데이트@main
표시가 있음 -> 앱의 시작점이다WindowGroup
- 앱의 모든 window에 뷰를 지정할 수 있음@StateObject
객체 선언@ObservedObject
로 만들어 이 객체의 변화를 관찰하고 싶다고 SwiftUI에 알림OnMove(perform:)
OnDlete(perform:)
-> 이미 Swipe로 삭제 가능toolbar
, EditButton
OnMove(perform:)
Button
ForEach
는 컬렉션의 변경 사항을 감시하여 데이터 소스 불일치 예외에 대해 걱정할 필요 없음앱 구축하고 한 번도 실행하지 않고 풍부한 동작을 모두 테스트했다 👍