# Introduction to SwiftUI (wwdc)
- VStack
- 세로로 쌓을 수 있음
- HStack
- 가로로 쌓을 수 있음
- 뷰에 마우스를 대고 cmd+클릭 => Embed in HStack 하면 HStack으로 감싸짐
- 뷰에 있는 요소에 대고 cmd+클릭 => inspector로 이동
- wwdc에서는 스와이프가 된다고 하는데 나는 오ㅐ안됨..10:50
- 뷰에 cmd+클릭하고 Extract View 클릭하면 바로 뷰를 추출할 수 있음

- 지금까지 우리는 single collection을 사용하여 목록을 만들었고, 이는 데이터에서 기반한 list였다.
- 하지만 SwiftUI를 사용하면 list에서 정적 content와 동적 content를 혼합하여 사용할 수도 있다.
=> 바로 ForEach를 사용하면 된다.
1. 처음

2. ForEach 사용시

이제 아래와 같이 목록 바깥에다가 정적 요소를 추가할 수 있게 됐다.


- Spacer()은 SwiftUI의 일반적인 layout 요소이다. toolbar에서 유연하게 공간을 이동하며 사용 가능한 공간을 채우는 역할을 한다.
#### SandwichDetail (이미지)
- resizable
- SwiftUI가 공간에 맞게 이미지 크기를 조정하는 모드
- aspectRatio
- 가로 세로 비율을 유지하며 화면에 맞도록 하는 모드
- fill
- 이미지 잘리기도 함 + 화면에 아예 꽉차게
- 
- fit
- 이미지 전체를 보여줌 + 비율 맞춤 (화면에 꽉차지 않음)
- 
차례대로



#### 프리뷰에서 네비게이션뷰 적용하기

원래 이랬는데 프리뷰에 NavigationView만 넣어주면 아래와 같이 제대로 나옴

#### 발표자의 질문
> 샌드위치 안의 소스의 양을 확인하기 위해 이미지를 확대했다 작게했다 하면서 동적으로 컨텐츠를 변경하고싶은데 어떻게 할 수 있을까?
> => 알려면 SwiftUI에서 뷰가 작동하는 방식과 이유에 대해 알아야한다.
- 스유에서 View는 UIView와 같은 기본 클래스에서 상속되는 클래스가 아니라 View 프로토콜을 준수하는 구조체이다.
- 따라서 이는 뷰가 저장 프로퍼티를 상속하지 않음을 의미하고, 이는 스택에 할당되고 값으로 전달된다. (pass by value)
- 스유에서는 뷰가 엄청나게 light하다. => SwiftUI에서는 리팩토링을 망설일필요가 없다. subview를 추출하는 것은 런타임 오버헤드가 없기 때문이다.
- 프레임워크는 언제 다시 렌더링을 할지 알고있다. 그 이유는 view가 dependencies를 가졌기 때문이다. ‼️
- 사용자가 zoom하면 이미지를 fill로, 아니면 이미지를 fit으로 바꾸는 예시

- SwiftUI는 해당변수가 read, written 될 때를 observe할 수 있다.
- SwiftUI는 body내에서 zoomed가 read 되어지는것을 알고, 그것에 따라 렌더링하도록 할 수 있다.
- 즉, 해당 프로펕티가 변할떄, framework는 body가 다시 렌더링하도록 한다.
다시 돌아와서 아래 모서리부분에 빈 공간이 생기는 문제점이 발생했다.

- 이를 해결하기 위해서는 `edgesIgnoringSafeArea(.bottom)` 을 사용해주면 된다. 그럼 아래쪽 가장자리가 사라진다.
- Spacer()는 자동으로 요소 사이의 일부 padding을 유지하기 위한 최소한의 크기를 갖는다.
- Spacer(minLength:)를 통해 설정할 수 있다.
- 
이런 애니메이션이 자연스럽게 나오도록 WithAnimation과 transition을 사용해줌


그럼 지금까지 아이폰에서 봤고, 아이패드에서는 어떻게 보일까?
아래와 같이 보인다.



그래서 빈 화면에 샌드위치를 선택하라는 글을 써주려면 이렇게 네비게이션뷰 안에 Text만 추가해주면 된다.

### SandwichStore로 리팩토링🔩
1. 최상단

앱의 시작점은 @main을 통해 이루어지고, 그 객체는 App 프로토콜을 채택하며 WindowGroup에서 시작화면을 정의한다.
2. ContentView

3. SandwichStore

### 📚 스유 프로퍼티 래퍼 정리
> @ObservedObject / @Published
@State는 `특정 view에서만 사용하는 프로퍼티` 였다면,
@ObservedObject는` 여러 view에서 공유할 수 있는 커스텀 타입이 있는 경우나 여러 프로퍼티나 메서드가 있는 경우`, 즉 **복잡한 프로퍼티**에 사용된다.
<br>
특징
> ❗️ 1. String이나 integer 같은 간단한 로컬 프로퍼티 대신 외부 참조 타입을 사용한다는 점을 제외하면 @State와 매우 유사.
> ❗️ 2. @ObservedObject와 함께 사용하는 타입은 ObservableObject 프로토콜을 따라야 함.
> ❗️ 3. @Observed object가 데이터가 변경되었음을 view에 알리는 방법은 여러 가지가 있지만 가장 쉬운 방법은 @Published 프로퍼티 래퍼를 사용하는 것. = SwiftUI에 view reload를 트리거.
예시
```swift
class UserSettings: ObservableObject {
// @ObservedObject를 사용하기위해 @Published를 할당
@Published var score = 0
}
struct ContentView: View {
// @state를 지우고 @ObervedObject로 바꿔줌
// view가 외부 객체를 감지하게 해주는 역할
@ObservedObject var settings = UserSettings()
var body: some View {
VStack {
Text("나의 점수는 \(settings.score)점 입니다.")
Button(action: {
self.settings.score += 1
}) {
Text("Increase Score")
}
}
}
}
```
score에 @Published가 붙었기 때문에 이 score가 변경되면 view를 reload하게 된다.
> 참조타입이 아닌 struct로 해주고 싶을 때
```swift
struct UserSettings {
var score = 0
}
struct ContentView: View {
@State var settings = UserSettings()
var body: some View {
VStack {
Text("나의 점수는 \(settings.score)점 입니다.")
Button(action: {
self.settings.score += 1
}) {
Text("Increase Score")
}
}
}
}
```
> @StateObject
WWDC 2020에서 애플은 @StateObject를 추가로 공개했다.
@ObservedObject와 거의 같은 방식으로 작동한다.
SwiftUI가 View를 다시 랜더링 할 때, 실수록 취소되는 것을 방지해준다고 한다.