Bắt đầu phát triển iOS Apps với Swift part 2: Kết nối UI và Source Code
Trong phần 2 của bài viết chúng ta sẽ cùng tìm hiểu cách kết nối giữa UI đã tạo và Source code, đồng thời định nghĩa một số action mà user có thể thao tác trên UI đó. Trong một ứng dụng iOS, View controllers giữ vai trò điều phối luồng dữ liệu giữa các data model và các views nơi thể hiện data đó. ...
Trong phần 2 của bài viết chúng ta sẽ cùng tìm hiểu cách kết nối giữa UI đã tạo và Source code, đồng thời định nghĩa một số action mà user có thể thao tác trên UI đó. Trong một ứng dụng iOS, View controllers giữ vai trò điều phối luồng dữ liệu giữa các data model và các views nơi thể hiện data đó. Đồng thời quản lý vòng đời của các content view, xử lý khi xoay màn hình, định hướng các thành phần trong app và hồi đáp sau khi user thao tác vào các view trên màn hình. Chúng ta định nghĩa các thành phần của view controllers do mình viết bằng cách tạo vào implement các hàm trong subclass của View Controller. Sau đó chúng ta phải kết nối source code do mình viết và các thành phần UI mình định nghĩa trong StoryBoard với nhau để app có các chức năng như mong muốn.
Để định nghĩa các tương tác trong app, bạn cần định nghĩa các kết nối (gọi là Outlets và Actions) giữa các views ở Storyboard và source code trong file view controller theo các bước sau:
Outlet là một reference tới một object bạn đã tạo ở Storyboard từ source code file, cụ thể ở đây là file ViewController.swift. Để tạo outlet chúng ta dùng Control-drag để kéo object từ Storyboard vào view controller file. Hành động này tạo một property cho object, property này cho phép chúng ta access vào và thao tác trên object bằng source code lúc app đang chạy.
Kết nối text field với code trong file ViewController.swift
- Mở Main.storyboard
- Mở Assistant editor bằng cách click vào Assistant button
- Chuyển assistant editor từ Preview thành Automatic > ViewController.swift. Khi đó ViewController.swift sẽ được hiển thị ở bên phải.
- Ở file ViewController.swift, thêm dòng comment sau vào ngay dưới định nghĩa class
//MARK: Properties
Comment bắt đầu với //MARK là comment đặc biệt giúp ta đánh dấu sự bắt đầu một khối code có nhiệm vụ riêng. Đồng thời cũng là dấu giúp ta nhanh chóng "nhảy" tới đoạn code mình cần tìm. Các "nhảy" thì sẽ được giới thiệu sau trong chính bài viết này thôi. =)) 5. Chọn text field từ storyboard 6. Control-drag text field từ storyboad vào dòng tương tứng dưới //MARK mà chúng ta vừa đánh dấu. 7. Điền vào dialog vừa xuất hiện tên của text field là nameTextField 8. Click vào button Connect Xcode sẽ tự động add một dòng code
@IBOutlet weak var nameTextField: UITextField!
Chúng ta hãy cùng dành một chút thời gian để tìm hiểu về dòng code này. IBOutlet attribute nói với Xcode rằng bạn có thể kết nối tới nameTextField property từ Interface Builder. Đó là lý do vì sao attribute này có prefix là IB. Dòng code này khai báo một biến implicitly unwrapped optional có kiểu UITextField và tên là nameTextField. Chú ý một chút ở đấu chấm cảm cuối dòng code !, dấu này chỉ ra rằng type của biến là implicitly unwrapped optional - nghĩa là biến này sẽ luôn có giá trị sau lần set đầu tiên (không bị null sau đó). Khi view controller được load từ storyboard, hệ thống sẽ khởi toạ cấu trúc view và assign giá trị cho các outlets. Hàm viewDidLoad() sẽ được gọi và đảm bảo rằng các outlets sẽ có giá trị phù hợp.
Tiếp theo chúng ta sẽ kết nối label với source code trong file ViewController.swift theo cách tương tự. Kết nối Label với source code của file ViewController.swift
- Mở storyboard, chọn Label
- Control-Drag vào dòng ngay dưới nameTextField property
- Ở dialog vừa xuất hiện, chọn tên label là mealNameLabel
- Chọn Connect Dòng code sau đây sẽ hiện ra
@IBOutlet weak var mealNameLabel: UILabel!
Outlet cho phép bạn refer tới các thành phần trong view ở . Tuy nhiên để thực hiện respond khi user tương tác vào các element thì cần có một thành phần khác đảm nhận. Đó là Action.
Tạo setDefaultLabelText action ở ViewController.swift
- Ngay phía trên dấu } cuối cùng, thêm vào dòng comment dưới đây
//MARK: Actions
Comment này để chỉ ra đây là section code dùng list ra các action 2. Chọn Set Default Label Text button 3. Control-drag từ storyboard vào dòng code ngay dưới comment mark 4. Ở dialog vừa xuất hiện chọn Action cho phần Connection 5. Nhập setDefaultLabelText cho phần Name 6. Chọn UIButton cho Type 7. Click vào ConnectConnect Chúng ta sẽ có function sau
@IBAction func setDefaultLabelText(_ sender: UIButton) { }
Tham số sender chỉ ra object đóng vai trò làm trigger cho việc kích hoạt action - trong trường hợp này là một button. Hiện tại method này đang trống. Việc tạo xử lý cho việc user click vào button này khá là đơn giản. Thực hiện thay đổi text của label tại action
- Tìm tới function setDefaultLabelText bạn vừa add vào.
- Thêm dòng code set text của label
mealNameLabel.text = "Default Text"
Hiện tại function chúng ta có dạng
@IBAction func setDefaultLabelText(_ sender: UIButton) { mealNameLabel.text = "Default Text" }
Kiểm tra lại: Tới thời điểm hiện tại khi chạy app và click vào button chúng ta sẽ thấy label của text box thay đổi như dưới đây. Phần này chỉ mang tính ví dụ để mọi người có thể thấy được cơ chế của target-action pattern trong design app iOS - Đây là cơ chế một object gửi message tới một object khác khi một event xác định xảy ra. Trong trường hợp cụ thể này thì
- Event chính là việc user tạp vào button Set Default Text
- Action là setDefaultLabelText()
- Target là ViewController (nơi mà action method được định nghĩa)
- Sender là button Set Default Label Text Hệ thống gửi message bằng cách gọi action trong tagert và truyền message vào sender object. Sender thường là các đối tượng mà người dùng có thể tương tác vào như là button, slider, switch...vv. Target-action patter rất phổ biến trong iOS app nên các bạn sẽ được thấy thường xuyên hơn trong các bài sau này.
Để có thể xử lý được sự kiện user nhập tên món ăn vào text field, chúng ta cần tìm hiểu một khái niệm mới gọi là delegate. Một delegate là một object đại điện cho hay phối hợp cùng với các object khác. Delegating object - trong trường hợp này là text field - giữ mọt reference tới các object khác - delegate objectobject - và vào thời điểm thích hợp delegating object sẽ gửi message tới delegate object. Message sẽ thông báo cho delegate object về event mà delegating object đang quản lý hay vừa mới handle xong. Delegate object có thể update trạng thái của chính mình hay của các object khác trong app hoặc trả về kết quả...vv phụ thuộc vào loại event được xử lý.
Trong app của chúng ta, delegate của text field sẽ tương tác với text field khi user edit và biết được mức độ quan trọng của event khi nó xảy ra. Delegate sẽ sử dung thông tin đó để quyết định lưu hay xoá data và lúc hợp lý, ẩn bàn phím ...vv
Bất kì object nào cũng có thể phục phụ các object khác như một delegate khi mà nó tuân thủ protocol thích hợp. Protocol định nghĩa delegate của text field là UITextFieldDelegate. Vì vậy đầu tiên ViewController phải kế thừa UITextFieldDelegate protocol.
Kế thừa UITextFieldDelegate protocol
- Trong file ViewController.swift tìm dòng khai báo class
class ViewController: UIViewController {
- Sửa thành
class ViewController: UIViewController, UITextFieldDelegate {
Set ViewController object trở thành delegate của nameTextField property của nó.
- Trong ViewController.swift, tìm hàm viewDidLoad()
- Dưới dòng super.viewDidLoad() thêm một dòng trắng và đoạn code
// Handle the text field’s user input through delegate callbacks. nameTextField.delegate = self
self sẽ trỏ tới chính ViewController calss. Khi ViewController instance được load nó sẽ set chính bản thân mình thành delegate của nameTextField property. UITextFieldDelegate protocol định nghĩa ra 8 method, nhưng trong trường hợp này chúng ta chỉ cần quan tâm tới 2 method là:
func textFieldShouldReturn(_ textField: UITextField) -> Bool func textFieldDidEndEditing(_ textField: UITextField)
Để hiểu tại sao cần tới 2 hàm này chúng ta phải hiểu được cơ chế mà text field phản hồi lại thao tác của người dùng. Khi user tap vào text field thì nó tự động trở thành first responder, iOS sẽ show keyboard ra và bắt đầu session cho phép người dùng edit. Sau khi người dùng kết thúc edit thì text field phải đăng ký status của first responder để thông báo kết thúc. iOS khi đó sẽ xác định text field ko còn là active object nữa và route tới object thích hợp.
Chính vì vậy bạn cần phải đăng ký status của first responder bằng hàm textFieldShouldReturn.
- Trong ViewController.swift, ngay phía trên //MARK: Actions thêm mark mới
//MARK: UITextFieldDelegate
MARK này sẽ giúp chúng ta "nhảy" tới nó rất nhanh chóng. 2. Dưới comment thêm method
func textFieldShouldReturn(_ textField: UITextField) -> Bool { }
- Trong function đó thêm dòng code dưới đây để đăng ký first-responder status, đồng thời ẩn bàn phím đi
// Hide the keyboard. textField.resignFirstResponder() return true
Sau khi đã đăng ký xong chúng ta tiếp tục implement hàm textFieldDidEndEditing(:). Hàm này cho phép ta đọc dữ liệu mà người dùng đã nhập vào và tiến hành một số xử lý cần thiết với nó. Code hàm textFieldDidEndEditing
- Ở ViewController.swift, ngay dưới hàm textFieldShouldReturn(