Bắt đầu phát triển iOS Apps với Swift part 2: Kết nối UI và Source Code
Bài đăng này đã không được cập nhật trong 3 năm
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:
I. Tạo Outlets cho các thành phần UI
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.
II. Định nghĩa 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.
III. Xử lý khi user nhập dữ liệu vào text field
Để 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( thêm vào method
func textFieldDidEndEditing(_ textField: UITextField) {
}
- Set label giá trị mà người dùng vừa nhập
mealNameLabel.text = textField.text
Kết quả sẽ là:
func textFieldDidEndEditing(_ textField: UITextField) {
mealNameLabel.text = textField.text
}
Kiểm tra kết quả: Chạy simulator và nhập tên của món ăn bạn thích vào text field để kiểm tra
IV. Tổng kết
Vậy là trong phần này chúng ta đã:
- Giải thích được mối quan hệ giữa các thành phần trên màn hình với source code trong view controller
- Tạo được outlets và actions
- Xử lý dữ liệu user nhập vào
- Để class kế thừa và tuân theo một protocol
- Hiểu về delagation pattern
- Tuân theo target-action pattern khi thiết kế cấu trúc app
All rights reserved