1、Sandbox 沙箱
iOS 为每个应用提供了独立的文件空间,一个应用只能直接访问为本应用分配的文件目录,不可以访问其他目录,每个应用自己独立的访问空间被称为该应用的沙盒。也就是说,一个应用与文件系统的交互绝大部分都被限制在它自己的应用沙盒内。
-
1)在新 App 被安装时,安装器会为应用创建一系列角色不同的容器(container)。

-
2)iOS 中同一个应用在不同的手机中分配的路径可能是不同的,所以我们无法通过硬编码指定完整路径名来找到对应文件。Foundation 框架提供了一组专门的接口来获取应用沙箱不同位置的目录路径。
// 获取用户主路径
public func NSHomeDirectory() -> String
// 获取临时文件路径
public func NSTemporaryDirectory() -> String
// 获取满足条件的路径列表
public func NSSearchPathForDirectoriesInDomains(directory: NSSearchPathDirectory,
_ domainMask: NSSearchPathDomainMask,
_ expandTilde: Bool) -> [String]
该函数返回一组路径的数组,如果仅是查找用户的目录,这个数组只包含一个元素,如果第二个参数包含多个值,该数组会包含多个元素。当为 iOS 编写程序时,第二个参数应是 NSUserDomainMask,并且得到一个包含单个路径的数组作为返回。在 iOS 中后两个参数是不变的。
-
directory :指定查找的目录范围。
NSSearchPathDirectory |
说明 |
ApplicationDirectory |
/Applications |
LibraryDirectory |
/Library |
DocumentDirectory |
/Documents |
ApplicationSupportDirectory |
/Library/Application Support |
UserDirectory |
/Users |
CachesDirectory |
/Library/Caches |
-
domainMask :指定查找的文件系统域,可以是多值。
NSSearchPathDomainMask |
说明 |
UserDomainMask |
用户域,指向当前用户的 home 目录(~) |
LocalDomainMask |
本地域,指向对所有用户可用的当前机器范围 |
NetworkDomainMask |
网络域,指向 /Network |
SystemDomainMask |
系统域,指向 /System |
expandTilde :指定是否展开路径中的代字符(~)。
2、NSBundle 路径
public class NSBundle : NSObject
在 iOS 中提到的 NSBundle 是文件系统中的一个特殊位置,它存放的是应用可执行文件及相关资源文件。这个位置的所有文件在系统运行时只具有可读或者可执行的权限,不能进行修改。
-
应用程序 bundle 中主要有以下几种类型的文件:
- Info.plist:用来配置应用的基本参数信息。包括版本号,指向的可执行文件名、包名等。
- 可执行文件:每个应用程序必须要有一个可执行文件。
- 资源文件:是可执行文件以外的数据文件,常用的如图像、图标、音频文件、视图文件、配置文件等。
应用程序 bundle 的配置信息都存在 Info.plist 文件中。它里面各项都以 key-value 的形式进行描述,包括了应用程序唯一标识名、版本号、可执行文件名等信息。
-
bundle 配置信息主要参数:
key |
友好显示名 |
value |
CFBundleDisplayName |
Bundle display name |
程序的应用名,安装后显示在桌面上的那个名称,可以进行本地化设置 |
CFBundleExecutable |
Executable file |
应用可执行程序的名称 |
CFBundleIdentifier |
Bundle identifier |
应用程序的唯一标识 |
CFBundleVersion |
Bundle version |
应用编译版本号 |
CFBundleShortVersionString |
Bundle version string, short |
应用 release 发布版版本号 |
当创建一个应用时,系统存储了应用相关联的所有数据(其中包括图片、本地化字符串、图标等),将这些内容放入一个称为应用包(application bundle)的包中。在应用中添加一个资源时很方便的:仅需将文件拖到 Xcode 的左边窗格中。当出现对话框时,通常选择复制资源文件到你的项目目录中,这样你的项目都是自包含的。
command-line tool 是没有 bundle 的,所以用 NSBundle 的时候一直是 null,如果要使用 bundle 获取项目中的资源,必须要使用 application。
- Bundle 常见问题
- 项目里面的某个 .swift 文件无法使用
- 检查 TARGETS => Build Phases => Compile Sources 里是否包含此 .swift 文件。
- 项目里面的某个资源文件(比如 plist、音频等)无法使用
- 检查 TARGETS => Build Phases => Copy Bundle Resources 里是否包含此资源文件。
-
获取 NSBundle 资源
// 获得 Bundle 信息
/*
通常指向 xxx.app/ 这个根目录
*/
let mainBundle = NSBundle.mainBundle()
// 获取 Bundle 文件路径
let bundlePath:String = NSBundle.mainBundle().bundlePath
let resourcePath:String? = NSBundle.mainBundle().resourcePath
// 获取 Bundle URL 路径
let bundleUrl:NSURL = NSBundle.mainBundle().bundleURL
let resourceURL:NSURL? = NSBundle.mainBundle().resourceURL
// 获得 Bundle 目录下的文件路径
let filePath1:String = NSBundle.mainBundle().pathForResource("test", ofType: "txt")!
// bundle 下子目录 inDirectory 下的文件路径
let filePath2:String = NSBundle.mainBundle().pathForResource("test", ofType: "txt", inDirectory: "testFolder")!
// 获得 Bundle 目录下的 URL 路径
let fileUrl1:NSURL = NSBundle.mainBundle().URLForResource("test", withExtension: "txt")!
// bundle 下子目录 subdirectory 下的 URL 路径
let fileUrl2:NSURL = NSBundle.mainBundle().URLForResource("test", withExtension: "txt", subdirectory: "testFolder")!
// 获取应用程序唯一标识包名
let indentifier:String? = NSBundle.mainBundle().bundleIdentifier
// 获取应用程序 Info.plist 配置项词典对象实例
let info = NSBundle.mainBundle().infoDictionary
// 获取某一特定字段的内容
let bundleID:AnyObject? = NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleName")
3、NSURL 路径
public class NSURL : NSObject, NSSecureCoding, NSCopying, NSURLHandleClient
public class NSURLComponents : NSObject, NSCopying
在文件系统中,文件和目录都是使用完整文件路径来唯一标识的。我们可以使用 NSString 和 NSURL 两种对象来描述文件路径。官方建议使用 NSURL 。
NSURL 是用来表示 URL 地址的类,通过 URL 我们可以定位一个远程 web 服务器上的资源位置,也可以定位硬盘上的一个本地文件的路径。对于 web 资源,往往结合 NSURLSession、NSURLConnection、NSURLDownload 等使用,对于本地资源,一般结合 NSFileManager、NSFileHandle、NSBundle 使用。
-
NSURLComponents 只支持 iOS7.0 及以上的 API 类,它可以实现对 URL 各个部分的读写。NSURLComponents 对 URL 各个部分的内容都有两种格式的属性来表示:
原生格式 |
URL-Encoded |
scheme |
- |
host |
percentEncodedHost |
port |
- |
path |
percentEncodedPath |
query |
percentEncodedQuery |
fragment |
percentEncodedFragment |
user |
percentEncodedUser |
password |
percentEncodedPassword |
-
1)NSURL 结构:
protocol://hostname[:port]/path/[;parameters][?query]#fragment // 带方括号[]的为可选项
protocol :协议
hostname :主机名
port :端口
path :路径
parameters :参数
query :查询
fragment :信息片段
如:https://swiftinaction.com/example?section=5
这个 URL 包含 scheme(https)、host(swiftinaction.com)、path(/example)、query(section=5)等若干部分。
其中 URL 的 scheme 字段标识了一个 URL 所遵循的协议:
http:// 超文本传输协议
https:// 超文本传输安全协议
ftp:// 文件传输协议
file:// 本地文件 URL
data:// 数据 URL
-
2)URL 的创建
// 由字符串创建
// 简单字符串直接创建
let url1:NSURL = NSURL(string: "https://swiftinaction.com/example")!
let complexString:String = "https://swiftinaction.com/中文字符串/example"
let convertString:String? = complexString.stringByAddingPercentEncodingWithAllowedCharacters(
NSCharacterSet(charactersInString: "`#%^{}\"[]|\\<> "))
// 由复杂字符串/中文创建时,需要对字符串进行编码转换
let url2:NSURL = NSURL(string: convertString!)!
// 由基础 URL 和基于基础 URL 的一个相对路径字符串创建
let baseUrl:NSURL = NSURL(string: "https://swiftinaction.com")!
let fullUrl:NSURL = NSURL(string: "/example", relativeToURL: baseUrl)!
// 生成绝对路径
let url3:NSURL = fullUrl.absoluteURL
// 由文件路径创建
// 自动判断 URL 路径为文件,还是目录,为目录时自动在路径末尾加 “/”
let url4:NSURL = NSURL.fileURLWithPath("/Users/JHQ0228/Desktop/test")
// 指定 URL 路径为一个目录,自动在路径末尾加 “/”
let url5:NSURL = NSURL.fileURLWithPath("/Users/JHQ0228/Desktop/test", isDirectory: true)
-
3)URL 的获取
let url1:NSURL = NSURL(string: "http://JHQ:password@swiftinaction.com:8080/sayHello/toChinese.png;
date=20160223?name=JHQ#atMorning")!
// 获取 URL 的 绝对路径字符串
let absoluteString:String? = url1.absoluteString
// 获取 URL 的 协议类型
let scheneString:String? = url1.scheme
// 获取 URL 的 主机名
let hostString:String? = url1.host
// 获取 URL 的 端口
let portString:NSNumber? = url1.port
// 获取 URL 的 路径名
let pathString:String? = url1.path
// 获取 URL 的 参数
let parametersString:String? = url1.parameterString
// 获取 URL 的 查询语句
let queryString:String? = url1.query
// 获取 URL 的 信息片段语句
let fragmentString:String? = url1.fragment
// 获取 URL 的 路径组成部分
let pathComponents:AnyObject? = url1.pathComponents
// 获取 URL 的 相对路径
let relativePath:String? = url1.relativePath
// 获取 URL 的 路径最后一个组成部分
let lastPathComponent:String? = url1.lastPathComponent
// 获取 URL 的 路径扩展名
let pathExtension:String? = url1.pathExtension
// 获取 URL 的 用户名
let user:String? = url1.user
// 获取 URL 的 密码
let password:String? = url1.password
-
4)URL 的判断
let fileUrl:NSURL = NSBundle.mainBundle().URLForResource("testFile", withExtension: "txt")!
// 检查文件的可达性
/*
只能用来判断文件系统内部资源的可达性,对于 web URl 等其他类型全返回 false
*/
let bl1:Bool = fileUrl.checkResourceIsReachableAndReturnError(nil)
// 判断是否为文件 URl
let bl2:Bool = fileUrl.fileURL
-
5)URL 的路径拼接
let url:NSURL = NSURL(string: "http://swiftinaction.com/sayHello")!
// 追加路径到当前路径末尾
// 只追加路径,不在路径末尾添加 “/”
let appendUrl1:NSURL = url.URLByAppendingPathComponent("toJhq")
// isDirectory 为 true 时在路径末尾添加 “/”
let appendUrl2:NSURL = url.URLByAppendingPathComponent("toJhq", isDirectory: true)
// 追加路径后缀到当前路径末尾
/*
当路径以 “/” 结尾时,后缀会添加到末尾的 “/” 之前
*/
let appendUrl3:NSURL = url.URLByAppendingPathExtension("png")
// 删除路径末尾的最后一个路径
let deleteUrl1:NSURL = appendUrl1.URLByDeletingLastPathComponent!
// 删除路径末尾的后缀
let deleteUrl2:NSURL = appendUrl3.URLByDeletingPathExtension!
-
6)NSURLComponents
let componentsUrl:NSURLComponents = NSURLComponents(string: "http://swiftinaction.com/sayHello")!
componentsUrl.scheme = "https"
componentsUrl.host = "swiftinaction.com.cn"
componentsUrl.port = 8080
componentsUrl.path = "/sayHello/toChinese/你好"
componentsUrl.query = "name=JHQ"
componentsUrl.fragment = "atMorning"
componentsUrl.user = "JHQ"
componentsUrl.password = "123456789"
// 将 NSURLComponents 转为 NSURL
let nsUrl:NSURL = componentsUrl.URL!
let componentsUrlString1:String = componentsUrl.path!
// 为内容数据的十六进制编码字符串
let componentsUrlString2:String = componentsUrl.percentEncodedPath!
4、数据持久化