body: คืออะไร, computed property ของ View ใน SwiftUI

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-06-24 เวลาอ่าน: 7 นาที

คุณสมบัติ body เป็นองค์ประกอบหลักของโปรโตคอล View ใน SwiftUI ซึ่งกำหนดว่าเนื้อหาใดที่จะแสดงบนหน้าจอ ตาม Apple Developer Documentation, 2024 body เป็นข้อกำหนดบังคับเพียงอย่างเดียวของโปรโตคอล View และส่งคืนบางประเภทที่สอดคล้องกับโปรโตคอลเดียวกันนี้ SwiftUI เรียกใช้ body ทุกครั้งที่มีการเปลี่ยนแปลงสถานะเพื่อสร้างและเปรียบเทียบแผนผังองค์ประกอบใหม่

ประเด็นสำคัญ

  • body เป็นคุณสมบัติที่คำนวณได้ซึ่งจำเป็นสำหรับทุกประเภทที่ใช้งานโปรโตคอล View
  • some View เป็นประเภทการส่งคืนแบบทึบแสงที่ช่วยให้ SwiftUI ปรับการเรนเดอร์ให้เหมาะสม
  • body ถูกเรียกทุกครั้งที่มีการเปลี่ยนแปลงสถานะแต่ต้องไม่มีผลข้างเคียง
  • ViewBuilder ห่อหุ้ม body โดยนัยถ้ามันส่งคืนหลายองค์ประกอบ
  • body จะไม่ถูกเรียกถ้าเอกลักษณ์และสถานะของ View ไม่เปลี่ยนแปลง

body ใน SwiftUI คืออะไร?

body เป็นคุณสมบัติที่คำนวณได้ซึ่งเป็นข้อกำหนดบังคับเพียงอย่างเดียวของโปรโตคอล View ทุกโครงสร้างที่สอดคล้องกับ View ต้องใช้งาน body คุณสมบัตินี้ส่งคืนเนื้อหาที่ SwiftUI แสดงบนหน้าจอ — อาจเป็นข้อความ รูปภาพ ปุ่ม ภาชนะที่มีองค์ประกอบซ้อนกัน หรือประเภทอื่นใดที่สอดคล้องกับโปรโตคอล View

ลายเซ็นของ body คงที่เสมอ: var body: some View { get } ประเภทการส่งคืนคือ some View (ประเภททึบแสง) ไม่ใช่ประเภทที่เป็นรูปธรรม ซึ่งหมายความว่า Views ที่แตกต่างกันสามารถส่งคืนประเภทที่เป็นรูปธรรมที่แตกต่างกันใน body ได้ แต่คอมไพเลอร์ Swift จะกำหนดประเภทที่เป็นรูปธรรมสำหรับแต่ละการใช้งานในเวลาคอมไพล์

ตาม WWDC 2022 body คือจุดเริ่มต้นสำหรับคำอธิบายอินเทอร์เฟซแบบประกาศ ต่างจาก UIKit ที่คุณสร้างและกำหนดค่า UIView ตามคำสั่ง ใน SwiftUI คุณอธิบายสิ่งที่ควรแสดงในลักษณะประกาศ และ SwiftUI จะคำนวณวิธีใช้งานด้วยตัวเอง

body เป็นฟังก์ชันบริสุทธิ์

body ควรทำงานเป็น ฟังก์ชันบริสุทธิ์ — ด้วยอินพุตเดียวกัน (คุณสมบัติของโครงสร้างและสถานะ) ควรส่งคืนแผนผัง View เดียวกัน ถ้า body ขึ้นอยู่กับสถานะที่เปลี่ยนแปลงได้ภายนอก (ตัวแปรส่วนกลาง UserDefaults โดยไม่มีตัวห่อ @AppStorage) พฤติกรรมจะคาดเดาไม่ได้และ SwiftUI อาจวาดหน้าจอใหม่ไม่ถูกต้อง

คุณสมบัติที่คำนวณได้ body ทำงานอย่างไร

คุณสมบัติที่คำนวณได้ body ไม่ได้เก็บค่า — มันถูกคำนวณทุกครั้งที่เข้าถึง เมื่อ SwiftUI กำหนดว่าสถานะเปลี่ยนแปลงแล้ว มันจะสร้างโครงสร้าง View ใหม่และอ่านค่าใหม่ของ body เพื่อรับแผนผังองค์ประกอบปัจจุบันสำหรับการแสดงผล

swift
struct CounterView: View {
    @State private var count = 0

    var body: some View {
        VStack {
            Text("ตัวนับ: \(count)")
                .font(.largeTitle)
            Button("เพิ่ม") {
                count += 1
            }
            .padding()
            .background(.blue)
            .foregroundColor(.white)
            .cornerRadius(8)
        }
    }
}

ในตัวอย่างนี้ body ส่งคืน VStack ที่มีข้อความและปุ่มพร้อมตัวปรับแต่ง เมื่อกดปุ่ม คุณสมบัติ @State count จะเพิ่มขึ้น SwiftUI จะสร้างโครงสร้าง CounterView ใหม่และเรียกใช้ body อีกครั้งเพื่อรับแผนผังที่อัปเดตด้วยค่าข้อความใหม่

ตัวปรับแต่ง (.font, .padding, .background, .foregroundColor, .cornerRadius) ไม่ได้แก้ไข View ดั้งเดิม แต่ห่อหุ้มมันใน ModifiedContent — ประเภทใหม่ที่เพิ่มการปรับแต่ง ตัวปรับแต่งแต่ละตัวสร้างระดับการซ้อนอีกหนึ่งระดับ ซึ่งสำคัญที่ต้องพิจารณาสำหรับประสิทธิภาพ

body และประเภททึบแสง some View

some View ในประเภทการส่งคืนของ body ไม่ใช่แค่ธรรมเนียมแต่เป็นข้อกำหนดของคอมไพเลอร์ Swift ต้องการให้เส้นทางการส่งคืนทั้งหมดใน body มี ประเภทที่เป็นรูปธรรมเดียวกัน หากไม่มี @ViewBuilder คุณไม่สามารถส่งคืน Text ในสาขาหนึ่งและ Button ในอีกสาขาหนึ่ง — คอมไพเลอร์จะแจ้งข้อผิดพลาด

swift
struct ConditionalView: View {
    var isReady: Bool

    @ViewBuilder
    var body: some View {
        if isReady {
            Text("พร้อม")
                .foregroundColor(.green)
        } else {
            ProgressView()
        }
    }
}

@ViewBuilder บน body อนุญาตให้ใช้ตรรกะแบบมีเงื่อนไข (if/else, switch) โดยไม่มีข้อผิดพลาดในการคอมไพล์ ViewBuilder จะห่อหุ้มสาขาต่าง ๆ โดยอัตโนมัติใน ConditionalContent — ประเภทพิเศษที่ซ่อนความแตกต่างของประเภทที่เป็นรูปธรรม นี่คือความสามารถสำคัญสำหรับการสร้างอินเทอร์เฟซแบบไดนามิก

หากไม่มี @ViewBuilder คอมไพเลอร์จะพยายามอนุมานประเภทเดียวสำหรับเส้นทางการส่งคืนทั้งหมด ถ้าประเภทแตกต่างกัน — จะเกิดข้อผิดพลาด นี่คือเหตุผลที่ SwiftUI ใช้ @ViewBuilder โดยนัยกับ body ในการประกาศ View แม้ว่าในโค้ดผู้ใช้คุณต้องเพิ่มคำอธิบายประกอบอย่างชัดเจนสำหรับเมธอดและคุณสมบัติที่กำหนดเองที่ส่งคืนหลาย Views

ประสิทธิภาพของ some View

การใช้ some View แทนประเภทที่เป็นรูปธรรมไม่ได้ลดประสิทธิภาพ — คอมไพเลอร์รู้ประเภทที่แน่นอนในเวลาคอมไพล์และสร้างโค้ดโดยตรงโดยไม่ต้องจัดส่งแบบไดนามิก AnyView ในทางกลับกัน ใช้การลบประเภท (type erasure) ด้วยค่าใช้จ่ายในการห่อหุ้มในคอนเทนเนอร์อัตถิภาวนิยม

วงจรชีวิตของ body: เมื่อใดและอย่างไรที่ถูกเรียก

body ถูกเรียกโดย SwiftUI ในสามสถานการณ์หลัก: เมื่อ View ถูกแสดงครั้งแรก เมื่อ @State/@Binding/@ObservedObject/@StateObject เปลี่ยนแปลง และเมื่อ View แม่ส่งค่าใหม่ผ่านตัวเริ่มต้น SwiftUI อาจเรียกใช้ body เมื่อค่าสภาพแวดล้อม (@Environment) เปลี่ยนแปลง

ความถี่ของการเรียก body ไม่ควรทำให้คุณกังวล — SwiftUI ปรับการวาดใหม่ให้เหมาะสมผ่านกลไก เอกลักษณ์ แต่ละ View ในลำดับชั้นมีตัวระบุที่ไม่ซ้ำกัน ถ้าเอกลักษณ์และข้อมูลอินพุตไม่เปลี่ยนแปลง — body จะไม่ถูกเรียกแม้ว่า View แม่จะถูกวาดใหม่ ซึ่งทำได้ผ่านการเปรียบเทียบ Equatable และความเสถียรของโครงสร้าง

swift
struct ParentView: View {
    var body: some View {
        ChildView(name: "Alice") // เอกลักษณ์ที่เสถียร
    }
}

struct ChildView: View {
    let name: String
    var body: some View {
        Text("สวัสดี, \(name)!")
    }
}

ในตัวอย่างนี้ ถ้า ParentView ถูกวาดใหม่แต่ส่งค่า name เดียวกัน — ChildView.body จะไม่ถูกเรียก SwiftUI เปรียบเทียบข้อมูลอินพุตของโครงสร้าง และถ้าไม่เปลี่ยนแปลง จะข้ามการวาดใหม่ของคอมโพเนนต์ลูก นี่คือกลไก การแยกความแตกต่างของมุมมอง

เมื่อ body ถูกเรียกโดยไม่คาดคิด

มีข้อผิดพลาดหลายอย่างที่นำไปสู่การเรียก body โดยไม่คาดคิด: การใช้คลาสโดยไม่มี ObservableObject การส่งคลอเชอร์ที่สร้างขึ้นภายใน body (การสร้างคลอเชอร์แต่ละครั้งให้เอกลักษณ์ใหม่) และการใช้ EquatableView อย่างไม่ถูกต้อง ถ้า body ถูกเรียกบ่อยเกินไป — ตรวจสอบความเสถียรของเอกลักษณ์ของคอมโพเนนต์ลูกทั้งหมด

แนวทางปฏิบัติที่ดีที่สุดในการทำงานกับ body

กฎข้อแรก: body ควรน้อยที่สุด ย้ายตรรกะที่ซับซ้อนไปยังคุณสมบัติที่คำนวณได้หรือเมธอดแยกต่างหากที่ส่งคืน View สิ่งนี้ช่วยเพิ่มความสามารถในการอ่านและช่วยให้ SwiftUI ระบุได้แม่นยำยิ่งขึ้นว่าส่วนใดของลำดับชั้นที่เปลี่ยนแปลง แบ่ง body ขนาดใหญ่ออกเป็นคอมโพเนนต์ย่อยที่มีขอบเขตความรับผิดชอบที่ชัดเจน

กฎข้อที่สอง: อย่าใช้ body เพื่อทำงาน การโหลดข้อมูล การดำเนินการเครือข่าย การเขียนฐานข้อมูล — ทั้งหมดนี้ควรเกิดขึ้นภายนอก body ในงาน (tasks) ตัวปรับแต่ง onChange หรือผ่าน ObservableObject body มีไว้สำหรับการประกาศอินเทอร์เฟซเท่านั้น

กฎข้อที่สาม: ใช้คุณสมบัติ EquatableView หรือโปรโตคอล Equatable ที่กำหนดเองสำหรับ Views ถ้าการเปรียบเทียบโครงสร้างมาตรฐานไม่เพียงพอ สิ่งนี้ช่วยให้คุณบอก SwiftUI อย่างชัดเจนว่าเมื่อใดที่ View ลูกต้องการการวาดใหม่และหลีกเลี่ยงการเรียก body ที่ไม่จำเป็น

กฎข้อที่สี่: ถ้า body มีการคำนวณที่ซับซ้อน (การจัดรูปแบบ การกรอง การเรียงลำดับ) — ใช้ @State สำหรับการแคชผลลัพธ์หรือย้ายการคำนวณไปยังเมธอดแยกที่เรียกจาก onChange การคำนวณซ้ำใน body ทุกครั้งที่อัปเดตสถานะเป็นสาเหตุทั่วไปของภาพเคลื่อนไหวช้า

กฎข้อที่ห้า: สำหรับรายการ (List, ForEach) ให้มั่นใจว่ามี ตัวระบุที่เสถียร ผ่านพารามิเตอร์ id หากไม่มีเอกลักษณ์ที่เสถียร ForEach จะสร้างองค์ประกอบทั้งหมดใหม่เมื่อมีการเปลี่ยนแปลงใด ๆ โดยเรียก body สำหรับแต่ละองค์ประกอบ แม้ว่าจะมีเพียงองค์ประกอบเดียวที่เปลี่ยนแปลง

คำถามที่พบบ่อย

body ใน SwiftUI คืออะไร?

body เป็นคุณสมบัติที่คำนวณได้ของโปรโตคอล View ที่ส่งคืนเนื้อหาสำหรับแสดง เป็นข้อกำหนดบังคับเพียงอย่างเดียวของโปรโตคอล ประเภทการส่งคืนคือ some View ซึ่งช่วยให้ SwiftUI ปรับลำดับชั้นให้เหมาะสมในเวลาคอมไพล์

body สามารถถูกเรียกหลายครั้งได้หรือไม่?

ได้ SwiftUI เรียก body ทุกครั้งที่มีการเปลี่ยนแปลงสถานะ (@State, @Binding, @ObservedObject) หรือข้อมูลอินพุต นี่เป็นพฤติกรรมปกติของเฟรมเวิร์กแบบประกาศ SwiftUI ปรับความถี่การเรียกให้เหมาะสมผ่านกลไกเอกลักษณ์และการเปรียบเทียบ Equatable

ทำไม body ส่งคืน some View แทนที่จะเป็นประเภทที่เป็นรูปธรรม?

some View เป็นประเภททึบแสงที่ซ่อนการใช้งานที่เป็นรูปธรรม คอมไพเลอร์กำหนดประเภทในเวลาคอมไพล์เพื่อให้มั่นใจถึงประสิทธิภาพการเรียกโดยตรง สิ่งนี้ให้ความยืดหยุ่น: คุณสามารถเปลี่ยนประเภทการส่งคืนได้โดยไม่ต้องเปลี่ยนลายเซ็น

สามารถส่งคืน nil จาก body ได้หรือไม่?

ไม่ body ไม่สามารถเป็นทางเลือกได้ — ประเภทการส่งคืน some View ไม่อนุญาตให้เป็น nil ถ้าคุณต้องการซ่อนองค์ประกอบตามเงื่อนไข ให้ใช้ตรรกะแบบมีเงื่อนไขภายใน @ViewBuilder หรือส่งคืน EmptyView ซึ่งไม่ใช้พื้นที่ในลำดับชั้น

จำนวนตัวปรับแต่งส่งผลต่อประสิทธิภาพของ body หรือไม่?

ตัวปรับแต่งแต่ละตัวสร้างชั้น ModifiedContent ใหม่ เพิ่มความลึกของลำดับชั้น สำหรับหน้าจอส่วนใหญ่ (สูงสุด 50 ตัวปรับแต่ง) ผลกระทบไม่มีนัยสำคัญ จำนวนตัวปรับแต่งที่มากเกินไป (หลายร้อย) อาจทำให้การเปรียบเทียบช้าลง จัดกลุ่มตัวปรับแต่งที่เกี่ยวข้องในส่วนขยายที่กำหนดเอง

สรุป

  • body เป็นคุณสมบัติที่คำนวณได้ซึ่งจำเป็นของโปรโตคอล View ที่กำหนดเนื้อหาบนหน้าจอ
  • some View เป็นประเภทการส่งคืนแบบทึบแสงที่ซ่อนการใช้งานที่เป็นรูปธรรมจากโค้ดที่เรียก
  • @ViewBuilder ถูกใช้โดยนัยกับ body เพื่อรองรับตรรกะแบบมีเงื่อนไขและหลายองค์ประกอบ
  • body ต้องไม่มีผลข้างเคียง — เป็นการประกาศอินเทอร์เฟซที่บริสุทธิ์
  • SwiftUI ปรับการเรียก body ให้เหมาะสมผ่านกลไกเอกลักษณ์และการเปรียบเทียบ Equatable
  • แบ่ง body ขนาดใหญ่ออกเป็นคอมโพเนนต์ย่อยเพื่อประสิทธิภาพและความสามารถในการอ่านที่ดีขึ้น
  • AnyView เพิ่มค่าใช้จ่าย — ใช้ @ViewBuilder และ Group แทนการลบประเภท

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม