Contents
Chào mừng bạn đến với Fx Studio. Chúng ta sẽ cùng nhau tìm hiểu về chủ đề khá là cơ bản trong Swift & iOS. Đó là UserDefaults. Đây là cách đầu tiên mà bạn sẽ dùng lưu trữ dữ liệu trong ứng dụng iOS của bạn.
Nếu mọi việc đã ổn rồi, thì …
Bắt đầu thôi!
Chuẩn bị
UserDefaults là một trong những thành phần cơ bản đầu tiên có trong nền tảng iOS. Nên về mặt công cụ sử dụng, thì hầu như tất cả các phiên bản của Xcode & Swift đều hỗ trợ nó. Nên bạn sẽ an tâm về mặt này.
Về mặt kiến thức, UserDefaults là một trong những khái niệm cơ bản. Do đó, bạn chỉ cần biết ít nhiều về Swift là đủ rồi. Còn nếu bạn chưa biết về Swift thì có thể tham khảo link sau đây.
Nếu bạn hứng thú với iOS thì có thể tiếp tục series Lập trình iOS cho mọi người ngay sau khi đọc xong bài viết này.
UserDefaults
UserDefaults được sử dụng để lưu trữ các phần nhỏ dữ liệu tồn tại trong suốt quá trình ứng dụng hoạt động. Ngay cả khi ứng dụng bị bắt đi và bạn vẫn lấy được giá trị cuối cùng khi sử dụng lại ứng dụng. Việc sử dụng UserDefaults được xem là khá phổ biến trong giới lập trình iOS.
Kiểu dữ liệu được sử dụng cho việc lưu trữ sẽ là các kiểu dữ liệu cơ bản và đơn giản. Ví dụ như: String, Int, Float …. Ngoài ra, bạn vẫn có thể lưu trữ các kiểu dữ liệu custom (như: class, struct, dictionary, array …)
Mỗi dữ liệu khi lưu trữ sẽ bao gồm một cặp key
và value
. Trong đó:
key
sẽ luôn là kiểu dữ liệu Stringvalue
sẽ là giá trị mà bạn muốn lưu trữ và nó có thể cấp nhập các kiểu dữ liệu cơ bản (như đã nói ở trên).
Nó sẽ lưu trữ các giá trị dữ liệu vào file *.plist
trong bộ nhớ của ứng dụng trên thiết bị. Khi ứng dụng bạn khởi chạy, thì nó sẽ được khôi phục và tiếp tục sử dụng trong suốt quá trình ứng dụng hoạt động.
Tóm lại, bạn không cần quan tâm về cơ chế hay bản chất của nó.
Về mặt ý nghĩa, UserDefaults sẽ dùng lưu trữ các settings người dùng từ phía local. Và không có nhu cầu đồng bộ dữ liệu đó lên server hay các thiết bị khác. Ngoài ra, tính bảo mật của nó khá kém, nên bạn cũng cần phải chú ý khi muốn lưu trữ các loại dữ liệu nhạy cảm.
Sử dụng
Chúng ta sẽ đi vào cách sử dụng cơ bản nhất của UserDefaults trước nhóe.
- Chúng ta cần sử dụng một đối tượng của UserDefaults, hoặc bạn có thể lấy ngay đối tượng mà hệ thông cung cấp.
let userdefault = UserDefaults.standard
- Đọc một giá trị với một
key
cho trước
let userdefault = UserDefaults.standard print(userdefault.string(forKey: "hello") ?? "n/a")
- Lưu giá trị với một
key
let userdefault = UserDefaults.standard userdefault.set("Hello", forKey: "hello")
Nhìn qua, bạn cũng hình dung cách phương thức cần sử dụng để thực hiện 2 công việc cơ bản rồi đó. Chúng sẽ dùng:
set
để lưu trữ dữ liệu vớikey
string
,int
… hoặcobject
để lấy giá trị mà bạn đã lưu vớikey
cho trước
EZ Game!
Synchronize
Nếu bạn là một dev iOS lâu năm. Hoặc đôi lúc bạn vô tình bắt gặp phương thức synchronize()
, thì bây giờ nó:
Không còn cần thiết nữa!
Trước đây, nó dùng để đồng bộ dữ liệu và để bạn có thể sử dụng lại dữ liệu lưu trữ mới mất. Khi bạn mở ứng dụng thì dữ liệu sẽ được khôi phục.
Tuy nhiên, Swift đã tiến hóa và bạn không cần dùng tới function này nữa. Dữ liệu của bạn luôn luôn được đảm bảo lưu trữ và phục hồi mới nhất.
Và nếu bạn vẫn còn sử dụng nó trong code của bạn, thì đôi khi đem lại tác dụng phụ không mong muốn. Đó là …
Làm chậm ứng dụng.
Lưu dữ liệu
Để lưu dữ liệu vào UserDefaults, bạn sẽ sử dụng phương thức set(_:forKey:)
của chính đối tượng UserDefaults.
- Kiểu dữ liệu lưu trự sẽ dựa vào giá trị mà bạn cung cấp
key
sẽ là do bạn đặt và nó có kiểu là String
Bạn có thể tham khảo các ví dự sau:
//Int defaults.set(22, forKey: "userAge") //Bool var darkModeEnabled = true defaults.set(darkModeEnabled, forKey: "darkModeEnabled") //Array let fruits = ["Apple", "Banana", "Mango"] defaults.set(fruits, forKey: "favoriteFruits") //Dictionary let toggleStates = ["WiFi": true, "Bluetooth": false, "Cellular": true] defaults.set(toggleStates, forKey: "toggleStates") //....
Cũng kha khá kiểu dữ liệu mà bạn có thể lưu trữ rồi đó.
Đọc dữ liệu
Công việc tiếp theo là bạn đọc lại các dữ liệu đã được lưu. Cần phải xác định 2 điều:
- Kiểu dữ liệu mà bạn muốn đọc
key
của dữ liệu mà bạn đã lưu trữ
Ta sẽ xem qua ví dụ đọc dữ liệu với các giá trị đã lưu ở ví dụ trên nhóe.
let userAge = defaults.integer(forKey: "userAge") let darkModeEnabled = defaults.bool(forKey: "darkModeEnabled") let favoriteFruits = defaults.array(forKey: "favoriteFruits”) let toggleStates = defaults.dictionary(forKey: "toggleStates")
UserDefaults sẽ cung cấp cho bạn đầy đủ các kiểu dữ liệu cơ bản theo từng phương thức phù hợp. Một số kiểu sẽ có giá trị trả về là Optional, ví dụ như String, Array, Dictionary …
Cuối cùng, nếu bạn không biết chính xác là kiểu gì, thì hãy sử dụng phương thức object(forKey)
với kiểu AnyObject? trả về. Sau đó, bạn tiến hành ép kiểu cho phù hợp.
Default value
Điều gì sẽ xảy ra nếu không có dữ liệu liên kết với key
?
Với phương thức get
thì bạn sẽ nhận lại một giá trị mặc định, khi chúng không tồn tại hoặc không liên kết với key
nào cả. Ví dụ như integer(forKey)
sẽ trả về là 0
nhóe.
print(userdefault.integer(forKey: "total")) //0
Với các kiểu dữ liệu như là String, Array, Dictionary … thì bạn sẽ nhận được phiên bản Optional của chúng. Và khi rơi vào trường hợp trên, thì chúng sẽ trả về là nil
.
Điều này nó tạo ra sự không nhất quán trong logic code của bạn. Chắc chắn bạn sẽ gặp khá nhiều bugs cơ bản với chúng.
Không tồn tại hay không có giá trị
Để thống nhất, bạn nên sử dụng phương thức object(forKey)
cho tất cả các giá trị mà bạn muốn lấy. Và nó sẽ trả về một Optional. Khi giá trị chưa liên kết với key
thì bạn sẽ nhận được là nil
. Công việc cuối cùng, bạn sẽ ép kiểu về kiểu mà bạn muốn sử dụng. Ví dụ nhóe!
let favoriteFruits = defaults.object(forKey: "favoriteFruits") as? [String] ?? [String]()
Trong quá trình ép kiểu, nếu chúng là nil
thì bạn có thể cung cấp một giá trị mặc định ban đầu để sử dụng. Vừa giải quyết bài toán tồn tại và vừa giá trị mặc định. EZ Game!
Custom Objects
Độ khó logic code của bạn sẽ tăng thêm. Và việc lưu trữ các đối tượng với kiểu dữ liệu Custom, như là: class, struct ... là điều hiển nhiên. Nhất là khi bạn có quá nhiều thuộc tính (properties) cần phải lưu trữ.
Tất nhiên, bạn cần phải có kiểu dữ liệu phù hợp cho việc lưu trữ. Với các class hay struct thì cần phải tuân thủ Codable Protocol. Nó sẽ giúp dữ liệu của bạn có thể chuyển đổi định dạng một cách tự động và nhanh chóng. Xem ví dụ với struct User sau nhóe!
struct User: Codable { let name: String let age: Int }
Ghi dữ liệu
Vì bạn đã khai báo kiểu dữ liệu của bạn tuân thủ với Codable Protocol rồi. Nên chúng ta sẽ chuyển đổi đối tượng đó thành Data. Sau đó, chúng ta sẽ lưu chúng vào UserDefaults dưới dạng một object
với key
xác định.
Ví dụ nhóe!
let userdefault = UserDefaults.standard let user = User(name: "chuotfx", age: 22) let encoder = JSONEncoder() if let encodedUser = try? encoder.encode(user) { userdefault.set(encodedUser, forKey: "user") }
Trong đó:
- JSONEncoder để tiến hành mã hóa đối tượng thành Data
set(_:forKey)
để tiến hành lưu trữ
Đọc dữ liệu
Công việc đọc dữ liệu, thì tiến hành ngược lại với công việc ghi.
- Đọc dữ liệu với kiểu là Data từ UserDefaults
- Tiến hành giải mã đối tượng với JSONDecoder
Xem tiếp ví dụ nhóe!
if let savedUserData = userdefault.object(forKey: "user") as? Data { let decoder = JSONDecoder() if let savedUser = try? decoder.decode(User.self, from: savedUserData) { print("Saved user: \(savedUser)") } }
register(defaults:)
Sau khi bạn đã am hiểu hết cơ bản về UserDefaults rồi. Thì chúng ta tiến tới với cách tiếp cận đúng đắng hơn khi bạn sử dụng UserDefaults.
Phương thức này giúp bạn cung cấp các giá trị mặc định cho các key
mà bạn muốn sử dụng. Nó giúp cho bạn tránh đi việc phải xác định:
- Đối tượng lưu trữ có tồn tại hay không?
- Chúng có giá trị mặc định hay không?
Xem ví dụ code nhóe!
let userDefaults = UserDefaults.standard userDefaults.register( defaults: [ "enabledSound": true, "enabledVibration": true ] ) print(userDefaults.bool(forKey: "enabledSound")) // true
Trong đó:
- Sử dụng phương thức
register
để tiến hành đăng ký cáckey
&value
ban đầu - Còn lại thì bạn sử dụng bình thường như trên
Code của bạn lúc này sẽ khá sạch đẹp nhóe!
Và khi bạn đã lưu trữ một dữ liệu với key
có trong phần register
trước đó rồi. Và bạn lặp lại nó trong phần register
kìa, thì bạn cũng an tâm. Các giá trị trong phần register
sẽ được bỏ qua, nếu chúng đã tồn lại trước rồi. Do đó, bạn có thể sử dụng register
bao nhiêu lần cũng được. Xem ví dụ nữa nha.
let userDefaults = UserDefaults.standard userDefaults.set(false, forKey: "enabledSound") // 1 userDefaults.register( defaults: [ "enabledSound": true, // 2 "enabledVibration": true ] ) userDefaults.bool(forKey: "enabledSound") // false
Tạm kết
- Tìm hiểu về UserDefautls và cách sử dụng cơ bản
- Đọc & ghi các kiểu dữ liệu cơ bản
- Đọc & ghi các đối tượng với kiểu dữ liệu Custom
- Sử dụng register để thêm các dữ liệu mặc định đầu tiên khi sử dụng
Okay! Tới đây, mình xin kết thúc bài viết về UserDefaults. Nếu có gì thắc mắc hay góp ý cho mình thì bạn có thể để lại bình luận hoặc gởi email theo trang Contact.
- Bạn có thể checkout code tại đây.
Cảm ơn bạn đã đọc bài viết này!
Related Posts:
Written by chuotfx
Hãy ngồi xuống, uống miếng bánh và ăn miếng trà. Chúng ta cùng nhau đàm đạo về đời, về code nhóe!
Leave a Reply Cancel reply
Fan page
Tags
Recent Posts
- Charles Proxy – Phần 1 : Giới thiệu, cài đặt và cấu hình
- Complete Concurrency với Swift 6
- 300 Bài code thiếu nhi bằng Python – Ebook
- Builder Pattern trong 10 phút
- Observer Pattern trong 10 phút
- Memento Pattern trong 10 phút
- Strategy Pattern trong 10 phút
- Automatic Reference Counting (ARC) trong 10 phút
- Autoresizing Masks trong 10 phút
- Regular Expression (Regex) trong Swift
You may also like:
Archives
- September 2024 (1)
- July 2024 (1)
- June 2024 (1)
- May 2024 (4)
- April 2024 (2)
- March 2024 (5)
- January 2024 (4)
- February 2023 (1)
- January 2023 (2)
- November 2022 (2)
- October 2022 (1)
- September 2022 (5)
- August 2022 (6)
- July 2022 (7)
- June 2022 (8)
- May 2022 (5)
- April 2022 (1)
- March 2022 (3)
- February 2022 (5)
- January 2022 (4)
- December 2021 (6)
- November 2021 (8)
- October 2021 (8)
- September 2021 (8)
- August 2021 (8)
- July 2021 (9)
- June 2021 (8)
- May 2021 (7)
- April 2021 (11)
- March 2021 (12)
- February 2021 (3)
- January 2021 (3)
- December 2020 (3)
- November 2020 (9)
- October 2020 (7)
- September 2020 (17)
- August 2020 (1)
- July 2020 (3)
- June 2020 (1)
- May 2020 (2)
- April 2020 (3)
- March 2020 (20)
- February 2020 (5)
- January 2020 (2)
- December 2019 (12)
- November 2019 (12)
- October 2019 (19)
- September 2019 (17)
- August 2019 (10)