View Controller Lifecycle trong phát triển ứng dụng iOS

Xin chào mọi người, trong bài viết này, như tiêu đề mình sẽ trình bày về lifecycle của view controller trong ứng dụng iOS. Việc hiểu về vòng đời của 1 view controller thực sự rất quan trọng trong việc phát triển bất cứ một ứng dụng nào. Nó giúp chúng ta đặt các hàm xử lý logic 1 cách hợp lý, nhằm tối ưu app, đạt được mục đích của người lập trình.

I. Khái quát

Việc đầu tiên, chúng ta cần hiểu rõ lifecycle của view controller là gì. Lifecycle hiểu nôm na giống như 1 event gồm 1 chuỗi các bước từ bước đầu hình thành tới bước kết thúc. Thực tế trong lập trình iOS, nó là vòng đời của view controller được tính từ lúc nó được nạp vào bộ nhớ (RAM) cho đến lúc terminated. Các bước này được thực thi thông qua subclass UIViewController.

Mục đích của View Controller là dùng để quản lý chỉ 1 view hoặc 1 tập hợp các subview (UILabel, UIButton,...). Các view này có thể được tạo ra theo 3 cách:

  • Thông qua Storyboard
  • Thông qua .xib file
  • Thông qua code (programmatically)

ViewController tuỳ biến các view tĩnh (từ storyboard, .xib file) thành các view động với ý muốn, mục đích hiển thị khác nhau. Nó kết nối giữa các components của view, gắn với data của model object.

II. Các hàm Lifecycle chính

nguồn: LearnAppMaking.com

Theo sơ đồ trên, chúng ta có thứ tự các hàm được gọi theo chu kì như sau:

  • (void)viewDidLoad
  • (void)viewWillAppear
  • (void)viewDidAppear
  • (void)viewWillDisappear
  • (void)viewDidDisappear

Lưu ý, đây chỉ là những hàm lifecycle chính, còn rất nhiều hàm nữa được sử dụng mình sẽ đề cập bên dưới sau.

1. ViewDidLoad

Phương thức này được gọi sau khi view controller đã load tất cả các view mà nó quản lý trong storyboard, hoặc .nib file, hoặc view được tạo thông qua code trong hàm loadView() (mình sẽ nói ở phần tiếp theo) vào bộ nhớ RAM. Ở trong hàm này, chúng ta override để chuẩn bị data hoặc khởi tạo các giá trị mặc định cho các outlet, đại diện cho UI trên màn hình. Một lưu ý là hàm này chỉ được gọi 1 lần duy nhất trong cả lifetime, nên hãy chắc chắn là bạn dùng nó cho những việc khởi tạo hoặc chỉ khai báo 1 lần.

Ví dụ bạn muốn gắn data vào 1 UILabel chẳng hạn.

2. viewWillAppear

Hàm này được gọi trước khi 1 view được thêm vào hệ thống view (UINavigationController) và trước animation hiển thị view đó. Hàm này được sử dụng khi bạn có task mà muốn nó lặp đi lặp lại mỗi lần view đó chuẩn bị được lên thớt. Khác với viewDidLoad, method này được gọi nhiều lần với mỗi 1 instance của view controller. Ví dụ cho dễ hiểu,  khi bạn vào màn hình A lần đầu tiên thì nó sẽ chạy hàm viewDidLoad rồi viewWillAppear, nhưng khi bạn sang màn hình B rồi trở lại màn hình A thì nó sẽ chỉ chạy lại vào viewWillAppear. Do lần đầu view đã load vào trong bộ nhớ RAM rồi.

Chúng ta có thể sử dụng hàm này để thực hiện các task mà kết hợp với việc display view. Ví dụ như ẩn 1 field nào đó hoặc disable 1 button cho đến khi view được hiển thị hoàn toàn.

3. viewDidAppear

Method này được gọi khi view đã được hiển thị trên màn hình. Chúng ta có thể sử dụng method này để thực hiện các animation trên UI, như là bật 1 video hoặc nhạc, hoặc có thể bắt đầu lấy dữ liệu data từ api, network.

4. viewWillDisappear

Method này được gọi trước khi view được remove khỏi hệ thống view. View lúc này vẫn còn nằm trong hệ thống view và chưa hoàn toàn bị xoá khỏi đó. Thật sự thì không có nhiều task cần triển khai ở thời điểm này của lifecycle. Tuy nhiên, developer vẫn có thể dùng nó để handle timing, tắt keyboard hoặc huỷ kết nối với network, api. Ngoài ra, nếu muốn lưu lại state của màn hình thì ở đây cũng là một sự lựa chọn lý tưởng.

5. viewDidAppear

Hàm này được gọi sau khi view đã được remove hoàn toàn khỏi hệ thống view. Thông thường method này được override để stop hoàn toàn các tác vụ mà view trước thực hiện. Ví dụ, tắt notification, huỷ các animation trên các view cũ, etc.

III. Một số lifecycle method khác

1. loadView

Method này chỉ được sử dụng khi view được tạo từ code. Nếu view được tạo thành từ file .xib hoặc storyboard thì hãy bỏ qua method này. Method này được gọi khi và chỉ khi view = nil (do không tìm thấy file storyboard hoặc .xib). Nó sẽ thay thế view đó bằng view mà mình code trong hàm này. Hàm này được gọi trước viewDidLoad nhằm để nạp view vào RAM.

2. viewWillLayoutSubviews

Mặc định thì hàm này sẽ không được gọi. Cho đến khi view's bound (kích thước) thay đổi và view đó tự động adjust lại các subview có trong view. Override method này để thực hiện các tác vụ trước khi các subview được cập nhật.

3. viewDidLayoutSubviews

Được gọi sau khi các subview đã được cập nhật lại kích thước và vị trí. Override method này thường  để thực hiện các thay đổi trên subview sau khi nó được cập nhật.

4. didReceiveMemoryWarning

Các thiết bị iOS có giới hạn bộ nhớ khác nhau. Khi mà bộ nhớ đầy, iOS không sử dụng phần dung lượng bộ nhớ giới hạn (limited hard disk space) để di chuyền phần data ra khỏi bộ nhớ như máy tính. nếu app bắt đầu ngốn quá nhiều memory, iOS bắt đầu cảnh báo việc đó thông qua notifications được gửi thông qua method này. Chúng ta có thể làm 1 số hành động để thêm dọn dẹp bộ nhớ, nếu chúng ta bỏ qua cảnh báo vào tiếp tục thực hiện các task trên view thì đến một giới hạn, iOS sẽ tự động end app và nó giống như việc bị crash vậy. Điều đó thực sự không tốt một chút nào.

IV. Lời kết

Trên đây, mình đã trình bày về lifecycle của 1 view controller trong lập trình iOS. Tất cả đều chỉ mang tính chất lý thuyết, việc vận dụng, tối ưu lifecycle này trong ứng dụng tuỳ thuộc vào mục đích từng cá nhân khác nhau. Hy vọng nó đã giúp các bạn hiểu thêm 1 phần nào đó trong lập trình iOS. Xin chào!

V. Reference

https://developer.apple.com/documentation/uikit/view_controllers

https://medium.com/good-morning-swift/ios-view-controller-life-cycle-2a0f02e74ff5