Lời mở đầu
Cách lưu dữ liệu sử dụng file Property List khá phổ biến trong lập trình ứng dụng iOS, nó thường được dùng để lưu các dữ liệu nhỏ và không cần tính bảo mật cao. Bài viết này mình sẽ chia sẻ với các bạn một số cách để thao tác với Property List.
Info.plist
Tất cả các project khi bạn mới tạo XCode sẽ tự tạo ra một file Info.plist, nó làm nhiệm vụ lưu lại các thông tin dự án của bạn. Từ project name, version cho đến các setting cũng như mô tả API của Apple.
Các thông tin trong file Info.plist sẽ được các API của Apple truy cập vào để lấy thông tin hiển thị lên ứng dụng. (VD: Hiển thị message cho pop up xin quyền truy cập Camera …) cũng như việc xác nhận thông tin của Apple khi bạn Submit ứng dụng lên App Store Connect. Vì vậy file này chỉ nên lưu những thông tin cài đặt của dự án. Nếu bạn muốn lưu dữ liệu dạng này ta có thể tạo một file mới và lưu vào đó.
Tạo file Property List mới
Bước 1: Chuột phải vào thư mục bạn muốn lưu file -> New File…
Bước 2: Đánh ô tìm kiếm phía trên với keyword “Property List” -> Next -> Đặt tên file
Vậy là bạn đã tạo thành công file Property List. Giờ bạn có thể mở file và điền thông tin mình muốn lưu vào file đó.
Tuy nhiên nếu sử dụng XCode thì chúng ta chỉ có thể lưu được các dữ liệu như:
- String
- Number
- Bool
- Data
- Date
- Array
- Dictionary
Chúng ta cũng có thể lưu kiểu custom object vào file Property List nhưng phải sử dụng code để encode dữ liệu cần lưu sang Data rồi khi sử dụng thì chúng ta decode nó về dữ liệu ban đầu.
Tạo file Property List bằng code
Chúng ta có thể tạo file Property List một cách đơn giản hơn bằng cách như sau:
func save(key: String, value: Any) {
let myData: NSDictionary = [key: value]
let fileManager = FileManager.default
// Đường dẫn lưu file và tên file của bạn
let path = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("MyInfo3.plist")
// Viết vào file nếu file không tồn tại nó sẽ tự tạo file mới.
myData.write(to: path, atomically: true)
print(path)// in ra console để thấy đường dẫn lưu file
}
Truy cập vào file Property List bằng code
Lấy data từ file Property list
func getMyPlist(key: String) -> Any? {
// Lấy ra đường dẫn vào file Property List của bạn
let path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("MyInfo.plist")
// Sử dụng NSDIctionary để lấy nội dung từ URL
guard let myDict = NSDictionary(contentsOf: path) else { return nil }
print(path)
// Trả về giá trị theo key trong Dictionary
return myDict[key]
}
Lưu dữ liệu vào file Property List
func saveMyPlist(key: String, value: Any) {
let fileManager = FileManager.default
// Tạo đường dẫn file
let path = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("MyInfo.plist")
guard let myDict = NSMutableDictionary(contentsOf: path) else {
// nếu file chưa tồn tại chúng ta sẽ ghi vào file với bộ key/value đầu tiên.
let myData: NSDictionary = [key: value]
myData.write(to: path, atomically: true)
return
}
// nếu file đã tồn tại chúng ta sẽ update dữ liệu
myDict[key] = value
myDict.write(to: path, atomically: true)
print(path)
}
Xóa một key trong Property List
func removeMyPlist(key: String) {
let fileManager = FileManager.default
// Tạo đường dẫn file
let path = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("MyInfo.plist")
guard let myDict = NSMutableDictionary(contentsOf: path) else { return }
// nếu file đã tồn tại chúng ta sẽ update dữ liệu
myDict.removeObject(forKey: key)
myDict.write(to: path, atomically: true)
}
Để tương tác dễ hơn với plist bắt buộc chúng ta phải tạo ra các func để quản lý các file đó. Nhưng nếu các bạn không muốn làm những thứ lằng nhằng đó thì chúng ta có thể chuyển qua dùng một file Property List có sẵn mà Apple đã cung cấp đó là sử dụng UserDefault
UserDefault
UserDefault là một singleton class nhằm mục đích giúp các nhà phát triển có thể dễ dàng lưu dữ liệu vào file Plist hơn. Mặc định khi bạn sử dụng UserDefault nó sẽ tạo ra một file Plist trong dự án. Từ đó ta có thể thêm, sửa, xóa các key nằm trong file Plist đó dựa trên các hàm mà UserDefault cung cấp.
UserDefault tương tác trên Property List nên nó cũng phải tuân thủ theo quy tắc của file đó. Vì vậy thông thường chung ta chỉ có thể gán được các giá trị mà file Plist cho phép.
Để lưu/lấy giá trị bằng UserDefault ta làm như sau:
let udf = UserDefaults.standard//Tạo instance
udf.set("11", forKey: "1")// gán giá trị 11 cho key "1"
udf.synchronize()//nó block thread đang gọi cho đến khi giá trị được gán hoàn tất
print(udf.value(forKey: "1"))// lấy dữ liệu của key 1 và in ra console
Như vậy với UserDefault chúng ta có thể làm việc với file Plist một cách đơn giản. Tuy nhiên, đôi khi chúng ta cũng phải lưu lại kiểu dữ liệu mà Plist không hỗ trợ. Lúc này chúng ta cần phải encode nó về Data để có thể lưu được dạng này.
Lưu ý
Chúng ta không nên lưu những dữ liệu quá nặng trong Plist, vì file này sẽ tiêu tốn bộ nhớ RAM khi bạn chạy ứng dụng.
Lưu custom object
Tạo mới class
class Employee: NSObject, NSCoding {
let name: String
let dob: String
// hàm khởi tạo
init(name: String, dob: String) {
self.name = name
self.dob = dob
}
// init với NSCoder bước này để decode
required convenience init(coder aDecoder: NSCoder) {
let name = aDecoder.decodeObject(forKey: "name") as! String
let dob = aDecoder.decodeObject(forKey: "dob") as! String
self.init(name: name, dob: dob)
}
// hàm này để encode
func encode(with aCoder: NSCoder) {
aCoder.encode(name, forKey: "name")
aCoder.encode(dob, forKey: "dob")
}
}
Lưu Employee vào UserDefault sử dụng NSKeyedArchiver
let employee = Employee(name: "Dino", dob: "19/09/1999")
let udf = UserDefaults.standard
do {
let encodeData = try NSKeyedArchiver.archivedData(withRootObject: employee, requiringSecureCoding: false)
udf.set(encodeData, forKey: "emp")
udf.synchronize()
} catch {
print(error)
}
Lấy ra Employee từ UserDefault
let decode = udf.data(forKey: "emp")
let decodeEmp = NSKeyedUnarchiver.unarchiveObject(with: decode!) as? Employee
Tổng kêt
Mình hi vọng bài viết này có thể giúp các bạn sử dụng Property List tốt hơn. Chúc các bạn thành công.