이 SwiftUI 바인딩 + 상태 예제는 본문을 다시 호출하지 않고 어떻게 작동합니까?

Aug 19 2020

동료는 다음 SwiftUI 예를 내놓았다 외모 가 그냥 기대 작품처럼 (일부 텍스트를 입력 할 수 있으며이 아래 미러링됩니다)하지만, 어떻게 작동 나에게 놀라운 일이다!

import SwiftUI

struct ContentView: View {
    @State var text = ""
    var body: some View {
        VStack {
            TextField("Change the string", text: $text) WrappedText(text: $text)
        }
    }
}

struct WrappedText: View {
    @Binding var text: String
    var body: some View {
        Text(text)
    }
}

SwiftUI의 초보 정신 모델은 TextField에 입력하면 $text바인딩 이 변경 되어 text@State var 가 변경 될 것이라고 생각 하게되었습니다 . 그러면을 무효화하여을 ContentView새로 호출 body합니다. 그러나 흥미롭게도 그것은 일어나는 일이 아닙니다! ContentView의 중단 점 설정 body은 한 번만 적중되는 반면 WrappedText body는 바인딩이 변경 될 때마다 실행됩니다. 하지만 제가 말할 수있는 한, text상태는 정말로 변하고 있습니다.

그래서 여기서 무슨 일이 일어나고 있습니까? SwiftUI가 변경 될 때마다 ContentView의 본문을 다시 호출하지 않는 이유는 무엇 text입니까?

답변

1 Asperi Aug 20 2020 at 04:04

상태 변경시 SwiftUI 렌더링 엔진은 처음에 body 내부의 뷰가 같은지 확인하고, 일부가 같지 않으면 body를 호출하여 다시 빌드하지만 같지 않은 뷰만 호출합니다. 귀하의 경우 아무도 (값으로) 값에 의존하지 않으므로 text(바인딩은 참조와 같으며 동일합니다)이 수준에서 다시 빌드 할 것이 없습니다. 그러나 내부 에서 new 는 old와 같지 않다는 WrappedText것이 감지 되었으므로 body는 이 부분을 다시 렌더링하도록 호출됩니다.TexttexttextWrappedText

이것은 SwiftUI의 렌더링 최적화로 선언되었습니다.-정확하게 변경된 뷰를 동등하게 확인하고 검증합니다.

기본적으로이 메커니즘은 View 구조체 속성에 의해 작동하지만, Eqatable프로토콜에 대한 뷰를 확인하고 뷰를 .equatable()다시 렌더링해야하는지 여부를 감지하기위한 좀 더 복잡한 로직을 제공하기 위해 수정자를 표시 하여 참여할 수 있습니다 .