viewDidLoad trong iOS: nó là gì, mục đích và ví dụ mã

Tác giả: IT Sectr Đã đăng: 2026-03-05 Thời gian đọc: 8 phút

viewDidLoad là phương thức đầu tiên mà UIKit gọi sau khi tải View của UIViewController vào bộ nhớ. Theo Apple Developer Documentation, phương thức này được gọi đúng một lần trong suốt thời gian tồn tại của controller. viewDidLoad là nơi chính để thiết lập giao diện ban đầu, đăng ký cell và khởi tạo dữ liệu.

Những điểm chính

  • viewDidLoad được gọi một lần sau khi tải View vào bộ nhớ
  • super.viewDidLoad là bắt buộc — nếu thiếu nó, Lifecycle bị hỏng
  • Trong phương thức này, bạn cấu hình UI, đăng ký cell và tạo data source
  • Không được gọi lại khi quay lại màn hình — sử dụng viewWillAppear
  • Phù hợp cho các thao tác một lần và đăng ký nhận thông báo vĩnh viễn

viewDidLoad là gì

viewDidLoad là một phương thức instance của UIViewController mà UIKit gọi ngay sau khi View của controller được tải vào bộ nhớ. Tại thời điểm này, tất cả các thuộc tính IBOutlet đã được kết nối với các thành phần giao diện, nhưng View chưa được thêm vào hệ thống phân cấp cửa sổ và chưa hiển thị cho người dùng. Nhà phát triển ghi đè phương thức này để thực hiện cấu hình màn hình ban đầu.

Phương thức này là một phần của ViewController Lifecycle và xuất hiện ngay sau loadView nếu View được tạo theo chương trình, hoặc sau khi tải từ Storyboard. Trong một dự án điển hình, viewDidLoad là phương thức được ghi đè thường xuyên nhất của UIViewController, vì nó cung cấp một điểm an toàn để làm việc với các subview đã tồn tại và sẵn sàng để cấu hình.

Một chi tiết quan trọng: tại thời điểm viewDidLoad được gọi, kích thước của View chưa tương ứng với kích thước cuối cùng — Auto Layout chưa hoàn thành các lượt xử lý và frame có thể khác so với dự kiến. Đối với các tính toán phụ thuộc vào kích thước, hãy sử dụng viewDidLayoutSubviews.

Khi nào viewDidLoad được gọi

Thời điểm gọi viewDidLoad phụ thuộc vào cách controller được khởi tạo. Trong hầu hết các trường hợp, UIKit tự động gọi phương thức này khi thuộc tính view của controller được truy cập lần đầu tiên — đây được gọi là cơ chế lazy-loading của UIViewController.

Khi màn hình xuất hiện lần đầu

Khi NavigationController hoặc TabBarController hiển thị màn hình của bạn lần đầu tiên, UIKit kiểm tra xem View đã được tải chưa. Nếu chưa — loadView được gọi (hoặc tải từ Storyboard), sau đó viewDidLoad được kích hoạt ngay lập tức. Đây là kịch bản tiêu chuẩn và nó xảy ra một lần cho mỗi instance controller.

swift
override func viewDidLoad() {
    super.viewDidLoad()
    print("View đã được tải — bạn có thể cấu hình giao diện")
    setupUI()
    configureTableView()
}

Khi quay lại màn hình hiện có

viewDidLoad không được gọi lại khi quay lại màn hình qua nút back hoặc dismiss. Nếu logic của bạn phụ thuộc vào việc màn hình xuất hiện lại — hãy đặt nó trong viewWillAppear. Đây là một trong những lỗi khái niệm phổ biến nhất: các nhà phát triển mong đợi viewDidLoad sẽ kích hoạt mỗi lần hiển thị, nhưng UIKit chỉ gọi nó một lần.

Khi forcedViewLoad

Đôi khi các nhà phát triển truy cập cưỡng bức vào view của controller để kích hoạt tải trước: let _ = controller.view. Điều này buộc loadView và viewDidLoad được gọi trước khi controller xuất hiện trên màn hình. Kỹ thuật này được sử dụng khi bạn cần chuẩn bị View trước để chuyển tiếp mượt mà.

Nên làm gì trong viewDidLoad

viewDidLoad được dành cho các thao tác thiết lập một lần không phụ thuộc vào việc màn hình có hiển thị hay không. Sử dụng đúng phương thức này là chìa khóa cho kiến trúc sạch và hành vi controller có thể dự đoán trước.

Cấu hình thành phần UI

Trong viewDidLoad, bạn đăng ký các tệp nib và lớp cho UITableView và UICollectionView, cấu hình delegate và đặt giá trị ban đầu cho các thuộc tính của thành phần UI. Vì tất cả IBOutlet đã được kết nối tại thời điểm này, bạn có thể truy cập an toàn label.text, imageView.image và các thuộc tính subview khác.

swift
override func viewDidLoad() {
    super.viewDidLoad()
    tableView.dataSource = self
    tableView.delegate = self
    tableView.register(
        CustomCell.self,
        forCellReuseIdentifier: CustomCell.identifier
    )
    title = "Màn hình chính"
}

Khởi tạo dữ liệu và đăng ký

Ở đây bạn tạo viewModel, khởi tạo data source với các mảng và đăng ký nhận thông báo cần hoạt động trong suốt thời gian tồn tại của controller. Ví dụ, đăng ký UIApplication.willEnterForegroundNotification để cập nhật dữ liệu khi quay lại từ nền là một ứng cử viên tốt cho viewDidLoad. ViewModel trong kiến trúc iOS hiện đại hoạt động như cầu nối giữa controller và logic nghiệp vụ, và khởi tạo nó trong viewDidLoad đảm bảo dữ liệu sẵn sàng khi màn hình xuất hiện lần đầu tiên.

Hãy đặc biệt chú ý đến việc cấu hình data source cho bảng và bộ sưu tập. Nếu bảng của bạn sử dụng UIFetchedResultsController hoặc NSFetchedResultsController với Core Data, hãy khởi tạo fetch request và delegate trong viewDidLoad. Điều này đảm bảo rằng khi màn hình xuất hiện lần đầu tiên, bảng sẽ đã được điền dữ liệu mà không cần yêu cầu bổ sung.

Thiết lập điều hướng

Trong viewDidLoad, bạn cấu hình các nút NavigationBar, thiết lập large title, thêm search controller và đặt các nút edit/done. Các thành phần này hiếm khi thay đổi khi màn hình được hiển thị lại, vì vậy khởi tạo chúng ở đây là tối ưu.

Không nên làm gì trong viewDidLoad

Không phải tất cả các thao tác đều phù hợp trong viewDidLoad. Một số hành động đặt trong phương thức này dẫn đến tiêu thụ bộ nhớ quá mức, hành vi không chính xác hoặc lỗi khi màn hình được hiển thị lại.

Tránh bắt đầu các yêu cầu mạng mà kết quả chỉ ảnh hưởng đến UI. Nếu yêu cầu hoàn thành trước khi màn hình xuất hiện, người dùng sẽ không thấy kết quả và nếu hoàn thành sau — dữ liệu có thể đã lỗi thời. Bắt đầu tải trong viewDidLoad, nhưng cập nhật UI trong viewWillAppear.

Không thực hiện các thao tác trong viewDidLoad phụ thuộc vào kích thước và vị trí của View. Tại thời điểm gọi, Auto Layout chưa hoàn thành các lượt xử lý và frame có thể chưa phải là cuối cùng. Đối với các tính toán, hãy sử dụng viewDidLayoutSubviews hoặc ghi đè updateViewConstraints.

Không đăng ký các thông báo chỉ có liên quan khi màn hình hiển thị. Thông báo bàn phím, thông báo thay đổi nội dung từ các controller con — hãy đăng ký chúng trong viewWillAppear và hủy đăng ký trong viewDidDisappear để tránh các cuộc gọi không cần thiết và rò rỉ.

Không gọi các phương thức yêu cầu màn hình hiển thị. Ví dụ, cố gắng hiển thị UIAlertController từ viewDidLoad sẽ gây ra lỗi vì View của controller chưa được thêm vào hệ thống phân cấp cửa sổ. Bất kỳ thao tác UI nào phụ thuộc vào window hoặc presentedViewController chỉ nên được thực hiện sau khi màn hình xuất hiện.

Không khởi tạo tài nguyên nặng một cách không cần thiết. Nếu màn hình hiếm khi được hiển thị hoặc dữ liệu không được hiển thị ngay lập tức, hãy hoãn việc tạo các đối tượng tốn tài nguyên cho đến khi thực sự cần thiết. Khởi tạo lười (lazy) các thuộc tính trong Swift là một cơ chế tích hợp để giải quyết vấn đề này: một thuộc tính với bộ điều chỉnh lazy sẽ chỉ được tạo khi truy cập lần đầu, tiết kiệm bộ nhớ và tăng tốc tải màn hình.

Không sử dụng viewDidLoad cho các thao tác cần được thực hiện mỗi khi màn hình xuất hiện. Đây là lỗi cơ bản nhất: các nhà phát triển mới thường đặt logic cập nhật dữ liệu trong viewDidLoad và ngạc nhiên rằng khi quay lại từ màn hình khác, bảng không tải lại. Nếu một thao tác nên lặp lại mỗi lần hiển thị — hãy sử dụng viewWillAppear. Nếu nó nên thực thi một lần trong suốt vòng đời — hãy sử dụng viewDidLoad. Hãy nhớ quy tắc đơn giản này để tránh hầu hết các vấn đề với vòng đời UIViewController.

Ví dụ mã với viewDidLoad

Hãy xem ba ví dụ thực tế minh họa cách sử dụng đúng viewDidLoad trong các dự án thực tế. Mỗi ví dụ giải quyết một tác vụ cấu hình màn hình cụ thể.

Ví dụ 1: cấu hình bộ sưu tập với cell tùy chỉnh

swift
override func viewDidLoad() {
    super.viewDidLoad()
    collectionView.register(
        PhotoCell.self,
        forCellWithReuseIdentifier: PhotoCell.reuseId
    )
    collectionView.register(
        HeaderView.self,
        forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
        withReuseIdentifier: HeaderView.reuseId
    )
    viewModel.delegate = self
    viewModel.fetchInitialPage()
}

Ví dụ 2: thiết lập ràng buộc theo chương trình

swift
override func viewDidLoad() {
    super.viewDidLoad()
    let label = UILabel()
    label.text = "Xin chào thế giới!"
    label.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(label)

    NSLayoutConstraint.activate([
        label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
        label.centerYAnchor.constraint(equalTo: view.centerYAnchor)
    ])
}

Ví dụ 3: cấu hình trạng thái trống và bộ tải

Trong viewDidLoad, bạn cũng cấu hình các thành phần hiển thị khi không có dữ liệu: trạng thái trống, bộ tải, placeholder. Các thành phần này được tạo một lần và tái sử dụng mỗi khi màn hình xuất hiện. Ẩn hoặc hiện các thành phần này được quản lý trong viewWillAppear tùy thuộc vào dữ liệu hiện tại.

swift
override func viewDidLoad() {
    super.viewDidLoad()
    emptyStateLabel = UILabel()
    emptyStateLabel.text = "Không có dữ liệu"
    emptyStateLabel.textAlignment = .center
    emptyStateLabel.isHidden = true
    view.addSubview(emptyStateLabel)

    activityIndicator = UIActivityIndicatorView(style: .medium)
    activityIndicator.hidesWhenStopped = true
    view.addSubview(activityIndicator)
}

Ví dụ 4: đăng ký thông báo ứng dụng

swift
override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(handleEnterForeground),
        name: UIApplication.willEnterForegroundNotification,
        object: nil
    )
}

@objc private func handleEnterForeground() {
    refreshContent()
}

Câu hỏi thường gặp

viewDidLoad có thể được gọi nhiều hơn một lần không?

Trong điều kiện bình thường, không — UIKit gọi viewDidLoad một lần sau khi tải View vào bộ nhớ. Nếu controller bị hủy và được tạo lại, viewDidLoad sẽ chạy cho instance mới.

Tôi có cần gọi super.viewDidLoad không?

Có, bắt buộc. Gọi super.viewDidLoad đảm bảo UIKit thực hiện thiết lập nội bộ cần thiết để Lifecycle hoạt động chính xác. Luôn gọi super đầu tiên bên trong phương thức.

Sự khác biệt giữa viewDidLoad và viewWillAppear là gì?

viewDidLoad được gọi một lần khi View được tải. viewWillAppear được gọi mỗi lần trước khi màn hình xuất hiện. Cái đầu tiên dành cho thiết lập một lần, cái thứ hai để cập nhật dữ liệu và trạng thái.

Tôi có thể thực hiện các thao tác nặng trong viewDidLoad không?

Các thao tác đồng bộ nặng trong viewDidLoad chặn luồng chính và làm chậm việc hiển thị màn hình. Tải không đồng bộ có thể chấp nhận được, nhưng khi cập nhật UI sau khi hoàn thành, cần tính đến khả năng màn hình có thể đã bị ẩn.

Làm thế nào để buộc gọi viewDidLoad?

Bạn không thể gọi viewDidLoad trực tiếp — UIKit gọi nó. Để buộc tải View, hãy truy cập thuộc tính controller.view. Điều này sẽ tự động kích hoạt loadView và viewDidLoad.

Tổng kết

  • viewDidLoad là phương thức thiết lập một lần của UIViewController được gọi sau khi tải View vào bộ nhớ
  • Được gọi một lần trong suốt vòng đời của controller khi truy cập View lần đầu
  • Phù hợp để đăng ký cell, cấu hình delegate, khởi tạo viewModel
  • Luôn gọi super.viewDidLoad để Lifecycle hoạt động chính xác
  • Không sử dụng viewDidLoad cho các thao tác phụ thuộc vào kích thước View
  • Để cập nhật dữ liệu mỗi lần xuất hiện, hãy sử dụng viewWillAppear
  • Đăng ký thông báo vĩnh viễn là phù hợp, tạm thời — trong viewWillAppear

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm