ViewController — แก่นของตัวควบคุมหน้าจอใน iOS และ Lifecycle ของมัน

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

UIViewController เป็นคลาสหลักของแอปพลิเคชัน iOS ที่จัดการหน้าจอและเนื้อหาของมัน ทุกหน้าจอของ iPhone หรือ iPad ถูกจัดการโดย ViewController หนึ่งตัว ซึ่งประสานงานการแสดงผล วงจรชีวิต และการนำทาง อ่านเพิ่มเติมเกี่ยวกับสถาปัตยกรรม UIKit ได้ใน เอกสารทางการของ Apple

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

  • UIViewController — คลาสพื้นฐานสำหรับจัดการหน้าจอใน UIKit พร้อมวงจรชีวิตของตัวเอง
  • viewDidLoad — ถูกเรียกครั้งเดียว จุดเริ่มต้น UI และการสมัครรับข้อมูล
  • viewWillAppear — หน้าจอจะปรากฏเร็วๆ นี้ อัปเดตข้อมูลก่อนการแสดงผล
  • Lifecycle ประกอบด้วยห้าเมธอด: viewDidLoad, viewWillAppear, viewDidAppear, viewWillDisappear, viewDidDisappear
  • Massive View Controller — แอนติแพทเทิร์นหลักของ iOS แก้ไขได้ผ่าน MVVM หรือ Coordinator

ViewController คืออะไร?

UIViewController เป็นคลาสจากเฟรมเวิร์ก UIKit ที่จัดการลำดับชั้นของ UIView และประสานงานการแสดงผลข้อมูลบนหน้าจอ ทุกแอปพลิเคชัน iOS มี ViewController อย่างน้อยหนึ่งตัว — ตัวควบคุมรากของหน้าต่าง ตัวควบคุมจัดการการหมุนหน้าจอ การเปลี่ยนระหว่างหน้าจอ และเหตุการณ์วงจรชีวิต

สถาปัตยกรรม MVC (Model-View-Controller) ใน iOS ถูกนำไปใช้ผ่าน UIViewController อย่างแม่นยำ: ตัวควบคุมรับข้อมูลจากโมเดลและอัปเดตมุมมอง ViewController ไม่ใช่องค์ประกอบที่มองเห็นได้ — มันจัดการคุณสมบัติ view ซึ่งมีลำดับชั้นของ subview ตามข้อมูลของ Apple (2026) UIKit มีคลาสย่อย UIViewController ในตัวมากกว่า 40 คลาส

iPhone SDK แรก (2008) มี UIViewController พร้อมเมธอดวงจรชีวิตสามเมธอด ในช่วง 18 ปี Apple ได้เพิ่มการสนับสนุน Container View Controller การนำเสนอแบบปรับได้ UIViewControllerTransitioningDelegate สำหรับแอนิเมชันแบบกำหนดเอง และโหมดหน้าจอแบ่งบน iPad UIViewController ยังคงเป็นส่วนประกอบบังคับสำหรับแอปพลิเคชัน UIKit

วงจรชีวิตของ UIViewController

วงจรชีวิตของ UIViewController คือลำดับของเมธอดที่ถูกเรียกโดยระบบเมื่อสร้าง แสดง และซ่อนหน้าจอ การทำความเข้าใจ Lifecycle มีความสำคัญอย่างยิ่ง: การวางโค้ดผิดตำแหน่งนำไปสู่การรั่วไหลของหน่วยความจำ คำขอเครือข่ายที่ไม่จำเป็น และการกระพริบของอินเทอร์เฟซ

เมธอดช่วงเวลาที่เรียกวัตถุประสงค์
viewDidLoadหนึ่งครั้ง หลังจาก view ถูกโหลดเข้าสู่หน่วยความจำการตั้งค่า UI เริ่มต้น การสมัครรับ Combine
viewWillAppearก่อนที่หน้าจอจะปรากฏอัปเดตข้อมูล ซ่อน/แสดงแถบนำทาง
viewDidAppearหลังจากหน้าจอปรากฏเริ่มแอนิเมชัน การวิเคราะห์ อัปเดตกล้อง
viewWillDisappearก่อนออกจากหน้าจอบันทึกร่าง ยกเลิกการสมัครรับการแจ้งเตือน
viewDidDisappearหลังจากออกจากหน้าจอหยุดกระบวนการหนัก ปลดปล่อยทรัพยากร

ลำดับการเรียกเมื่อหน้าจอปรากฏ

เมื่อหน้าจอแสดงครั้งแรก ลำดับคือ: init → loadView → viewDidLoad → viewWillAppear → viewDidAppear เมื่อปรากฏอีกครั้ง (กลับจากหน้าจออื่น): viewWillAppear → viewDidAppear viewDidLoad ถูกเรียกเพียงครั้งเดียวตลอดอายุของตัวควบคุม

viewDidLoad, init และการตั้งค่า UI

เมธอด viewDidLoad เป็นจุดหลักในการกำหนดค่าส่วนติดต่อผู้ใช้ มันถูกเรียกหลังจาก view ถูกโหลดเข้าสู่หน่วยความจำ เมื่อการเชื่อมต่อ IBOutlet ทั้งหมดถูกสร้างขึ้นแล้ว ที่นี่องค์ประกอบ UI ถูกสร้างขึ้นโดยโปรแกรม ข้อจำกัดถูกกำหนดค่า และข้อมูลเริ่มต้นถูกโหลด

swift
final class ProfileViewController: UIViewController {

    private let tableView = UITableView()
    private let viewModel = ProfileViewModel()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
        bindViewModel()
    }

    private func setupUI() {
        view.addSubview(tableView)
        tableView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
        tableView.register(ProfileCell.self,
                         forCellReuseIdentifier: ProfileCell.reuseId)
    }

    private func bindViewModel() {
        viewModel.$user
            .receive(on: DispatchQueue.main)
            .sink { [weak self] user in
                self?.title = user.name
            }
            .store(in: &cancellables)
    }
}

ใน SwiftUI โค้ดนี้เทียบเท่ากับ body ของ View แต่ UIViewController ให้การควบคุมวงจรชีวิตและการปรับแต่งอย่างเต็มที่ bindViewModel ใช้ Combine สำหรับการสมัครรับแบบรีแอกทีฟ — ข้อมูลจะถูกอัปเดตโดยอัตโนมัติเมื่อโมเดลเปลี่ยน

viewWillAppear และการอัปเดตข้อมูล

viewWillAppear ถูกเรียกทุกครั้งก่อนที่หน้าจอจะปรากฏ แม้ว่าจะอยู่ในหน่วยความจำแล้วก็ตาม นี่คือสถานที่สำหรับอัปเดตข้อมูลที่อาจเปลี่ยนแปลงบนหน้าจออื่น: โหลดรายการใหม่ อัปเดตป้ายการแจ้งเตือน กำหนดค่าแถบนำทางสำหรับหน้าจอเฉพาะ

swift
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    // ซ่อนแถบนำทางบนหน้าจอนี้
    navigationController?.setNavigationBarHidden(true, animated: animated)

    // อัปเดตข้อมูลเมื่อกลับจากหน้าจออื่น
    tableView.reloadData()
    badgeLabel.text = "\(CartManager.shared.itemCount)"
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    // การวิเคราะห์: หลังจากที่ผู้ใช้เห็นหน้าจอแล้วเท่านั้น
    AnalyticsService.shared.logScreenView("Profile")
}

ความแตกต่างระหว่าง viewDidLoad และ viewWillAppear มีความสำคัญ: viewDidLoad ทำงานครั้งเดียวและเหมาะสมสำหรับการตั้งค่าแบบคงที่ viewWillAppear ทำงานทุกครั้งที่แสดงหน้าจอและเหมาะสมสำหรับการอัปเดตแบบไดนามิก การวางคำขอเครือข่ายใน viewDidLoad จะทำให้แสดงข้อมูลที่ล้าสมัยเมื่อกลับมาที่หน้าจอ

Container View Controller: UINavigationController และ UITabBarController

Container View Controller คือ ViewController ที่จัดการ ViewController ย่อยหนึ่งตัวหรือมากกว่า Apple มีคอนเทนเนอร์ในตัวสามตัว: UINavigationController (สแต็กหน้าจอ), UITabBarController (แท็บ) และ UISplitViewController (มาสเตอร์-ดีเทลสำหรับ iPad)

UINavigationController จัดระเบียบการเปลี่ยนในสแต็ก — push เพิ่มหน้าจอ pop ลบออก UITabBarController สลับระหว่างส่วนอิสระของแอปพลิเคชัน UISplitViewController แสดงตัวควบคุมสองตัวเคียงข้างกันบน iPad และหนึ่งตัวบน iPhone นักพัฒนาสามารถสร้างคอนเทนเนอร์แบบกำหนดเองผ่าน addChild

swift
// Container View Controller แบบกำหนดเอง
final class ContainerViewController: UIViewController {

    private let sidebarVC = SidebarViewController()
    private let contentVC = ContentViewController()

    override func viewDidLoad() {
        super.viewDidLoad()

        // การเพิ่มตัวควบคุมย่อย
        addChild(sidebarVC)
        view.addSubview(sidebarVC.view)
        sidebarVC.didMove(toParent: self)

        addChild(contentVC)
        view.addSubview(contentVC.view)
        contentVC.didMove(toParent: self)
    }
}

การทำงานที่ถูกต้องกับ Container View Controller ต้องการการเรียก addChild การเพิ่ม view และ didMove(toParent:) ตามลำดับนี้ เมื่อลบ: willMove(toParent: nil), removeFromSuperview, removeFromParent การละเมิดลำดับนำไปสู่การรั่วไหลของหน่วยความจำ

การแก้ปัญหา Massive View Controller ด้วย MVVM และ Coordinator

ปัญหา Massive View Controller เกิดขึ้นเมื่อ UIViewController มีโค้ดหลายร้อยบรรทัดพร้อมตรรกะทางธุรกิจ คำขอเครือข่าย การนำทาง และโค้ด UI Apple รับทราบปัญหาและแนะนำ MVVM (Model-View-ViewModel) พร้อมกับ Coordinator เพื่อแยกการนำทาง

MVVM ย้ายตรรกะทางธุรกิจจากตัวควบคุมไปยัง ViewModel Controller เพียงเชื่อม ViewModel กับ View ผ่าน Combine หรือผู้รับมอบอำนาจ Coordinator แยกตรรกะการนำทาง — การสร้างและการเปลี่ยนระหว่างตัวควบคุม — ออกเป็นคลาสแยกต่างหาก แนวทางนี้ถูกนำมาใช้ในแนวทางปฏิบัติที่ดีที่สุดของ Apple ตั้งแต่ปี 2024

swift
// Coordinator — การจัดการการนำทาง
protocol Coordinator {
    var childCoordinators: [Coordinator] { get set }
    func start()
}

final class MainCoordinator: Coordinator {

    var childCoordinators = [Coordinator]()
    private let navigationController: UINavigationController

    init(navigationController: UINavigationController) {
        self.navigationController = navigationController
    }

    func start() {
        let vc = ListViewController()
        vc.didSelectItem = { [weak self] item in
            self?.showDetail(item)
        }
        navigationController.pushViewController(vc, animated: false)
    }

    private func showDetail(_ item: Item) {
        let vc = DetailViewController(item: item)
        navigationController.pushViewController(vc, animated: true)
    }
}

UIViewController เทียบกับ SwiftUI: เมื่อใดควรเลือกอะไร

การเลือกระหว่าง UIViewController และ SwiftUI View ขึ้นอยู่กับปีเริ่มต้นโครงการ ข้อกำหนดการปรับแต่ง และเวอร์ชัน iOS ขั้นต่ำที่รองรับ UIKit กับ UIViewController ยังคงเป็นพื้นฐานสำหรับโครงการที่เริ่มก่อนปี 2020 และสำหรับแอปพลิเคชันที่มีการปรับแต่งส่วนต่อประสานอย่างลึกซึ้ง

SwiftUI เหมาะสำหรับโครงการใหม่ที่มี iOS 17+ ส่วนต่อประสานมาตรฐาน และต้นแบบ อย่างไรก็ตาม การเปลี่ยนแบบกำหนดเอง การทำงานกับกล้อง MapKit แอนิเมชัน CALayer ที่ซับซ้อนจำเป็นต้องใช้ UIViewController Apple แนะนำให้รวมแนวทางผ่าน UIHostingController (SwiftUI ภายใน UIKit) และ UIViewRepresentable (UIKit ภายใน SwiftUI)

สถานการณ์UIKit (UIViewController)SwiftUI (View)
แอนิเมชันแบบกำหนดเองควบคุมเต็มที่ผ่าน UIViewPropertyAnimatorจำกัดผ่าน Animation
การทำงานกับกล้องAVCaptureSession + UIViewPreviewผ่าน UIViewControllerRepresentable
CollectionViewUICollectionView + UICollectionViewLayoutLazyVGrid/LazyHGrid
การปรับ iPadUISplitViewController + UITraitCollectionNavigationSplitView + sizeClass
ความเร็วในการพัฒนาช้ากว่า (เลย์เอาต์ด้วยตนเอง)เร็วกว่า (declarative)

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

UIViewController แตกต่างจาก UIView อย่างไร?

UIViewController คือตัวควบคุมที่จัดการหน้าจอและวงจรชีวิตของมัน UIView คือมุมมองที่แสดงเนื้อหา ViewController มีลำดับชั้นของ UIViews แต่ตัวมันเองไม่ใช่องค์ประกอบที่มองเห็นได้ ตัวควบคุมหนึ่งตัวจัดการหลายมุมมอง

Massive View Controller คืออะไร?

Massive View Controller คือแอนติแพทเทิร์นที่ UIViewController มีตรรกะมากเกินไป: ข้อมูล การนำทาง คำขอเครือข่าย แอนิเมชัน วิธีแก้ไข — แยกโค้ดออกเป็นบริการ ผู้ประสานงาน และ ViewModel (MVVM) แยกต่างหาก

วิธีการส่งข้อมูลระหว่าง ViewControllers?

สี่วิธี: ผ่านคุณสมบัติใน prepare(for:sender:) (Segue), ผ่านผู้รับมอบอำนาจ (Delegate), ผ่านคลosure (Closure), ผ่านบริการที่ใช้ร่วมกัน สำหรับการเชื่อมต่อแบบหลวมๆ ให้ใช้ Coordinator + Delegate หรือ Combine

Container View Controller คืออะไร?

Container View Controller คือตัวควบคุมที่จัดการ ViewController ย่อย ตัวอย่าง: UINavigationController, UITabBarController, UISplitViewController ตัวควบคุมหลักเพิ่มลูกผ่าน addChild สลับระหว่างพวกเขา และจัดการเลย์เอาต์ของพวกเขา

เมื่อใดควรใช้ UIViewController แทน SwiftUI View?

UIViewController — สำหรับแอนิเมชันแบบกำหนดเองที่ซับซ้อน การทำงานกับกล้อง แผนที่ วิดีโอ UICollectionView ที่มีเลย์เอาต์แบบกำหนดเอง SwiftUI View — สำหรับส่วนต่อประสานมาตรฐานบน iOS 13+ การรวมผ่าน UIHostingController เป็นที่ยอมรับได้

สรุป

  • UIViewController — คลาส UIKit กลางสำหรับจัดการหน้าจอ ลำดับชั้น UIView และวงจรชีวิต
  • Lifecycle ประกอบด้วยห้าเมธอด: viewDidLoad, viewWillAppear, viewDidAppear, viewWillDisappear, viewDidDisappear
  • viewDidLoad — จุดตั้งค่า UI เริ่มต้น ถูกเรียกครั้งเดียวตลอดอายุของตัวควบคุม
  • viewWillAppear — ถูกเรียกทุกครั้งก่อนการแสดงผล เหมาะสำหรับอัปเดตข้อมูลและกำหนดค่าแถบนำทาง
  • Container View Controller (UINavigationController, UITabBarController) จัดการลำดับชั้นของตัวควบคุมย่อย
  • Massive View Controller แก้ไขได้ผ่าน MVVM (แยกตรรกะไปยัง ViewModel) และ Coordinator (แยกการนำทาง)
  • UIViewController และ SwiftUI สามารถรวมกันได้ผ่าน UIHostingController และ UIViewRepresentable สำหรับแอปพลิเคชันแบบไฮบริด

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

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

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

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