从默认系统中存储用户首选项到在关系数据库中管理大型数据集,大多数iOS应用程序都需要在所有应用程序启动过程中保持数据持久性。 在本文中,我们将探讨用于在iOS应用程序中存储数据的最常见策略。 我还将讨论iOS上的文件系统以及应用程序沙箱如何影响数据持久性。

介绍

您走了很长一段路,蚱way,您学到了很多东西。 但是,我们尚未讨论iOS开发的一个重要方面,即数据持久性。 几乎每个iOS应用程序都会存储数据以供以后使用。 您的应用程序存储的数据可以是任何东西,从用户首选项到临时缓存,甚至是大型关系数据集。

在讨论开发人员在iOS平台上采用的最常见的数据持久性策略之前,我将花一些时间来讨论文件系统和应用程序沙箱的概念。 您是否真的认为可以在文件系统上的任何位置存储应用程序的数据? 再想一想,padawan。

文件系统和应用程序沙箱

自2007年推出iPhone以来,iOS平台的安全性一直是Apple的首要任务之一。与OS X应用程序相比,iOS应用程序位于应用程序沙箱中。 应用程序的沙箱不仅引用文件系统中应用程序的沙箱目录。 它还包括对存储在设备,系统服务和硬件上的用户数据的受控访问和受限访问。

随着Mac App Store的推出,Apple也开始在OS X上强制执行应用程序沙箱。 即使对OS X应用程序施加的约束没有对iOS应用程序施加的约束那么严格,但基本概念是相似的。 虽然有区别。 例如,iOS应用程序的应用程序沙箱包含应用程序捆绑包,而OS X应用程序并非如此。 这些差异的原因主要是历史原因。

沙箱和目录

操作系统将每个iOS应用程序安装在沙箱目录中,该沙箱目录包含应用程序捆绑目录和三个附加目录: DocumentsLibrarytmp 。 可以通过调用简单的Foundation函数NSHomeDirectory()来访问应用程序的沙箱目录(通常称为其目录NSHomeDirectory()

print(NSHomeDirectory())

您可以自己尝试。 基于Single View Application模板创建一个新的Xcode项目,并将其命名为Data Persistence。


打开AppDelegate.swift并将上述代码片段添加到application(_:didFinishLaunchingWithOptions:) 。 如果您在模拟器中运行应用程序,则控制台中的输出应如下所示:

/Users/Bart/Library/Developer/CoreSimulator/Devices/14F00EFB-2EAB-438C-B401-7FEFDA1D94AB/data/Containers/Data/Application/81B23594-3BA2-4AF9-B91A-F74A53FD6945

但是,如果您在物理设备上运行该应用程序,则输出看起来会有些不同,如下所示。 但是,应用程序沙箱和施加的限制是相同的。

/var/mobile/Containers/Data/Application/41E7939B-6A39-4005-9C28-372FD9C7AD99

检索应用程序的Documents目录的路径需要做更多的工作,如您在下一个代码片段中所看到的。

let directories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)if let documents = directories.first {print(documents)
}

我们调用NSSearchPathForDirectoriesInDomains()函数,该函数在Foundation框架中定义。 作为第一个参数,我们传入类型为NSSearchPathDirectory DocumentDirectory ,以表明我们仅对应用程序的Documents目录感兴趣。 第二和第三个论点对我们的讨论不太重要。 该函数返回[String]类型的数组,其中包含一个结果,即应用程序的Documents目录的路径。

为什么使用沙箱?

沙箱的好处是什么? 沙盒应用程序的主要原因是安全性。 通过将应用程序限制在其自己的沙箱中,受感染的应用程序不会对操作系统或其他应用程序造成损坏。

所谓的受感染应用程序,是指被黑客入侵的应用程序,有意恶意的应用程序以及包含可能会无意造成损害的严重错误的应用程序。

即使将应用程序放在iOS平台上,也可以通过许多系统接口请求访问其应用程序沙箱外部的某些文件或资产。 例如,存储在设备上的音乐库。 但是,请知道系统框架负责与文件访问有关的所有操作。

哪里去了?

即使您可以在应用程序的沙箱中完成几乎任何您想做的事情,苹果公司也提供了一些有关应该存储在何处的准则。 出于以下几个原因,了解这些准则很重要。 将iOS设备备份到计算机或iCloud时,并非沙箱中的所有文件都包含在备份中。

例如, tmp目录仅应用于临时存储文件。 操作系统可以随时清空此目录,例如在设备磁盘空间不足时。 tmp目录不包括在备份中。

Documents目录用于用户数据,而Library目录用于不严格绑定到用户的应用程序数据。 Library目录中的Caches目录是另一个未备份的目录。

还请记住,您的应用程序不应修改应用程序捆绑目录的内容。 安装应用程序后,将对应用程序捆绑目录进行签名。 通过以任何方式修改应用程序捆绑目录的内容,可以更改上述签名,这意味着操作系统不允许应用程序再次启动。 这是Apple为保护客户而采取的另一项安全措施。

数据持久性选项

有几种策略可以将应用程序数据存储在磁盘上。 在本文中,我们简要介绍了iOS上的四种常见方法:

  • 默认系统
  • 物业清单
  • SQLite的
  • 核心数据

本文中介绍的选项不应视为可互换的。 每种策略都有其优点和缺点。 让我们先看一下默认系统。

用户默认值

默认系统是iOS继承自OS X的系统。即使它是为存储用户首选项而创建和设计的,它也可以用于存储任何类型的数据,只要它是属性列表类型NSStringNSNumberNSDateNSArrayNSDictionaryNSData或其任何可变变体。

那么Swift数据类型呢? 幸运的是,Swift足够聪明。 它可以通过将字符串和数字转换为NSStringNSNumber来存储它们。 Swift数组和字典也是如此。

默认系统仅是属性列表的集合,每个应用程序一个属性列表。 属性列表存储在应用程序的Library文件夹中的Preferences文件夹中,提示属性列表的用途和功能。

开发人员喜欢默认系统的原因之一是因为它非常易于使用。 看下面的例子,看看我的意思。

let userDefaults = NSUserDefaults.standardUserDefaults()// Setting Values
userDefaults.setBool(true, forKey: "Key1")
userDefaults.setInteger(123, forKey: "Key2")
userDefaults.setObject("Some Object", forKey: "Key3")
userDefaults.setObject([1, 2, 3, 4], forKey: "Key4")// Getting Values
userDefaults.boolForKey("Key1")
userDefaults.integerForKey("Key2")
userDefaults.objectForKey("Key3")
userDefaults.objectForKey("Key4")userDefaults.synchronize()

通过在NSUserDefaults上调用standardUserDefaults() ,将返回对共享默认对象的引用。

在最后一行,我们在共享默认对象上调用synchronize()以将任何更改写入磁盘。 很少需要调用synchronize() ,因为默认系统会在必要时保存更改。 但是,如果使用默认系统存储或更新设置,有时将更改显式保存到磁盘可能有用或必要。

乍一看,默认系统似乎只不过是位于特定位置的键值存储。 但是,在Foundation框架中定义的NSUserDefaults类不仅是用于管理键值存储的接口。 查看其类参考以获取更多信息。

在继续之前,将上面的代码片段粘贴到应用程序委托的application(_:didFinishLaunchingWithOptions:)方法中,然后在模拟器中运行该应用程序。 打开一个新的Finder窗口,然后导航到Library> Developer> CoreSimulator> Devices> <DEVICE_ID>> data> Containers> Data> Application> <APPLICATION_ID>

<DEVICE_ID><APPLICATION_ID>是模拟器和您的应用程序唯一的两个标识符。 模拟器的应用程序沙箱的位置取决于您使用的Xcode的版本。 如果您不使用Xcode 7,则路径可能会有所不同。

通过将应用程序主目录的路径打印到Xcode的控制台,可以使您的生活更轻松。 将以下打印语句添加到application(_:didFinishLaunchingWithOptions:)

print(NSHomeDirectory())

加密命名的文件夹是应用程序沙箱目录。 在应用程序沙箱目录中,打开 文件夹中的“首选项”文件夹,然后检查其内容。


您应该看到一个属性列表,其名称与应用程序的捆绑标识符相同。 这是您的应用程序的用户默认存储。 这就是属性列表在文本编辑器中的外观。 如您所见,属性列表作为XML文件存储在磁盘上。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict><key>Key1</key><true/><key>Key2</key><integer>123</integer><key>Key3</key><string>Some Object</string><key>Key4</key><array><integer>1</integer><integer>2</integer><integer>3</integer><integer>4</integer></array>
</dict>
</plist>

如果您想更轻松地访问模拟器中的应用程序的沙箱,那么我建议您看一下SimPholders 。 这是一个很小的实用程序,使使用模拟器变得非常容易。

物业清单

我们已经在本系列中介绍了属性列表。 实际上,用户默认数据库的后备存储是属性列表。 使用属性列表是存储和检索对象图的便捷策略。 属性列表已经存在了很长时间,易于使用,因此,它们是在iOS应用程序中存储数据的理想选择。

正如我前面提到的,请记住,属性列表只能存储属性列表数据,这一点很重要。 这是否意味着无法使用属性列表存储自定义模型对象? 那是可能的。 但是,自定义模型对象需要先归档(一种序列化形式),然后才能存储在属性列表中。 归档对象只是意味着需要将对象转换为可以存储在属性列表中的数据类型,例如NSData实例。

归档对象

您还记得Foundation框架中定义的NSCoding协议吗? NSCoding协议定义了两种方法, init(coder:)encodeWithCoder(_:) 。 一个类实现这些方法以允许对该类的实例进行编码和解码。

编码和解码是对象归档和分发的基本机制。 对象归档的工作方式在本系列的后面部分将变得很清楚。 在本课程中,我仅向您展示如何使用属性列表将数组和字典写入磁盘。

写入文件

以下代码段将使您了解将数组或字典写入磁盘有多么容易。 从理论上讲,存储在属性列表中的对象图可以任意复杂或任意大小。 但是,请记住,属性列表并不是要存储数十或数百兆字节的数据,尝试以这种方式使用它们可能会导致性能下降。

let directories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)if let documents = directories.first {if let urlDocuments = NSURL(string: documents) {let urlFruits = urlDocuments.URLByAppendingPathComponent("fruits.plist")let urlDictionary = urlDocuments.URLByAppendingPathComponent("dictionary.plist")// Write Array to Disklet fruits = ["Apple", "Mango", "Pineapple", "Plum", "Apricot"] as NSArraylet dictionary = ["anArray" : fruits, "aNumber" : 12345, "aBoolean" : true] as NSDictionaryfruits.writeToFile(urlFruits.path!, atomically: true)dictionary.writeToFile(urlDictionary.path!, atomically: true)// Load from Disklet loadedFruits = NSArray(contentsOfURL: urlFruits)if let fruits = loadedFruits {print(fruits)}let loadedDictionary = NSDictionary(contentsOfURL: urlDictionary)if let dictionary = loadedDictionary {print(dictionary)}}
}

让我们看一下上面的代码片段。 我们首先将对数组文字的引用存储在名为fruits的变量中。 我们创建文件URL来存储我们将要创建的属性列表。 通过将字符串附加到Documents目录的文件URL来创建文件URL。 我们追加的字符串是我们在一秒钟内创建的属性列表的名称,包括其扩展名.plist

将阵列写入磁盘就像在阵列上调用writeToFile(_:atomically:)一样容易。 您现在可以忽略atomically标记。 如示例所示,将字典写入磁盘遵循类似的模式。 该示例还说明了如何从属性列表创建数组和字典,但这是我们在本系列前面的内容。 在模拟器中运行应用程序,然后导航到应用程序的Documents目录。 在此目录中,您应该看到我们刚刚创建的两个属性列表。


这是在文本编辑器中打开字典时的属性列表。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict><key>aBoolean</key><true/><key>aNumber</key><integer>12345</integer><key>anArray</key><array><string>Apple</string><string>Mango</string><string>Pineapple</string><string>Plum</string><string>Apricot</string></array>
</dict>
</plist>

SQLite的

如果您的应用程序是数据驱动的并且可以处理大量数据,那么您可能需要研究SQLite。 什么是SQLite? SQLite网站上的标语显示为“小。快速。可靠。选择任意三个。”,总结起来很不错。

SQLite是一个实现轻量级嵌入式关系数据库的库。 顾名思义,它基于SQL标准( 结构化查询语言 ),就像MySQL和PostgreSQL。

与其他SQL数据库的主要区别在于SQLite是可移植的并且非常轻巧。 SQLite是无服务器的,而不是从客户端应用程序访问的单独进程。 换句话说,它嵌入在应用程序中或由应用程序运行所在的系统管理,这意味着它非常快。

SQLite网站声称它是部署最广泛的SQL数据库。 我不知道情况是否仍然如此,但这无疑是客户端数据存储的流行选择。 与直接使用对象相比,SQLite的优势在于SQLite快得多。 这主要是由于关系数据库和面向对象的编程语言在根本上有何不同。

为了弥合SQLite和Objective-C之间的鸿沟,随着时间的推移,已经创建了许多对象关系映射 (ORM)解决方案。 苹果公司为iOS和OS X创建的ORM被称为Core Data ,我们将在本课程的稍后部分中进行介绍。

飞肉的FMDB

在iOS上使用SQLite意味着使用基于C的库。 如果您更喜欢面向对象的解决方案,那么我强烈推荐Gus Mueller( Flying Meat,Inc. )的SQLite FMDB Objective-C包装器。

该图书馆非常有表现。 我过去使用过FMDB,并且对其API和库的健壮性和可靠性感到非常满意。

核心数据

刚接触Core Data的开发人员经常将Core Data误认为数据库,而实际上它是Apple创建和维护的对象关系映射解决方案。 马特·加拉格尔(Matt Gallagher )写了一篇很棒的文章,介绍了核心数据和数据库之间的区别。 Core Data提供了一个关系型的面向对象的模型,该模型可以序列化为XML,二进制或SQLite存储。 核心数据甚至支持内存存储。

为什么要使用Core Data而不是SQLite? 通过问这个问题,您错误地假定Core Data是一个数据库。 使用Core Data的优点是您可以使用对象而不是原始数据,例如SQLite数据库中的行或XML文件中存储的数据。 尽管Core Data最初发布时经历了一段艰难的岁月,但它已成长为具有许多功能的健壮框架,包括自动迁移,更改跟踪,故障和集成验证。

许多开发人员欣赏的另一个重要功能是Xcode内置的Core Data模型编辑器。 编辑器使开发人员可以通过图形界面为应用程序的数据模型建模。


核心数据是否是适合您的应用程序的正确解决方案,取决于您计划管理的数据,无论是数据量还是基础模型。 如果您计划管理非常大的数据集,那么随着时间的流逝,Core Data可能会成为性能瓶颈。 在这种情况下,SQLite可能是更好的解决方案。

iCloud的

您可能听说过iCloud,并且您可能想知道iCloud适合数据持久性的故事。 与SQLite和Core Data不同,iCloud不是数据持久性的一种形式。 相反,它是一个平台或服务,用于使用户数据可跨多个设备和一个应用程序甚至多个应用程序实例使用。

iCloud平台包含多个服务或组件。 我们感兴趣的组件是iCloud Storage ,它包括四种类型的存储:

  • CloudKit
  • 键值存储
  • 文件储存
  • 核心数据存储

如果您想了解有关iCloud Storage的更多信息,建议阅读有关iCloud Storage的系列文章 。

结论

现在,您应该对在为iOS平台进行开发时必须存储数据的选项有所了解。 请记住,并非我们涵盖的所有策略都是平等的。

这个系列正在慢慢结束。 在接下来的两期中,我们将创建另一个应用程序,以将到目前为止所学的知识付诸实践。 最好的学习方法就是做事。

如果您有任何问题或意见,可以将其留在下面的评论中,或通过Twitter与我联系。

翻译自: https://code.tutsplus.com/tutorials/ios-from-scratch-with-swift-data-persistence-and-sandboxing-on-ios--cms-25505

iOS从零开始,用Swift:iOS上的数据持久性和沙箱相关推荐

  1. iOS学习之Swift史上最全第三方大全

    目录 "轮子" 工具类 存储类 网络类 图片类 界面类 框架类 "车子"  示例项目 完整应用 "轮子" 工具类 项目 开发者 备注 Swi ...

  2. iOS学习之Swift史上最全第三方轮子大全

    @SwiftLanguage 更新至 2016-2-1,最近新收录 Graph, Localize-Swift, Cuckoo, Gecco, AudioKit, vapor, Every.swift ...

  3. iOS从零开始使用Swift:如何在设备上测试iOS应用程序

    为初学者配置应用程序以在物理设备上进行测试或分发给App Store可能是一场噩梦. 但是,每个iOS开发人员都必须解决这一障碍. 在本文中,我对如何为物理设备上的测试提供应用程序提供了很好的理解. ...

  4. 用Swift实现iOS相机及相册图片上传

    最近要做一个iOS相机及相册图片上传,其中遇到了这些问题:1.图片增删在UICollectionView里的变化:2.获取相机拍摄的照片和相册的照片:3.将PHAsset对象转为UIImage对象: ...

  5. (0081)iOS开发之无限后台定位并上传数据到服务器

    关键词:ios 后台持续定位 iOS 后台的理解 // http://blog.csdn.net/u013773524/article/details/52153917 // http://blog. ...

  6. Android与Swift iOS开发:语言与框架对比

    Swift是现在Apple主推的语言,2014年新推出的语言,比 Scala等"新"语言还要年轻10岁.2015年秋已经开源.目前在linux上可用,最近已经支持Android N ...

  7. iOS开发之swift资料大全

    目录(?)[+] 版本:Swift github排名 https://github.com/trending,github搜索:https://github.com/search 主要工作说明:  1 ...

  8. Android Swift iOS开发:语言与框架对比

    转载自:http://www.infoq.com/cn/articles/from-android-to-swift-ios?utm_campaign=rightbar_v2&utm_sour ...

  9. [共享]iOS开发系列--Swift语言

    2019独角兽企业重金招聘Python工程师标准>>> iOS开发系列--Swift语言 概述 Swift是苹果2014年推出的全新的编程语言,它继承了C语言.ObjC的特性,且克服 ...

  10. iOS开发系列--Swift语言

    概述 Swift是苹果2014年推出的全新的编程语言,它继承了C语言.ObjC的特性,且克服了C语言的兼容性问题.Swift发展过程中不仅保留了ObjC很多语法特性,它也借鉴了多种现代化语言的特点,在 ...

最新文章

  1. testngpp - next generation unit test framework for c/c++
  2. 面试:a==1 a==2 a==3 是 true 还是 false?
  3. Java语言学习思维导图
  4. php可以集成萤石监控吗,萤石多功能IP摄像机 真的可以让家更安全吗?
  5. leetcode 415. 字符串相加(Java版)
  6. CSS3给网页穿上美丽的外衣
  7. 一切转型始于数据和模型 | 2020 MATLAB EXPO 中国线上用户大会:即将上线
  8. 孜然网址导航系统源码v1.0
  9. Git常见指令的本质
  10. C++ map的简单实现
  11. 初学者虚拟机使用虚拟机
  12. OpenCV-图像金字塔cv::buildPyramid
  13. 《纽约时报》:乔布斯最后的日子 与家人相伴
  14. 信息管理与信息系统毕业论文选题?
  15. 华为数通NA-NP学习笔记(个人精简)
  16. 搭建VUE脚手架 + 引入element-ui
  17. vs2013设置winp#cap开发环境
  18. 修改织梦后台登陆地址login.php,织梦后台免登录的实现步骤 Dede后台自动登录的修改方法...
  19. 【Vue2】自定义指令 directives 过滤器 filter
  20. 贵州大学计算机试题及答案,贵州大学学位计算机选择题答案

热门文章

  1. python绘制聚类树状图
  2. 蓝牙相关学习:5.BLE协议属性协议层(ATT)
  3. K线技术指标实现详解—ENE
  4. 风之大陆ios android账号互通,《风之大陆》安卓和ios互通吗
  5. 服装尺寸 html,国家标准服装尺寸表
  6. 文本分类数据和评价指标
  7. Mysql基础命令语句(1)
  8. 华硕笔记本官网驱动如何下载
  9. select下拉框如何显示提示语,不要出现下拉选项中
  10. html周志模板,毕业设计指导周志模板