SwiftUI: 将数据写入文档目录
之前,我们研究了如何向UserDefaults
读取和写入数据,该方法非常适合用户偏好设置或者是少量的 JSON。但是,那通常不是存储数据的好地方,特别是如果您认为将来会开始存储更多数据。
在此应用中,我们将允许用户创建所需数量的数据,这意味着我们希望有一个更好的存储解决方案,并希望获得最佳结果,而不仅仅是将其放入UserDefaults
中。幸运的是,iOS使从设备存储中读取和写入数据变得非常容易,实际上,所有应用程序都有一个目录来存储我们想要的任何类型的文档。此处的文件会自动与 iCloud 备份同步,因此,如果用户使用新设备,则我们的数据将与所有其他系统数据一起还原——我们甚至无需考虑它。
有一个陷阱——该目录总是存在吗?——所有iOS应用程序都经过沙盒处理,这意味着它们在带有难以猜测目录名称的容器中运行。因此,我们不能(也不应尝试)猜测应用程序的安装目录,而需要依靠Apple的API查找应用程序的文档目录。
没有很好的方法,所以我几乎总是将相同的帮助程序方法复制并粘贴到我的项目中,现在我们将做完全相同的事情。这使用了一个称为FileManager
的新类,该类可以为我们提供当前用户的文档目录。从理论上讲,它可以返回几个路径URL,但是我们只关心第一个。
因此,将此方法添加到ContentView
中:
func getDocumentsDirectory() -> URL {
// 查找该用户的所有可能的文档目录
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
// 只需返回第一个,应该是唯一的一个
return paths[0]
}
该文档目录是我们自己需要处理的,并且由于它属于该应用程序,因此如果该应用程序本身被删除,它将自动被删除。除了物理设备限制外,我们没有多少存储空间限制,尽管请记住,用户可以使用``设置''应用程序查看您的应用程序占用了多少存储空间——谨记!
现在我们有了一个可以使用的目录,我们可以在那里自由地读写文件。您已经见过了用于读取数据的String(contentsOf:)
和Data(contentsOf :)
,但是对于写入数据,我们需要使用write(to:)
方法。与字符串一起使用时,它需要三个参数:
- 要写入的URL。
- 是否使写入原子化,这意味着“全部一次性”。
- 使用什么字符编码。
可以通过将文档目录URL与文件名(例如myfile.txt
)组合来创建其中的第一个。
第二个几乎应该始终设置为 true
。如果将其设置为false
并且我们尝试写入大文件,则我们应用的另一部分可能会尝试在仍在写入文件的同时读取该文件。这不会导致崩溃或其他任何事情,但这确实意味着它将仅读取部分数据,因为尚未写入其他部分。原子写入会导致系统将完整文件写入一个临时文件名(而不是我们要求的文件名),完成后,它会简单地重命名为目标文件名。这意味着要么整个文件都存在,要么什么都没有。
第三个参数是我们在项目5中简要介绍的内容,因为我们必须将 Swift 字符串与 Objective-C API 结合使用。那时我们使用了字符编码 UTF-16,这是 Objective-C 所使用的,但是 Swift 的本机编码是 UTF-8,因此我们将改用它。
为了将所有这些代码付诸实践,我们将修改模板的默认文本视图,以便将测试字符串写入documents
目录中的文件,再将其读回新字符串,然后将其打印出来——完成读写数据的周期。
将ContentView
的 body
属性更改为如下代码:
Text("Hello World")
.onTapGesture {
let str = "测试消息"
let url = self.getDocumentsDirectory().appendingPathComponent("message.txt")
do {
try str.write(to: url, atomically: true, encoding: .utf8)
let input = try String(contentsOf: url)
print(input)
} catch {
print(error.localizedDescription)
}
}
运行该程序后,您应该可以点击标签以查看“测试消息”,该消息已打印到 Xcode 的调试输出区域。
在继续之前,这对您来说是一个小挑战:在项目8中,我们研究了如何在 Bundle
上创建通用扩展,该扩展使我们能够查找,加载和解码应用程序包中的所有可编码数据。您是否可以为documents
目录编写类似的内容,也许可以将其作为FileManager
的一个扩展?
- HDUOJ----3342Legal or Not
- go语言基本类型
- HDUOJ----2647Reward
- hduoj------确定比赛名次
- HDUOJ----1165Eddy's research II
- HDUOJ-----1556Color the ball
- HDUOJ-----2175取(m堆)石子游戏
- Golang语言社区-Go语言递归
- go语言mongdb管道使用(一)
- HDUOJ---------2255奔小康赚大钱
- HDUOJ------1711Number Sequence
- HDUOJ---1712 ACboy needs your help
- HDUOJ---1867 A + B for you again
- HDUOJ--------1420Prepared for New Acmer
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Laravel 手动开关 Eloquent 修改器的操作方法
- 怎么测试Linux下tcp最大连接数限制详解
- Laravel 5.1 框架Blade模板引擎用法实例分析
- 使用pygame实现垃圾分类小游戏功能(已获校级二等奖)
- Linux 系统下安装JDK1.8的教程详解
- php学习笔记之字符串常见操作总结
- Laravel5.1 框架模型工厂ModelFactory用法实例分析
- 关于AIX挂载NFS写入效率低效的解决办法
- Linux系统下部署项目的设置办法
- PHP利用缓存处理用户注册时的邮箱验证,成功后用户数据存入数据库操作示例
- ubantu 16.4下Hadoop完全分布式搭建实战教程
- Laravel5.1 框架模型查询作用域定义与用法实例分析
- 整理Linux中字符串的相关操作技巧
- Laravel5.1 框架Middleware中间件基本用法实例分析
- Linux基础命令之mktemp详解