iOS 개발을 하면서 헷갈렸던 개념들을 다시 정리해보고 있습니다.
만약 틀린 내용이 있다면 피드백은 언제나 환영합니다.
더 자세하고 알고싶다면 아래쪽 참고사이트에서 확인하면 좋을 것 같습니다!
말투는 편한 말투로 작성하니 양해 부탁드립니다.
Property Wrapper 이용해서 특정 변수가 변경될시 자동으로 뷰 업데이트 가능 (데이터 주도적 방식)
import SwiftUI
struct SampleView: View {
@State private var count: Int = 0
var body: some View {
VStack {
Text("This is SampleView")
Text("Count: \(count)")
// 버튼을 눌러서 count 변수의 값을 바꾸기
// State 변수가 바뀌면 UI도 새롭게 업데이트됨
Button {
count += 1
} label: {
Text("Increase count")
}
}
}
}
import SwiftUI
struct SampleView: View {
@State private var count: Int = 0
var body: some View {
NavigationView {
VStack {
Text("This is SampleView")
Text("Count: \(count)")
// 버튼을 눌러서 count 변수의 값을 바꾸기
Button {
count += 1
} label: {
Text("Increase count")
}
// 버튼을 눌러서 BindingView로 이동하기
NavigationLink {
// $ 표시로 binding임을 명시
BindingView(count: $count)
} label: {
Text("Move to BindingView")
}
}
}
}
}
struct BindingView: View {
@Binding var count: Int
// init에서 직접 Binding 변수를 할당하고 싶을 경우는 아래처럼 작성 가능
/*
init(count: Binding<Int>) {
self._count = count
}
*/
var body: some View {
VStack {
Text("This is BindingView")
Text("Count: \(count)")
// 버튼을 눌러서 count 변수의 값을 바꾸기
// Binding 변수가 바뀌면 SampleView의 State 변수도 함께 바뀜
Button {
count += 1
} label: {
Text("Increase count")
}
}
}
}
여기서 Publisher, 구독 같은 개념은 Combine이란 프레임워크와 밀접한 관련이 있습니다. Combine에 대한 내용도 나중에 따로 포스팅하겠습니다.
중요한 내용은 값이 변하는 타이밍을 감지하고 특정 코드를 실행하게 해준다는 것입니다!
import SwiftUI
import Combine
class Publisher {
@Published var count: Int = 0
init() {
// 1초 후에 count 증가시킴
DispatchQueue.main.asyncAfter(deadline: .now()+1.0) {
self.count += 1
}
// 2초 후에 count 증가시킴
DispatchQueue.main.asyncAfter(deadline: .now()+2.0) {
self.count += 1
}
// 3초 후에 count 증가시킴
DispatchQueue.main.asyncAfter(deadline: .now()+3.0) {
self.count += 1
}
}
}
class Subscriber {
private let publisher = Publisher()
// Combine 관련 코드 (구독을 취소할 수 있도록 함)
private var cancellables = Set<AnyCancellable>()
init() {
// Publisher 변수인 count를 구독
// 값이 변할때마다 received로 변한 값이 들어오고 print문이 실행됨
// 지금은 1초마다 값이 변하기 때문에 1초마다 print문이 실행됨
publisher.$count
.sink { received in
print(received)
}
.store(in: &cancellables)
}
}
struct SampleView: View {
private let subScriber = Subscriber()
var body: some View {
Text("This is SampleView")
}
}
import SwiftUI
class Publisher: ObservableObject {
@Published var count: Int = 0
init() {
// 1초 후에 count 증가시킴
DispatchQueue.main.asyncAfter(deadline: .now()+1.0) {
self.count += 1
}
// 2초 후에 count 증가시킴
DispatchQueue.main.asyncAfter(deadline: .now()+2.0) {
self.count += 1
}
// 3초 후에 count 증가시킴
DispatchQueue.main.asyncAfter(deadline: .now()+3.0) {
self.count += 1
}
}
}
struct SampleView: View {
@State private var count: Int = 0
@ObservedObject private var publisher = Publisher()
// init에서 직접 ObservedObject 객체를 할당하고 싶을 경우는 아래처럼 작성 가능
/*
init() {
self._publisher = ObservedObject(wrappedValue: Publisher())
}
*/
var body: some View {
VStack {
Text("This is SampleView")
// 자동으로 변화를 감지해서 UI를 업데이트하기 때문에 1초마다 count값이 증가함
Text("Count: \(publisher.count)")
}
}
}
import SwiftUI
class Publisher: ObservableObject {
@Published var count: Int = 0
init() {
// 5초 후에 카운트 증가시킴
DispatchQueue.main.asyncAfter(deadline: .now()+5.0) {
self.count += 1
}
// 6초 후에 카운트 증가시킴
DispatchQueue.main.asyncAfter(deadline: .now()+6.0) {
self.count += 1
}
// 7초 후에 카운트 증가시킴
DispatchQueue.main.asyncAfter(deadline: .now()+7.0) {
self.count += 1
}
}
}
struct SampleView: View {
@StateObject private var publisher = Publisher()
var body: some View {
NavigationView {
VStack {
Text("This is SampleView")
// 버튼을 눌러서 ParentView로 이동하기
NavigationLink {
// publisher 객체 넘겨주기
ParentView()
.environmentObject(publisher)
} label: {
Text("Move to ParentView")
}
}
}
}
}
struct ParentView: View {
// 넘겨진 객체들 중 Publisher 타입의 객체를 받아옴
@EnvironmentObject private var publisher: Publisher
var body: some View {
VStack {
Text("This is ParentView")
// ChildView로 publisher를 넘기는 코드를 따로 작성하지 않아도 됨
// 만약 navigation으로 이동하는 뷰라면 .environmentObject로 다시 넘겨줘야함
ChildView()
}
}
}
struct ChildView: View {
// 넘겨진 객체들 중 Publisher 타입의 객체를 받아옴
@EnvironmentObject private var publisher: Publisher
var body: some View {
VStack {
Text("This is ChildView")
Text("Count: \(publisher.count)")
}
.background(Color.cyan)
}
}
https://medium.com/hcleedev/swift-observedobject와-stateobject-4f851ed9ef0d
https://www.hohyeonmoon.com/blog/swiftui-data-flow/
https://stackoverflow.com/questions/61804474/why-cant-swiftui-distinguish-2-different-environment-objects
https://dblog.tech/21