存储和读取待办事项
你现在新增的任何待办事项,都会随着app的运行中断而消失,删除掉的条目则会在app重新运行后再次出现,这不是一个真实的app应有的表现。
得益于iOS系统的多任务处理功能,一个app可以在用户退回主界面(按下home键)或者打开另一个app时,当前的app会被悬挂到后台运行,被悬挂到后台的app仍然保留它的数据。
但是并不是每个用户都是这样使用app的,有时用户会关闭掉多余的app以释放手机的内存(双击home键,并且向上滑动关闭app),或者说重启了设备,被关闭掉的app将释放掉它占用的内存和数据。如果发生了上述情况,那么我们所做的所有改变,不管是新增、编辑或者删除,都会被释放掉,第二次运行app的时候又会回到app的初始状态,相当于你什么都没做。
所以仅仅将app的数据保存在内存中是不够的,因为没有任何保证可以使你的app永远不被关闭。
你要做的是,在iPhone的闪存里持久化的存贮这些数据。这和我们保存一个word文档的作用是一样的,只是我们需要编程让app自动去处理这件事。
在app中,用户不需要点击Save之类的按钮来进行保存。
在这一小节,你将要做以下几件事:
1、决定在系统的哪个位置来保存你用于存储待办事项清单的文件。
2、将待办事项清单存储到那个文件去,无论是新增、编辑还是删除。
3、当app中断后重启启动时,读取这个保存的文件。
让我们一点点的开始。
iOS的文档目录
iOS的app都被存储在一个封闭的环境中,就是那个叫做“沙盒”的环境。每个app都有自己的目录用于存储文件,而且绝不允许从其他app的目录中读取文件。
这是一种安全保证机制,用于避免恶意软件比如病毒造成破坏。如果一个app仅可以改变自己生成的文件,就不会对系统的其他部分造成影响了。
在app所属的沙盒中,你可以将文件存储在一个叫做“Docments(文档)”的地方。
文档目录中的内容支持同步到iTunes或者iCloud。
当你发布了app的新版本,并且用户下载更新后,文档目录是不受影响的。即使app更新后,任何保存到文档的数据也都不受影响。
换句话说,文档目录就是你保存数据文件的绝佳位置。
让我们来看看它是怎么工作的。
打开ChecklistViewController.swift,并且添加以下方法:
func documentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
func dataFilePath() -> URL {
return documentsDirectory().appendingPathComponent("Checklists.plist")
}
documentsDirectory()方法是我添加的一个便利化的方法,目前没有标准方法给你用于得到指向文档文件夹的路径,所以我自己写了一个。
dataFilePath() 方法使用documentsDirectory()的返回结果构建了路径到存储待办事项清单的文件。这个文件的名称是Checklists.plist,并且这个文件存储在文档目录中。
注意一下,以上两个方法都返回一个URL对象。iOS系统使用URLs在文件系统上引用文件。就像上网的时候使用http://URL,你在寻找文件的时候使用file://URL。
⚠️:检查一下documentsDirectory()方法中写的是.documentDirectory而不是.documentationDirectory。Xcode的自动补写功能经常会在这里弄混。
还是在ChecklistViewController.swift文件中,在init方法中添加两个打印语句,就添加在super.init()后面:
required init?(coder aDecoder: NSCoder) {
...
super.init(coder: aDecoder)
print("Documents folder is \(documentsDirectory())")
print("Data file path is \(dataFilePath())")
}
运行app,Xcode的调试区域会显示你app的文档目录第实际路径。
比如我在模拟器中运行结果显示为:
Documents folder is file:///Users/matthijs/Library/Developer/
CoreSimulator/Devices/66422991-21E3-4394-8DCE-0584865EA854/data/
Containers/Data/Application/96643C0B-2772-48D1-AD93-DBC2ACD4B779/
Documents/
Data file path is file:///Users/matthijs/Library/Developer/CoreSimulator/
Devices/66422991-21E3-4394-8DCE-0584865EA854/data/Containers/Data/
Application/96643C0B-2772-48D1-AD93-DBC2ACD4B779/Documents/
Checklists.plist
如果你是在iPhone上运行的话,它会显示为下面这个样子:
Documents folder is file:///var/mobile/Applications/
FDD50B54-9383-4DCC-9C19-C3DEBC1A96FE/Documents
Data file path is file:///var/mobile/Applications/FDD50B54-9383-4DCC-9C19-C3DEBC1A96FE/Documents/Checklists.plist
在模拟器中包含app文档文件夹内容的文件夹名称是“96643C0B-2772-48D1-AD93-DBC2ACD4B779”,而在实际设备中这个名称是“FDD50B54-9383-4DCC-9C19-C3DEBC1A96FE”,你不需要记住它们,也根本记不住。
这个文件夹名称是一个随机的ID,当app在模拟器中或者设备中初始化的时候自动生成的。任何在该文件夹中的内容都属于app的沙盒的一部分。
在这节课中,我们全程都会在模拟器中运行app,不会在设备上运行,因为在模拟器中运行时,这些文件是保存在Mac电脑的硬盘上的,你可以轻易的查看这些文件。
在桌面上打开finder,然后使用command+shift+G键,打开前往文件夹窗口,输入我们刚才得到的路径,就可以找到这些文件了,输入的时候从/User/...开始就可以,不需要加File://,也不要加Checklists.plist,现在这个文件还不存在 。
然后finder窗口会跳转到模拟器的Document文件夹。不要关闭这个窗口,你可以在这个窗口中观察到Checklists.plist文件的创建。
小贴示:如果你打算手动寻找模拟器的文档目录,那么你需要按住Option键,因为Library这个目录是隐藏的。
目前你可以观察到以下几点:
1、Documents目录是用来保存数据文件的,目前这个目录下没有东西,是空的。
2、LIbrary目录包含cache(闪存)和preference(参数)文件。这些文件由操作系统管理。
3、tmp目录是用来保存临时文件的。有时app会需要保存一些临时文件。每次app关闭后,临时文件会被清理掉。
iPhone设备中的Documents目录也可以打开,在手机中找到Settings
->General->Usage.在Storage & iCloud Usage中点击Manage Storage并且选择app的名称。就可以看到Documents目录了: