본문 바로가기

Swift & SwiftUI

100days of SwiftUi - project 7

 

공부한 내용 정리

 

100 days of SwiftUi - Project 7

https://www.hackingwithswift.com/100/swiftui/36

 

import SwiftUI

struct User {
    var firstName = "Billbo"
    var lastName = "Baggins"
}

struct ContentView: View {
    @State private var user = User()
    
    var body: some View {
        VStack {
            Text("Hello, \(user.firstName) \(user.lastName)" )
            TextField("First name: ", text: $user.firstName)
            TextField("Last name", text: $user.lastName)
        }
        .padding()
    }
}

 

TextField에 글자를 입력한 대로 화면의 이름이 바뀜

그러나 struct를 class로 바꾸면 TextField는 바뀌는것이 보이는데 화면의 이름이 바뀌지 않음. 

왜그럴까?  -> Struct은 값타입이고 Class는 참조타입이기 때문이다.

struct타입은 값이 복사되어 개별의 객체가 되고 Class는 같은 인스턴스 메모리 주소를 가르킴.

(구조체에서 속성을 수정하는 메서드에는 mutating 키워드 필요. 그러나 구조체 자체가 상수인 경우 속성 변경할 수 없게됨. Swift는 속성이 변경될 때 전체 구조체를 파괴하고 다시 생성할 수 있어야 하지만, 상수 구조체인경우 다시 생성할 수 없게됨 )

여러 뷰 간에 데이터를 공유하려는 경우(두 개 이상의 뷰가 동일한 데이터를 가리키도록 하여 하나가 변경될 때 모두 해당 변경 사항을 가져오려면) 구조체보다 클래스를 사용해야 함.

 

@State

@State를 사용하면 SwiftUI에 속성의 변경 사항을 감시하도록 요청을 한다. 문자열을 변경하고, true/false 값을 반대로 변경하고, 배열에 추가하는 등의 작업을 수행하면 속성이 변경되고 @State의 요청으로 SwiftUI는 뷰의 body 속성을 다시 호출하게 된다. (User가 구조체였을 때 해당 구조체의 속성을 수정할 때마다 Swift는 구조체의 새 인스턴스를 생성하게됨.)

 

왜 클래스 속성이 변경될 때 화면에 변경된 사항이 반영되지 않은걸까? 

User가 클래스일 때 속성 자체는 변경되지 않으므로 @State는 아무 것도 알아차리지 못하고 뷰를 다시 로드할 수 없게됨. 클래스 내부의 값이 변경되고 있지만 @State는 이를 모니터링하지 못함. 클래스 내부의 값이 변경되지만 클래스 속성의 값인 주소 자체가 변하는것은 아니기 때문에 해당 변경 사항을 반영하기 위해 뷰가 다시 로드되지 않는다는 것입니다.

 

어떻게 해야 하나?

클래스의 변경을 알아차리고 다시 뷰를 로드할 수 있도록 해당 클래스에 @Observable 키워드를 붙여준다

클래스 내의 속성에 변경 사항이 있는지 관찰함. 변경된 속성에 대해서만 업데이트를 함.

 

 

Showing and hiding views

버튼을 클릭하여 다른 sheet를 볼 수 있는 기능 만들기

import SwiftUI

struct SeconView: View {
    var body: some View {
        Text("Second View")
    }
}

struct Tutorial3: View {
    @State private var showingSheet = false
    
    var body: some View {
        Button("Show sheet") {
            showingSheet.toggle()
        }
        .sheet(isPresented: $showingSheet) {
            SeconView()
        }
    }
}

 

 

새로 열린 sheet 을 닫기 버튼으로 구현하기

환경변수 @Environment(\.dismiss) var dismiss 를 설정하여 버튼에 달아준다.

struct SeconView: View {
    @Environment(\.dismiss) var dismiss
    let name: String
    
    var body: some View {
        VStack {
            Text("Hello, \(name)!")
            Button("dismiss") {
                dismiss()
            }
            .padding(.top, 30)
        }
    }
}

 

 

Deleting items using onDelete()

ForEach로 동적으로 row 만든 후 삭제하기

ForEach는 해당 indexSet를 배열에 직접 전달. 이것을 이용하여 해당 배열을 삭제함.

offset에 대해서 추가적으로 이 블로그 보기

https://blog.canapio.com/109

 

struct Tutorial4: View {
    @State private var numbers = [Int]()
    @State private var currentNumber = 1
    
    var body: some View {
        NavigationStack {
            VStack {
                List {
                    ForEach (numbers, id: \.self){
                        Text("Row \($0)")
                    }
                    .onDelete(perform: { indexSet in
                        removeRows(at: indexSet)
                    })
                }
                
                Button("Add number") {
                    numbers.append(currentNumber)
                    currentNumber += 1
                }
            }
            .toolbar {
                EditButton()
            }
        }
    }
    
    func removeRows(at offsets: IndexSet ) {
        numbers.remove(atOffsets: offsets)
    }
}

 

 

'Swift & SwiftUI' 카테고리의 다른 글

Simple Task App  (0) 2023.12.21
CS 193p Lecture 3~4 정리  (0) 2023.11.22
Networking for beginners  (0) 2023.10.11
Optional Binding, Chaining  (0) 2023.10.09
사용자의 위치정보 가져오기  (0) 2023.10.05