ตัวอย่างสถานะการผูก SwiftUI + นี้จัดการให้ทำงานได้อย่างไรโดยไม่ต้องเรียกใช้เนื้อความซ้ำ
เพื่อนร่วมงานคนหนึ่งมาพร้อมกับตัวอย่าง 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
?
คำตอบ
ในกลไกการแสดงผล SwiftUI ของการเปลี่ยนสถานะในตอนแรกจะตรวจสอบความเท่าเทียมกันของมุมมองภายในร่างกายและหากบางส่วนไม่เท่ากันให้เรียกใช้ร่างกายเพื่อสร้างใหม่ แต่เฉพาะมุมมองที่ไม่เท่ากัน ในกรณีของคุณไม่มีมุมมองใดขึ้นอยู่กับ (เป็นค่า) กับtext
มูลค่า (การผูกก็เหมือนกับการอ้างอิง - เหมือนกัน) ดังนั้นจึงไม่มีอะไรที่ต้องสร้างใหม่ในระดับนี้ แต่ข้างในWrappedText
ตรวจพบว่าText
ใหม่text
ไม่เท่ากับอันเก่าtext
ดังนั้น body of WrappedText
จึงถูกเรียกให้ re-render ส่วนนี้
นี่เป็นการประกาศการเพิ่มประสิทธิภาพการแสดงผลของ SwiftUI - โดยการตรวจสอบและตรวจสอบความถูกต้องของมุมมองที่เปลี่ยนแปลงโดยความเท่าเทียมกัน
โดยค่าเริ่มต้นกลไกนี้ทำงานโดยคุณสมบัติ View struct แต่เราสามารถมีส่วนร่วมได้โดยการยืนยันมุมมองของเราต่อEqatable
โปรโตคอลและทำเครื่องหมาย.equatable()
ตัวปรับแต่งเพื่อให้ตรรกะที่ซับซ้อนมากขึ้นสำหรับการตรวจจับว่า View ควรจะแสดง (หรือไม่) อีกครั้ง