ios 如何在 Swift 应用程序中保存本地数据?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28628225/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to save local data in a Swift app?
提问by Nicklas Ridewing
I'm currently working on a iOS app developed in Swift and I need to store some user-created content on the device but I can't seem to find a simple and quick way to store/receive the users content on the device.
我目前正在开发一个用 Swift 开发的 iOS 应用程序,我需要在设备上存储一些用户创建的内容,但我似乎找不到一种简单快捷的方法来存储/接收设备上的用户内容。
Could someone explain how to store and access local storage?
有人可以解释如何存储和访问本地存储吗?
The idea is to store the data when the user executes an action and receive it when the app starts.
这个想法是在用户执行操作时存储数据并在应用程序启动时接收它。
回答by Wez
The simplest solution if you are just storing two strings is NSUserDefaults
, in Swift 3 this class has been renamed to just UserDefaults
.
如果您只存储两个字符串NSUserDefaults
,最简单的解决方案是,在 Swift 3 中,此类已重命名为 just UserDefaults
。
It's best to store your keys somewhere globally so that you can reuse them elsewhere in your code.
最好将您的密钥存储在全局某个地方,以便您可以在代码的其他地方重用它们。
struct defaultsKeys {
static let keyOne = "firstStringKey"
static let keyTwo = "secondStringKey"
}
Swift 3.0, 4.0 & 5.0
斯威夫特 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
斯威夫特 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
}
For anything more serious than minor config, flags or base strings you should use some sort of persistent store - A popular option at the moment is Realmbut you can also use SQLiteor Apples very own CoreData.
对于比次要配置、标志或基本字符串更严重的任何事情,您应该使用某种持久存储 - 目前一个流行的选择是Realm但您也可以使用SQLite或 Apple 自己的CoreData。
回答by Dave G
They Say Use NSUserDefaults
他们说使用 NSUserDefaults
When I was implementing long term (after app close) data storage for the first time, everything I read online pointed me towards NSUserDefaults. However, I wanted to store a dictionary and, although possible, it was proving to be a pain. I spent hours trying to get type-errors to go away.
当我第一次实现长期(应用程序关闭后)数据存储时,我在网上阅读的所有内容都指向了 NSUserDefaults。然而,我想存储一本字典,虽然可能,但事实证明这是一种痛苦。我花了几个小时试图让类型错误消失。
NSUserDefaults is Also Limited in Function
NSUserDefaults 在功能上也有限制
Further reading revealed how the read/write of NSUserDefaults really forces the app to read/write everything or nothing, all at once, so it isn't efficient. Then I learned that retrieving an array isn't straight forward. I realized that if you're storing more than a few strings or booleans, NSUserDefaults really isn't ideal.
进一步阅读揭示了 NSUserDefaults 的读/写如何真正强制应用程序一次读/写所有内容或什么都不读/写,因此效率不高。然后我了解到检索数组并不简单。我意识到,如果您存储的字符串或布尔值不止几个,那么 NSUserDefaults 确实不理想。
It's also not scalable. If you're learning how to code, learn the scalable way. Only use NSUserDefaults for storing simple strings or booleans related to preferences. Store arrays and other data using Core Data, it's not as hard as they say. Just start small.
它也不是可扩展的。如果您正在学习如何编码,请学习可扩展的方式。仅使用 NSUserDefaults 来存储与首选项相关的简单字符串或布尔值。使用 Core Data 存储数组和其他数据,并不像他们说的那么难。从小事做起。
Update: Also, if you add Apple Watch support, there's another potential consideration. Your app's NSUserDefaults is now automatically sent to the Watch Extension.
更新:此外,如果您添加 Apple Watch 支持,还有另一个潜在的考虑因素。您的应用程序的 NSUserDefaults 现在会自动发送到 Watch Extension。
Using Core Data
使用核心数据
So I ignored the warnings about Core Data being a more difficult solution and started reading. Within three hours I had it working. I had my table array being saved in Core Data and reloading the data upon opening the app back up! The tutorial code was easy enough to adapt and I was able to have it store both title and detail arrays with only a little extra experimenting.
所以我忽略了关于 Core Data 是一个更困难的解决方案的警告并开始阅读。在三个小时内,我让它工作了。我将表数组保存在 Core Data 中,并在打开应用程序备份时重新加载数据!教程代码很容易适应,我只需做一点额外的实验就可以让它存储标题和细节数组。
So for anyone reading this post who's struggling with NSUserDefault type issues or whose need is more than storing strings, consider spending an hour or two playing with core data.
因此,对于正在为 NSUserDefault 类型问题苦苦挣扎或需要的不仅仅是存储字符串的阅读这篇文章的任何人,请考虑花一两个小时来处理核心数据。
Here's the tutorial I read:
这是我阅读的教程:
http://www.raywenderlich.com/85578/first-core-data-app-using-swift
http://www.raywenderlich.com/85578/first-core-data-app-using-swift
If you didn't check "Core Data"
如果您没有选中“核心数据”
If you didn't check "Core Data"when you created your app, you can add it after and it only takes five minutes:
如果你在创建你的应用程序时没有勾选“Core Data”,你可以在之后添加它,只需要五分钟:
http://craig24.com/2014/12/how-to-add-core-data-to-an-existing-swift-project-in-xcode/
http://craig24.com/2014/12/how-to-add-core-data-to-an-existing-swift-project-in-xcode/
http://blog.zeityer.com/post/119012600864/adding-core-data-to-an-existing-swift-project
http://blog.zeityer.com/post/119012600864/adding-core-data-to-an-existing-swift-project
How to Delete from Core Data Lists
如何从核心数据列表中删除
回答by Nicklas Ridewing
Okey so thanks to @bploatand the link to http://www.codingexplorer.com/nsuserdefaults-a-swift-introduction/
好的,感谢@bploat和http://www.codingexplorer.com/nsuserdefaults-a-swift-introduction/的链接
I've found that the answer is quite simple for some basic string storage.
我发现对于一些基本的字符串存储,答案非常简单。
let defaults = NSUserDefaults.standardUserDefaults()
// Store
defaults.setObject("theGreatestName", forKey: "username")
// Receive
if let name = defaults.stringForKey("username")
{
print(name)
// Will output "theGreatestName"
}
I've summarized it here http://ridewing.se/blog/save-local-data-in-swift/
回答by Patrick Lynch
Using NSCoding and NSKeyedArchiveris another great option for data that's too complex for NSUserDefaults
, but for which CoreData would be overkill. It also gives you the opportunity to manage the file structure more explicitly, which is great if you want to use encryption.
使用NSCoding和的NSKeyedArchiver是数据的另一种不错的选择那是太复杂NSUserDefaults
,但其CoreData将是矫枉过正。它还使您有机会更明确地管理文件结构,如果您想使用加密,这非常有用。
回答by LevinsonTechnologies
For Swift 4.0, this got easier:
对于 Swift 4.0,这变得更容易了:
let defaults = UserDefaults.standard
//Set
defaults.set(passwordTextField.text, forKey: "Password")
//Get
let myPassword = defaults.string(forKey: "Password")
回答by Ravindra Shekhawat
Swift 3.0
斯威夫特 3.0
Setter :Local Storage
设置器:本地存储
let authtoken = "12345"
// Userdefaults helps to store session data locally
let defaults = UserDefaults.standard
defaults.set(authtoken, forKey: "authtoken")
defaults.synchronize()
Getter:Local Storage
吸气剂:本地存储
if UserDefaults.standard.string(forKey: "authtoken") != nil {
//perform your task on success }
回答by Arun Yokesh
For Swift 3
对于 Swift 3
UserDefaults.standard.setValue(token, forKey: "user_auth_token")
print("\(UserDefaults.standard.value(forKey: "user_auth_token")!)")
回答by DragonCherry
For someone who'd not prefer to handle UserDefaults for some reasons, there's another option - NSKeyedArchiver & NSKeyedUnarchiver. It helps save objects into a file using archiver, and load archived file to original objects.
对于由于某些原因不喜欢处理 UserDefaults 的人,还有另一种选择 - NSKeyedArchiver 和 NSKeyedUnarchiver。它有助于使用存档器将对象保存到文件中,并将存档文件加载到原始对象中。
// 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)
}
I've write an simple utility to save/load objects in local storage, used sample codes above. You might want to see this. https://github.com/DragonCherry/LocalStorage
我编写了一个简单的实用程序来在本地存储中保存/加载对象,使用了上面的示例代码。你可能想看看这个。 https://github.com/DragonCherry/LocalStorage
回答by Joseph Astrahan
Swift 5+
斯威夫特 5+
None of the answers really cover in detail the default built in local storage capabilities. It can do far more than just strings.
没有一个答案真正详细地涵盖了默认内置的本地存储功能。它可以做的不仅仅是字符串。
You have the following options straight from the apple documentation for 'getting' data from the defaults.
您可以直接从苹果文档中获得以下选项,用于从默认值中“获取”数据。
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.
Here are the options for 'setting'
这是“设置”的选项
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.
If are storing things like preferencesand not a large dataset these are perfectly fine options.
如果要存储首选项之类的内容而不是大型数据集,这些是非常好的选择。
Double Example:
双重示例:
Setting:
环境:
let defaults = UserDefaults.standard
var someDouble:Double = 0.5
defaults.set(someDouble, forKey: "someDouble")
Getting:
获得:
let defaults = UserDefaults.standard
var someDouble:Double = 0.0
someDouble = defaults.double(forKey: "someDouble")
What is interesting about one of the getters is dictionaryRepresentation, this handy getter will take all your data types regardless what they are and put them into a nice dictionary that you can access by it's string name and give the correct corresponding data type when you ask for it back since it's of type 'any'.
其中一个 getter 有趣的是dictionaryRepresentation,这个方便的 getter 将获取您所有的数据类型,无论它们是什么,并将它们放入一个不错的字典中,您可以通过它的字符串名称访问该字典,并在您要求时提供正确的相应数据类型它返回,因为它是'any'类型。
You can store your own classes and objects also using the func set(Any?, forKey: String)
and func object(forKey: String) -> Any?
setter and getter accordingly.
您也可以相应地使用func set(Any?, forKey: String)
和func object(forKey: String) -> Any?
setter 和 getter存储您自己的类和对象。
Hope this clarifies more the power of the UserDefaults class for storing local data.
希望这能进一步阐明 UserDefaults 类用于存储本地数据的功能。
On the note of how much you should store and how often, Hardy_Germanygave a good answer on that on this post, here is a quote from it
关于您应该存储多少以及存储频率,Hardy_Germany在这篇文章中给出了一个很好的答案,这里引用了它
As many already mentioned: I'm not aware of any SIZE limitation (except physical memory) to store data in a .plist (e.g. UserDefaults). So it's not a question of HOW MUCH.
The real question should be HOW OFTEN you write new / changed values... And this is related to the battery drain this writes will cause.
IOS has no chance to avoid a physical write to "disk" if a single value changed, just to keep data integrity. Regarding UserDefaults this cause the whole file rewritten to disk.
This powers up the "disk" and keep it powered up for a longer time and prevent IOS to go to low power state.
正如许多人已经提到的:我不知道将数据存储在 .plist(例如 UserDefaults)中的任何 SIZE 限制(物理内存除外)。所以这不是多少的问题。
真正的问题应该是你多久写入新的/更改的值......这与写入会导致电池消耗有关。
如果单个值更改,IOS 没有机会避免物理写入“磁盘”,只是为了保持数据完整性。关于 UserDefaults 这会导致整个文件重写到磁盘。
这会为“磁盘”加电并使其保持通电更长时间,并防止 IOS 进入低功耗状态。
Something else to note as mentioned by user Mohammad Reza Farahani from this postis the asynchronousand synchronousnature of userDefaults.
正如用户 Mohammad Reza Farahani 在这篇文章中提到的,还有一点需要注意的是userDefaults的异步和同步特性。
When you set a default value, it's changed synchronously within your process, and asynchronously to persistent storage and other processes.
当您设置默认值时,它会在您的流程中同步更改,并异步更改为持久存储和其他流程。
For example if you save and quickly close the program you may notice it does not save the results, this is because it's persisting asynchronously. You might not notice this all the time so if you plan on saving before quitting the program you may want to account for this by giving it some time to finish.
例如,如果您保存并快速关闭程序,您可能会注意到它没有保存结果,这是因为它是异步持久化的。您可能不会一直注意到这一点,因此如果您打算在退出程序之前进行保存,您可能需要通过给它一些时间来完成来解决这个问题。
Maybe someone has some nice solutions for this they can share in the comments?
也许有人对此有一些不错的解决方案,他们可以在评论中分享?
回答by nour sandid
NsUserDefaults saves only small variable sizes. If you want to save many objects you can use CoreData as a native solution, or I created a library that helps you save objects as easy as .save() function. It's based on SQLite.
NsUserDefaults 只保存小的变量大小。如果您想保存许多对象,您可以使用 CoreData 作为本机解决方案,或者我创建了一个库来帮助您保存对象,就像 .save() 函数一样简单。它基于 SQLite。
Check it out and tell me your comments
看看并告诉我你的意见