기어가더라도 제대로

[SwiftUI-기초] 양방향 바인딩(two-way binding), ForEach 본문

SwiftUI - 기초

[SwiftUI-기초] 양방향 바인딩(two-way binding), ForEach

Damagucci-juice 2022. 10. 6. 00:01

UI에서 얻는 값을 저장 - 양방향 결합(two-way binding)

오류 예제 코드

  • 이 코드는 오류를 뱉음
  • TextField 에서 얻을 값을 저장할 공간을 만들어 주지 않았기 때문
  • struct 내부에 텍스트 필드에서 얻은 값을 저장할 property가 필요
  • 다음과 같이 선언해주었는데 과연 될까?
struct ContentView: View {
    @State private var name = ""

    var body: some View {
        Form {
            TextField("Enter your name", text: name)
            Text("Hello, world!")
        }
    }
}
  • 이것도 오류를 냄
  • 이는 Swift 가 property 의 기능을 다르게 두었음
    • "property 의 값을 여기에 보여주세요"
      • 저번 튜토리얼에서 button 의 text 가 변경되는 경우
    • "property의 값을 여기에 보여는 주는데요, 만약 변경사항이 생기면 다시 property에 써주세요."
      • 위의 예제의 경우
  • 이를 two-way binding 이라고 함
    • text field 에 name 속성을 보여주고
    • text field 에서 일어나는 변경사항을 name property 에 업데이트함
  • 이 특별한 binding 을 "$" 표시로 한다.
    • "프로퍼티에서 값을 읽고요, 변경사항이 생기면 그 프로퍼티에 다시 써주세요" 라고 swift 에게 전하는 약속
struct ContentView: View {
    @State private var name = ""

    var body: some View {
        Form {
            TextField("Enter your name", text: $name)
            Text("Your name is \(name)")
        }
    }
}
  • name 과 $name의 차이점
    • 양방향 바인딩을 여기서 하겠다 -> $name
    • 양방향 바인딩을 여기서 하지 않겠다.  -> name
      • Text 는 변경될 일이 없기 때문

 

반복문 안에서 view 생성

여기서 주인공은 ForEach 입니다.

  • 범위나 배열을 돌면서 뷰를 만드는 작업을 반복할 수 있다.
  • 10 개 view 제한에도 걸리지 않는다. (직접 타이핑 하면 걸림, 10개 이상 생성할 수 있다는 뜻)
  • 범위나 배열과 하나의 요소를 넘겨받았을 때 실행할 클로저도 같이 넘긴다. 

Picker 뷰와 함께 사용되는 예시

  1. 이름의 배열이 있습니다.
  2. 현재 선택된 학생의 이름을 저장하는 @State 변수가 있습니다.(기본값은 "Harry")
  3. 사용자에게 가장 좋아하는 학생을 고르도록 Picker 뷰를 생성하고 양방향 바인딩으로 @State property 에게 연결합니다. 
  4. ForEach 를 사용해 모든 학생의 이름이 반복해서 Text 뷰에 나타나도록 합니다. 
struct ContentView: View {
    let students = ["Harry", "Hermione", "Ron"]
    @State private var selectedStudent = "Harry"

    var body: some View {
        NavigationView {
            Form {
                Picker("Select your student", selection: $selectedStudent) {
                    ForEach(students, id: \.self) {
                        Text($0)
                    }
                }
            }
        }
    }
}
  • selectedStudent 변수는 기본값이 "Herry" 이긴 하지만 변경 가능성이 있으므로 @State 프로퍼티 래퍼를 붙입니다.
  • Picker 는 label 을 갖는데 사용자에게 무엇을 할지 알려주고, Screen reader 가 읽는 정보를 제공합니다. 
  • Picker 는 selectedStudent와 양방향 바인딩 되어있습니다. 
  • ForEach 내부에서 모든 학생의 이름을 반복합니다. 
  • 학생의 이름마다 Text 뷰를 생성해 학생의 이름을 보여줍니다. 

여기까진 쉬우리라 생각합니다. 

근데 id: \.self  가 낯설어 보입니다. 

  • SwiftUI 가 뷰가 변경되면 감지할 id 
  • 모든 뷰를 고유하게 인식하는데 도움을 줌
    • "Ron" 을 이름 배열에서 가장 앞으로 가져다 놓으면, SwiftUI 도 그에 맞춰 뷰를 생성
    • 각각의 항목을 구별할 수 있도록 지정해줘야합니다. 
  • ForEach(students, id: \.self) 의 해석
    • students 속성을 쓸 건데
    • 이 속성의 요소들의 고유한 요소가 그 자체야.
  • 만약 student 가 단순한 문자열의 배열이 아니라 Student 같은 struct 였다면, 학번이 있을 수 있고, 이름이 있을 수 있는데, 
  • 그 구조체의 고유한 식별자를 선언하는 것이라고 보면 됨
  • 여기서는 단순한 문자열이기 때문에 그 자체가 (\.self) 고유한 식별자라고 알려주는 상황
  • SwiftUI 는 ForEach 를 하면 "어떤 식별자가 문자열 배열에서 각 항목 아이템을 유일하게 해주는가"를 묻는데
  • 여기에 "string 그자체로 유일해요" 라고 답하는 모양새
  • 만약 문자열 배열에 중복되는 값이 있으면 문제 가능성이 있음
Comments