如何在 Swift 应用程序中保存本地数据?
Posted
技术标签:
【中文标题】如何在 Swift 应用程序中保存本地数据?【英文标题】:How to save local data in a Swift app? 【发布时间】:2022-01-18 03:46:30 【问题描述】:我目前正在开发一个用 Swift 开发的 ios 应用程序,我需要在设备上存储一些用户创建的内容,但我似乎找不到一种简单快捷的方法来存储/接收用户内容设备。
有人能解释一下如何存储和访问本地存储吗?
这个想法是在用户执行操作时存储数据,并在应用启动时接收数据。
【问题讨论】:
您好,欢迎您,您要存储什么样的数据?您能否提供任何代码来举例说明您正在寻找什么?谢谢。 我需要存储的数据基本上只是字符串数据。因此,为了保持简单,我需要保存两个 String 值,如果用户重新启动应用程序,我可以接收它们。 你可以使用 NSUserDefaults。这是您需要的信息codingexplorer.com/nsuserdefaults-a-swift-introduction 【参考方案1】:存储少量字符串或常见类型的最简单解决方案是UserDefaults。
UserDefaults 类提供方便的方法来访问常见类型,例如浮点数、双精度数、整数、布尔值和 URL。
UserDefaults
允许我们根据我们选择的键存储对象,最好将这些键存储在可访问的地方以便我们可以重复使用它们。
按键
struct DefaultsKeys
static let keyOne = "firstStringKey"
static let keyTwo = "secondStringKey"
设置
let defaults = UserDefaults.standard
defaults.set("Some String Value", forKey: DefaultsKeys.keyOne)
defaults.set("Another String Value", forKey: DefaultsKeys.keyTwo)
获取
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
斯威夫特 2.0
在 Swift 2.0 中,UserDefaults
被称为 NSUserDefaults
,而 setter 和 getter 的命名略有不同:
设置
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject("Some String Value", forKey: DefaultsKeys.keyOne)
defaults.setObject("Another String Value", forKey: DefaultsKeys.keyTwo)
获取
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
对于比次要配置更严重的事情,您应该考虑使用更强大的持久性存储:
CoreData Realm SQLite【讨论】:
很好的例子。不过,这可能应该是一个枚举而不是一个结构。 这是一个奇怪的枚举实现,如果你只有静态常量,它也可能是一个结构。 此代码错误。不要使用 KVC 方法setValue(_:forKey:)
将数据保存到 UserDefaults。使用 set(_:forKey:)
提供的 UserDefaults
方法(在 Swift 3 中)。
我更新了 Swift 3 代码。我不知道 Swift 2 的语法应该是什么。
@rmaddy 没关系。【参考方案2】:
他们说使用 NSUserDefaults
当我第一次实现长期(应用关闭后)数据存储时,我在网上阅读的所有内容都指向 NSUserDefaults。但是,我想存储一本字典,尽管有可能,但事实证明这很痛苦。我花了几个小时试图让类型错误消失。
NSUserDefaults 功能也有限
进一步阅读揭示了 NSUserDefaults 的读/写是如何真正迫使应用一次读/写所有内容或什么都不写,因此效率不高。然后我了解到检索数组并不是直截了当的。我意识到,如果您要存储多个字符串或布尔值,则 NSUserDefaults 确实不理想。
它也是不可扩展的。如果您正在学习如何编码,请学习可扩展的方式。仅使用 NSUserDefaults 来存储与首选项相关的简单字符串或布尔值。使用 Core Data 存储数组和其他数据,并不像他们说的那么难。从小事做起。
更新:此外,如果您添加 Apple Watch 支持,还有另一个潜在的考虑因素。您应用的 NSUserDefaults 现在会自动发送到 Watch Extension。
使用核心数据
所以我忽略了有关 Core Data 是一个更困难的解决方案的警告并开始阅读。在三个小时内,我让它工作了。我将表数组保存在 Core Data 中,并在打开应用程序备份时重新加载数据!教程代码很容易适应,我只需做一些额外的实验就可以让它同时存储标题和细节数组。
因此,对于阅读这篇文章的任何人如果遇到 NSUserDefault 类型问题或需要的不仅仅是存储字符串,请考虑花一两个小时来处理核心数据。
这是我阅读的教程:
http://www.raywenderlich.com/85578/first-core-data-app-using-swift
如果你没有勾选“核心数据”
如果您在创建应用时没有勾选“核心数据”,您可以在之后添加,只需五分钟:
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
如何从核心数据列表中删除
Delete Data from Coredata Swift
【讨论】:
将数据保存到 Documents 目录中某处或应用沙盒目录中其他位置的 .plist 文件的中间立场。 我是新手,所以对这个问题持保留态度,但这是中间立场吗? NSUserDefaults 实际上是一个 p.list 文件,所以(根据我读过的内容)保存到文档目录中的 p.list 文件与使用 NSUserDefaults 是一样的。我没有使用该方法的原因是因为将数组保存到 p.list 听起来像是涉及额外的步骤,例如将其转换为另一种类型,然后在恢复值时,需要在读取它们后重新分配值来自 p.list。同样,仅基于我过去几天的阅读。 嗯,将数组保存到 .plist 文件非常简单(层次结构中的所有对象都是数组、字符串、字典或数字(没有自定义类)。 同意,读取文件是孤注一掷,但您可以根据其结构将数据拆分为单独的文件。 CoreData 有一个显着的学习曲线,至少在我上次检查时是这样。 我想说:使用 NSUserDefaults 来存储首选项(毕竟这就是名称的意思),用于存储持久和/或敏感数据的钥匙串,您的 .plist 文件的自定义方案 very基本的 应用程序生成的数据,CoreData 用于更重的东西。【参考方案3】:好的,感谢@bploat 和http://www.codingexplorer.com/nsuserdefaults-a-swift-introduction/ 的链接
我发现对于一些基本的字符串存储来说,答案非常简单。
let defaults = NSUserDefaults.standardUserDefaults()
// Store
defaults.setObject("theGreatestName", forKey: "username")
// Receive
if let name = defaults.stringForKey("username")
print(name)
// Will output "theGreatestName"
我在这里总结了http://ridewing.se/blog/save-local-data-in-swift/
【讨论】:
【参考方案4】:对于对于NSUserDefaults
来说过于复杂的数据,使用NSCoding and NSKeyedArchiver 是另一个不错的选择,但CoreData 对这些数据来说可能是多余的。它还使您有机会更明确地管理文件结构,如果您想使用加密,这非常好。
【讨论】:
【参考方案5】:对于 Swift 4.0,这变得更容易了:
let defaults = UserDefaults.standard
//Set
defaults.set(passwordTextField.text, forKey: "Password")
//Get
let myPassword = defaults.string(forKey: "Password")
【讨论】:
【参考方案6】:Swift 5+
没有一个答案真正详细介绍了默认内置的本地存储功能。它可以做的不仅仅是字符串。
您可以直接从苹果文档中获得以下选项,用于从默认值中“获取”数据。
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.
这里是“设置”的选项
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.
如果要存储 首选项 和 不是大数据 集,这些都是非常好的选项。
双例:
设置:
let defaults = UserDefaults.standard
var someDouble:Double = 0.5
defaults.set(someDouble, forKey: "someDouble")
获取:
let defaults = UserDefaults.standard
var someDouble:Double = 0.0
someDouble = defaults.double(forKey: "someDouble")
其中一个 getter 的有趣之处在于 dictionaryRepresentation,这个方便的 getter 将获取您所有的数据类型,无论它们是什么,并将它们放入一个漂亮的字典中,您可以通过它的字符串名称和当您要求返回时,请给出正确的相应数据类型,因为它的类型是 'any'。
您也可以相应地使用func set(Any?, forKey: String)
和func object(forKey: String) -> Any?
setter 和getter 来存储自己的类和对象。
希望这能进一步阐明 UserDefaults 类在存储本地数据方面的强大功能。
关于您应该存储多少以及多久存储一次,Hardy_Germany 在 post 上给出了很好的答案,这是它的引述
正如许多人已经提到的:我不知道有任何 SIZE 限制 (物理内存除外)将数据存储在 .plist 中(例如 用户默认值)。所以这不是多少钱的问题。
真正的问题应该是你多久写一次新的/改变的 值...这与此写入的电池消耗有关 原因。
IOS 没有机会避免物理写入“磁盘”,如果单个 值改变,只是为了保持数据的完整性。关于 UserDefaults 这会导致整个文件重写到磁盘。
这会为“磁盘”加电并使其保持通电更长时间,并且 防止 IOS 进入低功耗状态。
用户 Mohammad Reza Farahani 在此 post 中提到的其他需要注意的是 userDefaults 的异步和同步性质。
当您设置默认值时,它会在您的内部同步更改 进程,并与持久存储和其他进程异步。
例如,如果您保存并快速关闭程序,您可能会注意到它没有保存结果,这是因为它是异步持久化的。您可能不会一直注意到这一点,因此如果您打算在退出程序之前保存,您可能希望通过给它一些时间来完成这一点。
也许有人对此有一些不错的解决方案,可以在 cmets 中分享?
【讨论】:
【参考方案7】:Swift 3.0
Setter:本地存储
let authtoken = "12345"
// Userdefaults helps to store session data locally
let defaults = UserDefaults.standard
defaults.set(authtoken, forKey: "authtoken")
defaults.synchronize()
Getter:本地存储
if UserDefaults.standard.string(forKey: "authtoken") != nil
//perform your task on success
【讨论】:
您不应该像 UserDefaults 中的 authtoken 那样保存 smth。请为此使用钥匙串【参考方案8】:对于 Swift 3
UserDefaults.standard.setValue(token, forKey: "user_auth_token")
print("\(UserDefaults.standard.value(forKey: "user_auth_token")!)")
【讨论】:
不要使用KVC方式保存数据。 不要在 UserDefaults 中存储令牌。使用 Keychian。【参考方案9】:对于由于某些原因不喜欢处理 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)
我编写了一个简单的实用程序来在本地存储中保存/加载对象,使用上面的示例代码。你可能想看看这个。 https://github.com/DragonCherry/LocalStorage
【讨论】:
【参考方案10】:NsUserDefaults 只保存小的变量大小。 如果您想保存许多对象,您可以使用 CoreData 作为本机解决方案,或者我创建了一个库,可以帮助您像 .save() 函数一样简单地保存对象。它基于 SQLite。
SundeedQLite
检查一下并告诉我你的cmets
【讨论】:
【参考方案11】:这很好地解释了如何在 Swift 5 中执行此操作:https://www.hackingwithswift.com/example-code/system/how-to-save-user-settings-using-userdefaults
总结:
设置一个值:
let defaults = UserDefaults.standard
defaults.set("value", forKey: "key")
获取字符串值:
let key = defaults.object(forKey: "StringKey") as? [String] ?? [String]()
获取整数值:
let key = defaults.integer(forKey: "IntegerKey")
【讨论】:
以上是关于如何在 Swift 应用程序中保存本地数据?的主要内容,如果未能解决你的问题,请参考以下文章
我可以在颤振应用程序中保存本地磁盘数据库吗?文档目录在哪里创建路径?