Làm cách nào để lưu dữ liệu cục bộ trong ứng dụng Swift?


148

Tôi hiện đang làm việc trên một ứng dụng iOS được phát triển trong Swift và tôi cần lưu trữ một số nội dung do người dùng tạo trên thiết bị nhưng dường như tôi không thể tìm thấy một cách đơn giản và nhanh chóng để lưu trữ / nhận nội dung người dùng trên thiết bị.

Ai đó có thể giải thích làm thế nào để lưu trữ và truy cập lưu trữ cục bộ?

Ý tưởng là lưu trữ dữ liệu khi người dùng thực thi một hành động và nhận nó khi ứng dụng khởi động.


Xin chào và chào mừng, bạn đang lưu trữ loại dữ liệu nào? Bạn có thể cung cấp bất kỳ mã nào để đưa ra một ví dụ về những gì bạn đang tìm kiếm? Cảm ơn.
Wez

1
Dữ liệu mà tôi cần lưu trữ về cơ bản chỉ là dữ liệu chuỗi. Vì vậy, để giữ cho nó thực sự đơn giản, tôi cần lưu hai giá trị Chuỗi mà tôi có thể nhận được nếu người dùng khởi động lại ứng dụng.
Nicklas Ridewing

2
Bạn có thể sử dụng NSUserDefaults. Dưới đây là thông tin bạn cần mã hóaexplorer.com/nsuserdefaults
a

Câu trả lời:


197

Giải pháp đơn giản nhất nếu bạn chỉ lưu trữ hai chuỗi là NSUserDefaults, trong Swift 3, lớp này đã được đổi tên thành chỉ UserDefaults.

Tốt nhất là lưu trữ khóa của bạn ở đâu đó trên toàn cầu để bạn có thể sử dụng lại chúng ở nơi khác trong mã của mình.

struct defaultsKeys {
    static let keyOne = "firstStringKey"
    static let keyTwo = "secondStringKey"
}

Swift 3.0, 4.0 & 5.0

// Setting

let defaults = UserDefaults.standard
defaults.set("Some String Value", forKey: defaultsKeys.keyOne)
defaults.set("Another String Value", forKey: defaultsKeys.keyTwo)

// Getting

let defaults = UserDefaults.standard
if let stringOne = defaults.string(forKey: defaultsKeys.keyOne) {
    print(stringOne) // Some String Value
}
if let stringTwo = defaults.string(forKey: defaultsKeys.keyTwo) {
    print(stringTwo) // Another String Value
}

Swift 2.0

// Setting

let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject("Some String Value", forKey: defaultsKeys.keyOne)
defaults.setObject("Another String Value", forKey: defaultsKeys.keyTwo)

// Getting

let defaults = NSUserDefaults.standardUserDefaults()
if let stringOne = defaults.stringForKey(defaultsKeys.keyOne) {
    print(stringOne) // Some String Value
}
if let stringTwo = defaults.stringForKey(defaultsKeys.keyTwo) {
    print(stringTwo) // Another String Value
}

Đối với bất kỳ điều gì nghiêm trọng hơn cấu hình nhỏ, cờ hoặc chuỗi cơ sở, bạn nên sử dụng một số loại lưu trữ liên tục - Một tùy chọn phổ biến tại thời điểm này là Realm nhưng bạn cũng có thể sử dụng SQLD hoặc Táo CoreData rất riêng .


7
Ví dụ tốt đẹp. Điều này có lẽ nên là một enum thay vì một cấu trúc mặc dù.
quét và quét

3
Đó là một triển khai kỳ lạ của enum, nếu bạn chỉ có hằng số tĩnh, nó cũng có thể là một cấu trúc.
Craig Grummitt 14/03/2016

1
Mã này là sai. Không sử dụng các phương thức KVC setValue(_:forKey:)để lưu dữ liệu vào UserDefaults. Sử dụng các UserDefaultsphương thức được cung cấp của set(_:forKey:)(trong Swift 3).
rmaddy

Tôi đã cập nhật mã Swift 3. Tôi không biết cú pháp Swift 2 nên là gì.
rmaddy

@rmaddy cũng tốt thôi.
Wez

57

Họ nói sử dụng NSUserDefaults

Khi tôi triển khai lưu trữ dữ liệu dài hạn (sau khi đóng ứng dụng) lần đầu tiên, mọi thứ tôi đọc trực tuyến đều hướng tôi đến NSUserDefaults. Tuy nhiên, tôi muốn lưu trữ một cuốn từ điển và, mặc dù có thể, nó đã được chứng minh là một nỗi đau. Tôi đã dành hàng giờ cố gắng để có được lỗi loại để biến mất.

NSUserDefaults cũng bị hạn chế về chức năng

Đọc thêm cho thấy cách đọc / ghi của NSUserDefaults thực sự buộc ứng dụng phải đọc / ghi mọi thứ hoặc không có gì, tất cả cùng một lúc, vì vậy nó không hiệu quả. Sau đó, tôi đã học được rằng việc lấy một mảng không phải là thẳng. Tôi nhận ra rằng nếu bạn lưu trữ nhiều hơn một vài chuỗi hoặc booleans, NSUserDefaults thực sự không lý tưởng.

Nó cũng không thể mở rộng. Nếu bạn đang học cách viết mã, hãy học cách mở rộng. Chỉ sử dụng NSUserDefaults để lưu trữ các chuỗi hoặc booleans đơn giản liên quan đến tùy chọn. Lưu trữ mảng và dữ liệu khác bằng Core Data, nó không khó như họ nói. Chỉ cần bắt đầu nhỏ.

Cập nhật: Ngoài ra, nếu bạn thêm hỗ trợ Apple Watch, sẽ có một sự cân nhắc tiềm năng khác. NSUserDefaults của ứng dụng của bạn giờ đây sẽ tự động được gửi đến Tiện ích mở rộng đồng hồ.

Sử dụng dữ liệu cốt lõi

Vì vậy, tôi đã bỏ qua các cảnh báo về Core Data là một giải pháp khó khăn hơn và bắt đầu đọc. Trong vòng ba giờ tôi đã có nó làm việc. Tôi đã lưu mảng bảng của mình trong Dữ liệu lõi và tải lại dữ liệu khi mở ứng dụng sao lưu! Mã hướng dẫn đủ dễ để thích nghi và tôi đã có thể lưu nó cả mảng tiêu đề và chi tiết chỉ với một chút thử nghiệm.

Vì vậy, đối với bất kỳ ai đọc bài đăng này, những người đang đấu tranh với các vấn đề loại NSUserDefault hoặc có nhu cầu nhiều hơn là lưu trữ chuỗi, hãy xem xét dành một hoặc hai giờ để chơi với dữ liệu cốt lõi.

Đây là hướng dẫn tôi đọc:

http://www.raywenderlich.com/85578/first-core-data-app-USE-swift

Nếu bạn không kiểm tra "Dữ liệu cốt lõi"

Nếu bạn không kiểm tra "Dữ liệu cốt lõi" khi bạn tạo ứng dụng của mình, bạn có thể thêm nó sau và chỉ mất năm phút:

http://craig24.com/2014/12/how-to-add-core-data-to-an-ex hiện-swift-project-in-xcode /

http://blog.zeityer.com/post/119012600864/adding-core-data-to-an-ex hiện-swift-project

Cách xóa khỏi danh sách dữ liệu cốt lõi

Xóa dữ liệu khỏi Coredata Swift


6
Có một nền tảng trung bình là lưu dữ liệu của bạn vào tệp .plist ở đâu đó trong thư mục Tài liệu hoặc ở nơi khác trong thư mục hộp cát của ứng dụng.
Nicolas Miari

Tôi là một người mới, vì vậy hãy đặt câu hỏi này với một hạt muối, nhưng đó có phải là trung dung không? NSUserDefaults thực tế là một tệp p.list, vì vậy (dựa trên những gì tôi đã đọc) lưu vào tệp p.list trong thư mục tài liệu cũng giống như sử dụng NSUserDefaults. Lý do tôi không sử dụng phương pháp đó là vì lưu một mảng vào p.list nghe có vẻ như nó liên quan đến các bước bổ sung, như chuyển đổi nó sang loại khác và sau đó, khi khôi phục các giá trị, nó yêu cầu gán lại các giá trị sau khi đọc chúng từ danh sách p.list. Một lần nữa, chỉ dựa trên việc tôi đọc trong vài ngày qua.
Dave G

Chà, việc lưu một mảng vào tệp .plist khá đơn giản (tất cả các đối tượng trong hệ thống phân cấp là Mảng, Chuỗi, Từ điển hoặc Số (không có lớp tùy chỉnh).
Nicolas Miari

Đồng ý, đọc tệp là tất cả hoặc không có gì, nhưng bạn có thể chia dữ liệu của mình thành các tệp riêng biệt tùy thuộc vào cấu trúc của nó. Và CoreData đã có một lộ trình học tập đáng kể, ít nhất là lần cuối cùng tôi kiểm tra.
Nicolas Miari

3
Tôi sẽ nói: sử dụng NSUserDefaults để lưu trữ các tùy chọn (đó chính là tên của nó), Móc khóa để lưu trữ dữ liệu liên tục và / hoặc nhạy cảm, lược đồ tùy chỉnh của bạn cho các tệp .plist cho dữ liệu được tạo ứng dụng rất cơ bản và CoreData cho các nội dung nặng hơn .
Nicolas Miari

11

Okey cảm ơn @bploat và liên kết đến http://www.codingexplorer.com/nsuserdefaults-a-swift-int sinhtion /

Tôi thấy rằng câu trả lời khá đơn giản đối với một số lưu trữ chuỗi cơ bản.

let defaults = NSUserDefaults.standardUserDefaults()

// Store
defaults.setObject("theGreatestName", forKey: "username")

// Receive
if let name = defaults.stringForKey("username")
{
    print(name)
    // Will output "theGreatestName"
}

Tôi đã tóm tắt ở đây http://ridewing.se/blog/save-local-data-in-swift/


9

Sử dụng NSCoding và NSKeyedArchiver là một tùy chọn tuyệt vời khác cho dữ liệu quá phức tạp NSUserDefaults, nhưng CoreData sẽ quá mức cần thiết. Nó cũng cung cấp cho bạn cơ hội để quản lý cấu trúc tệp rõ ràng hơn, điều này thật tuyệt nếu bạn muốn sử dụng mã hóa.


7

Đối với Swift 4.0, điều này trở nên dễ dàng hơn:

let defaults = UserDefaults.standard
//Set
defaults.set(passwordTextField.text, forKey: "Password")
//Get
let myPassword = defaults.string(forKey: "Password")

6

Swift 3.0

Setter: Lưu trữ cục bộ

let authtoken = "12345"
    // Userdefaults helps to store session data locally 
 let defaults = UserDefaults.standard                                           
defaults.set(authtoken, forKey: "authtoken")

 defaults.synchronize()

Getter: Lưu trữ cục bộ

 if UserDefaults.standard.string(forKey: "authtoken") != nil {

//perform your task on success }

2
Bạn không nên lưu smth như authtoken trong UserDefaults..Xin vui lòng sử dụng Keychain cho việc này
BilalReffas

5

Dành cho Swift 3

UserDefaults.standard.setValue(token, forKey: "user_auth_token")
print("\(UserDefaults.standard.value(forKey: "user_auth_token")!)")

Không sử dụng các phương pháp KVC để lưu dữ liệu.
rmaddy

4

Đối với một số người không thích xử lý UserDefaults vì một số lý do, có một tùy chọn khác - NSKeyedArchiver & NSKeyedUnarchiver. Nó giúp lưu các đối tượng vào một tệp bằng cách sử dụng lưu trữ và tải tệp lưu trữ vào các đối tượng gốc.

// To archive object,
let mutableData: NSMutableData = NSMutableData()
let archiver: NSKeyedArchiver = NSKeyedArchiver(forWritingWith: mutableData)
archiver.encode(object, forKey: key)
archiver.finishEncoding()
return mutableData.write(toFile: path, atomically: true)

// To unarchive objects,
if let data = try? Data(contentsOf: URL(fileURLWithPath: path)) {
    let unarchiver = NSKeyedUnarchiver(forReadingWith: data)
    let object = unarchiver.decodeObject(forKey: key)
}

Tôi đã viết một tiện ích đơn giản để lưu / tải các đối tượng trong bộ nhớ cục bộ, đã sử dụng các mã mẫu ở trên. Bạn có thể muốn thấy điều này. https://github.com/DragonCherry/LocalStorage


3

Swift 5+

Không có câu trả lời nào thực sự bao gồm chi tiết về khả năng lưu trữ cục bộ mặc định. Nó có thể làm nhiều hơn là chỉ chuỗi.

Bạn có các tùy chọn sau trực tiếp từ tài liệu apple để lấy 'dữ liệu' từ mặc định.

func object(forKey: String) -> Any?
//Returns the object associated with the specified key.

func url(forKey: String) -> URL?
//Returns the URL associated with the specified key.

func array(forKey: String) -> [Any]?
//Returns the array associated with the specified key.

func dictionary(forKey: String) -> [String : Any]?
//Returns the dictionary object associated with the specified key.

func string(forKey: String) -> String?
//Returns the string associated with the specified key.

func stringArray(forKey: String) -> [String]?
//Returns the array of strings associated with the specified key.

func data(forKey: String) -> Data?
//Returns the data object associated with the specified key.

func bool(forKey: String) -> Bool
//Returns the Boolean value associated with the specified key.

func integer(forKey: String) -> Int
//Returns the integer value associated with the specified key.

func float(forKey: String) -> Float
//Returns the float value associated with the specified key.

func double(forKey: String) -> Double
//Returns the double value associated with the specified key.

func dictionaryRepresentation() -> [String : Any]
//Returns a dictionary that contains a union of all key-value pairs in the domains in the search list.

Dưới đây là các tùy chọn cho 'cài đặt'

func set(Any?, forKey: String)
//Sets the value of the specified default key.

func set(Float, forKey: String)
//Sets the value of the specified default key to the specified float value.

func set(Double, forKey: String)
//Sets the value of the specified default key to the double value.

func set(Int, forKey: String)
//Sets the value of the specified default key to the specified integer value.

func set(Bool, forKey: String)
//Sets the value of the specified default key to the specified Boolean value.

func set(URL?, forKey: String)
//Sets the value of the specified default key to the specified URL.

Nếu đang lưu trữ những thứ như sở thíchkhông phải là một tập dữ liệu lớn thì đây là những lựa chọn hoàn toàn tốt.

Ví dụ kép :

Cài đặt:

let defaults = UserDefaults.standard
var someDouble:Double = 0.5
defaults.set(someDouble, forKey: "someDouble")

Bắt:

let defaults = UserDefaults.standard
var someDouble:Double = 0.0
someDouble = defaults.double(forKey: "someDouble")

Điều thú vị về một trong những getters là từ điển Xuất hiện , trình getter tiện dụng này sẽ lấy tất cả các loại dữ liệu của bạn bất kể chúng là gì và đưa chúng vào một từ điển đẹp mà bạn có thể truy cập bằng tên chuỗi của nó và đưa ra loại dữ liệu tương ứng chính xác khi bạn yêu cầu nó trở lại vì nó thuộc loại 'bất kỳ' .

Bạn cũng có thể lưu trữ các lớp và đối tượng của riêng mình bằng cách sử dụng func set(Any?, forKey: String)func object(forKey: String) -> Any?setter và getter tương ứng.

Hy vọng điều này làm rõ hơn sức mạnh của lớp UserDefaults để lưu trữ dữ liệu cục bộ.

Về lưu ý về số lượng bạn nên lưu trữ và tần suất, Hardy_Germany đã đưa ra một câu trả lời tốt về điều đó trên bài đăng này , đây là một trích dẫn từ nó

Như nhiều người đã đề cập: Tôi không nhận thấy bất kỳ giới hạn SIZE nào (ngoại trừ bộ nhớ vật lý) để lưu trữ dữ liệu trong .plist (ví dụ: UserDefaults). Vì vậy, nó không phải là một câu hỏi NHIỀU.

Câu hỏi thực sự là LÀM THẾ NÀO khi bạn viết các giá trị mới / thay đổi ... Và điều này có liên quan đến việc hao pin mà việc ghi này sẽ gây ra.

IOS không có cơ hội tránh ghi vật lý vào "đĩa" nếu một giá trị duy nhất thay đổi, chỉ để giữ tính toàn vẹn dữ liệu. Về UserDefaults, điều này khiến toàn bộ tệp được ghi lại vào đĩa.

Điều này sẽ tăng sức mạnh cho "đĩa" và giữ cho nó hoạt động lâu hơn và ngăn iOS chuyển sang trạng thái năng lượng thấp.

Một điều khác cần lưu ý như được đề cập bởi người dùng Mohammad Reza Farahani từ bài đăng này là bản chất không đồng bộđồng bộ của userDefaults.

Khi bạn đặt một giá trị mặc định, nó sẽ thay đổi đồng bộ trong quy trình của bạn và không đồng bộ thành lưu trữ liên tục và các quy trình khác.

Ví dụ: nếu bạn lưu và nhanh chóng đóng chương trình, bạn có thể nhận thấy nó không lưu kết quả, điều này là do nó tồn tại không đồng bộ. Bạn có thể không nhận thấy điều này mọi lúc, vì vậy nếu bạn có kế hoạch tiết kiệm trước khi thoát khỏi chương trình, bạn có thể muốn tính đến việc này bằng cách cho nó một chút thời gian để kết thúc.

Có lẽ ai đó có một số giải pháp tốt cho việc này mà họ có thể chia sẻ trong các ý kiến?


0

NsUserDefaults chỉ lưu các kích thước biến nhỏ. Nếu bạn muốn lưu nhiều đối tượng, bạn có thể sử dụng CoreData làm giải pháp gốc hoặc tôi đã tạo một thư viện giúp bạn lưu các đối tượng dễ dàng như hàm .save (). Nó dựa trên SQLite.

SundeedQLite

Kiểm tra nó và cho tôi biết ý kiến ​​của bạn

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.