struct ContentView: View {
@StateObject var user = User()
}
class MyViewModel: ObservableObject {
@Published var dataSource: MyModel
init(dataSource: MyModel) {
self.dataSource = dataSource
}
}
class User: ObservableObject {
@Published var name = "Hohyeon Moon"
}
struct ContentView: View {
@ObservedObject var user = User()
var body: some View {
VStack {
Text("Your name is \(user.name).")
}
}
}
// SceneDelegate.swift
var settings = UserSettings()
window.rootViewController = UIHostingController(rootView: ContentView().environmentObject(settings))
view가 나타낼 때 수행할 action을 추가하고, 파라미터 perform에 들어가는 action은 optional 입니다.
.onAppear() // no effect
.onAppear(perform: {
// action
})
action이 nil이면 효과가 없습니다. 리턴값은 view가 나타날 때 action을 트리거한 view를 리턴합니다.
view가 사라질 때 수행할 action을 추가하고, 파라미터 perform에 들어가는 action은 optional입니다.
.onDisappear() // no effect
.onDisappear(perform: {
// action
})
iOS15에서 사용가능한 수정자입니다. 뷰가 나타날 때 수행할 비동기 작업을 추가합니다. (네트워크 요청을 넣을때 유용하게 사용한다)
예제 코드
var body: some View {
List {
// content
}
.task {
self.viewModel.requestNames()
}
}
task가 onAppear보다 좋은점은, task가 modifier로 추가된 view의 수명과 일치하는 수명을 가진다는 점입니다.
기본적으로 task() 수정자를 사용하여 생성된 작업은 가능한 가장 높은 우선순위로 실행되지만, 작업의 중요도에 따라 우선순위를 사용자 정의로 적용할 수 있다.
반환 값으로,id값이 변경된 작업을 다시 시작하는 뷰라는 점을 제외하면 위의 task와 동일하다.
위의 task와 다른점으로, 특정 값이 변경되면 SwiftUI는 이전 작업을 자동으로 취소하고 새값으로 새 작업을 생선한다는 차이도 있습니다. 변경을 감지하기 위해 수정자는 id 매개변수의 새 값이 이전값과 같은지 테스트합니다. 그러므로 이를 작동하기 위해 id는 Equatable 프로토콜을 준수해야한다.
var body: some View {
NavigationView {
List {
// content
}
// 이 id값이 변결될 때마다 fetchData()를 실행한다.
.task(id: selectedBox) {
await fetchData()
}
}
}
특정 값이 변경될때 action을 실행하고 싶으면 사용하면 된다.
예제 코드
.onChange(of: self.text) { [text] (newText) in
print(text, newText)
}
일반적으로 ForEach를 사용하여 SwiftUI에서 View를 반복 할 수 있습니다. SwiftUI의 ForEach는 Struct구조 이므로 직접 반환이 가능합니다.
Form {
ForEach(1..<10) { number in
Text("Row \(number)") // number를 지우고 $0를 넣을수도 있다.
}
}
id: \.self
부분은 SwfitUI가 배열의 각 요소를 고유하게 식별할 수 있도록 하기 위해 필요합니다. 즉, 항목을 추가하거나 제거하면 SwiftUI가 정확히 어떤 요소를 알고 있는지 확인 가능합니다.
List {
Section(header: Text("first section")) {
ForEach(arr1, id: \.self) { s in
Text(s) // 값이 순차적으로 나타남
}
}
// indices는 컬렉션을 오름차순으로 구독하는 유효한 인덱스입니다.
ForEach(people.indices) { index in
Text("\(people[index])")
}
배열의 인덱스를 안전하게 판단해주기 위해 사용함. Array를 확장해서 사용하는 모습
iOS9 이상 코드
extension Array {
subscript (safe index: Int) -> Element? {
return indices ~= index ? self[index] : nil
}
}
MVVM 같은 아키텍처중 하나이다 다른이름으로 VIP(View, Interactor, Presenter)라고 부르기도 한다.
VIP 주기를 도입하였다, 이는 단방향 제어 흐름을 제공하고 시스템의 기초를 형성한다.
View -> Interactor -> Presenter -> View 흐름, 여기서 모든 곳이 Strong으로 연결이 되면 순환 참조가 일어나기 떄문에 Presenter에서는 View로 가는 흐름은 Weak로 가진다.
View는 Interactor에 있는 비즈니스 로직 호출을 할 때 Request에 필요한 데이터를 담아 넘겨준다. Interactor는 필요한 로직을 처리한 후, Presenter에게 그 결과값을 Response에 담아서 전송한다. Presenter는 View가 화면에 정상적으로 값을 표현할 수 있도록 Response의 데이터를 가공해 ViewModel에 담아 넘겨준다.
참조
https://www.hohyeonmoon.com/blog/swiftui-data-flow/
https://zeddios.tistory.com/1306
https://zeddios.tistory.com/1154
https://seons-dev.tistory.com/33
http://minsone.github.io/programming/check-index-of-array-in-swift