如何在 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 应用程序中保存本地数据?的主要内容,如果未能解决你的问题,请参考以下文章

我可以在颤振应用程序中保存本地磁盘数据库吗?文档目录在哪里创建路径?

如何在核心数据中保存单个实体

通过共享扩展从图库中保存照片时 NSData WriteToFile 失败

在swiftui中保存照片?

如何在 Symfony2 中保存视图中的数据

在Flutter中保存照片(尤其是相机胶卷)