[iOS-Foundation] NSURL

NSURL /NSURLComponents

URI

URL(统一资源定位符) 是一种 URI,URN(统一资源名称) 也是一种 URI,所以 URI (统一资源标志符)可被视为定位符,名称或两者兼备。URN 如同一个人的名称,而 URL 代表一个人的住址。换言之,URN 定义某事物的身份,而 URL 提供查找该事物的方法。例如,ISBN 0-486-27557-4 无二义性地标识出莎士比亚的戏剧《罗密欧与朱丽叶》的某一特定版本,它可以允许人们在不指出其位置和获得方式的情况下谈论这本书。为获得该资源并阅读该书,人们需要它的位置,也就是一个URL地址。在类Unix操作系统中,一个典型的URL地址可能是一个文件目录,例如
file:///home/username/RomeoAndJuliet.pdf,该URL标识出存储于本地硬盘中的电子书文件。因此,URL和URN有着互补的作用。

URL Encode

URL 采用 ASCII 编码格式,所以不支持如中文等非 ASCII 码字符,另外 URL 中保留的分隔符号(?&=等)也无法作为内容,否则会引起歧义。这就需要通过编码,用安全的字符来表示这些不符合要求的字符,格式是%加两位安全字符,所以 URL 编码也称为百分号编码。在 iOS 中的相关操作分别为:

Encode
NSString *encodedString = [URLString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];

@interface NSCharacterSet (NSURLUtilities)
+ (NSCharacterSet *)URLUserAllowedCharacterSet;
+ (NSCharacterSet *)URLPasswordAllowedCharacterSet;
+ (NSCharacterSet *)URLHostAllowedCharacterSet;
+ (NSCharacterSet *)URLPathAllowedCharacterSet;
+ (NSCharacterSet *)URLQueryAllowedCharacterSet;
+ (NSCharacterSet *)URLFragmentAllowedCharacterSet;
@end
Unencode
+ (NSString *)decodeURLString:(NSString *)URLString {
    // 有时从服务端获取的 URL 中,空格被编码为+, 
    // 而方法- stringByRemovingPercentEncoding只替换百分号编码,
    // 所以要在执行该方法前,先将`+`替换掉(真正的加号字符是被百分号编码的)
    NSString *result = [URLString stringByReplacingOccurrencesOfString:@"+" withString:@" "];
    result = [result stringByRemovingPercentEncoding];
    
    return result;
}

NSURL

NSURL

一个 NSURL 对象代表了一个表示远程服务器资源或者本地文件的 URL。所以在 iOS 的网络请求和操作文件系统的 API 中,很多都需要 NSURL 类型的参数。

创建 NSURL 对象
+ URLWithString:
- initWithString:

传入的字符串类型的 URL 参数要求是经过编码后的,如果该参数不符合规范或者传入了 nil,那么上述方法会返回 nil。

+ URLWithString:relativeToURL:
- initWithString:relativeToURL:

除了字符串类型的 URL 参数,还需要一个 NSURL 类型的 Base URL 参数,字符串类型的 URL 将作为 Base URL 的相对路径。同样字符串类型的 URL 参数要求是经过编码后的,如果不符合规范或者传入了 nil,那么也会返回 nil。

NSURL *baseURL = [NSURL URLWithString:@"http://example.com/v1/"];
[NSURL URLWithString:@"foo" relativeToURL:baseURL];
// http://example.com/v1/foo
[NSURL URLWithString:@"/foo" relativeToURL:baseURL];
// 如果相对路径以/开始,根据规则,URL 最终会拼装为http://example.com/foo
[NSURL URLWithString:@"http://example2.com/" relativeToURL:baseURL];
// http://example2.com/,因为 URLString 并不是相对的 path 部分,而是完整的 URL,所以最终的值会忽略掉 baseURL。
+ fileURLWithPath:
- initFileURLWithPath:
+ fileURLWithPath:isDirectory:
- initFileURLWithPath:isDirectory:

创建一个 file URL (协议为file:///),参数 Path 需要传入一个系统路径,如果路径中包含~,那么需要先调用 NSString 的stringByExpandingTildeInPath方法解析~,如果传入的路径是相对路径,那么生成的 URL 将相对于当前路径。当没有 isDirectory 参数时,如果路径以/结束,则认为路径是一个目录,若不是以/结束,则系统会先检查路径是否存在,若路径存在且是一个目录,则系统会在路径后添加/,若路径不存在,系统则认为路径代表一个文件。而 isDirectory 参数则明确指明路径是否代表一个目录。

+ fileURLWithPathComponents:

传入一个字符串类型元素的数组,该方法用/将这些元素组装成一个 file URL。

+ fileURLWithFileSystemRepresentation:isDirectory:relativeToURL:
- initFileURLWithFileSystemRepresentation:isDirectory:relativeToURL:

通过 c string Path 创建文件 URL 对象。

- getFileSystemRepresentation:maxLength:

将文件 URL 以 c string 填入到提供的 buffer 中。

语法

URI语法由URI协议名,一个冒号,和协议对应的内容所构成。特定的协议定义了协议内容的语法和语义,而所有的协议都必须遵循一定的URI语法通用规则,亦即为某些专门目的保留部分特殊字符。URI语法同时也就各种原因对协议内容加以其他的限制,例如,保证各种分层协议之间的协同性。百分号编码也为URI提供附加信息。

一般的 URI 格式为:

scheme:[//[user:password@]host[:port]][/]path[?query][#fragment]

具体的例子如:

                    hierarchical part
        ┌───────────────────┴─────────────────────┐
                    authority               path
        ┌───────────────┴───────────────┐┌───┴────┐
  abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
  └┬┘   └───────┬───────┘ └────┬────┘ └┬┘           └─────────┬─────────┘ └──┬──┘
scheme  user information     host     port                  query         fragment

  urn:example:mammal:monotreme:echidna
  └┬┘ └────────────┬───────────────┘
scheme              path

NSURL 根据 RFC 2396 的定义提供了只读属性用于获取 URL 每一部分的值:

  • scheme,协议名,不带有连接内容的冒号,如“http”。
  • user,解码后的用户名。
  • password,解码后的 password。
  • host,主机域名或 IP 地址。
  • port ,端口号。
  • path,authority(user,password,host,port)后的部分,如果 URL 对象是 file URL,该属性会去掉最后的/。
  • query,解码后的 query 字符串,没有?,但包括连接多个键值对的&。
  • fragment,解码后的片段,不包括#。
  • parameterString,path 后由分号分隔的部分,如file:///path/to/file;foo中的 foo。
  • lastPathComponent,path 部分的最后一段。
  • pathExtension,path 指向资源的扩展名。
  • pathComponents,由解码后的 path 各段组成的数组。
  • resourceSpecifier,冒号后的全部内容。
  • absoluteString,将 URL string 和相对的 Base URL 拼接成的完整 URL string。
  • absoluteURL,返回一个 NSURL 对象,将 absoluteString 作为该 URL 对象的 string。
  • baseURL,如果 URL 对象本身由完整 URL 字符串构成,那么该属性为 nil。
  • relativeString,URL 对象的相对部分,即创建时传入的字符串部分。
  • relativePath,只包含相对字符串中的 path,而不包括 Base URL 中的。
  • standardizedURL,删除掉 path 中的.和..的新的 URL 对象。
  • fileSystemRepresentation,c string 表示的文件资源路径。
相等比较

NSURL 重写了- isEqual:方法,判断条件是,当两个 NSURL 对象的 baseURL 和 relativeString 都相同时,就认为它们是相等的。

修改和转换文件 URL
- fileReferenceURL

如果 URL 对象代表了一个 file path URL,那么该方法则返回一个其指向资源对应的 file reference URL,格式如file:///.file/id=16777217.83600349/ file reference URL 直接引用资源,而不是通过资源所在文件系统的路径,这样即使资源的 path 改变,file reference URL 仍然是有效的。如果 URL 对象不是一个 file path URL 或者 path 指向的资源并不存在,那么该方法会返回 nil。如果 URL 对象本身就是 file reference URL 那么该方法返回对象本身。不要直接持久化保存 file reference URL,因为当系统重新启动后它们不再有效,而应该使用 bookmark

filePathURL

如果 URL 对象是一个 file path URL 且指向的资源确实存在,那么该属性返回对象本身,如果 URL 对象是一个 file reference URL,那么则返回对应的 file path URL,否则返回 nil。

- URLByAppendingPathComponent:

返回一个新的 file path URL,这个 URL 在原 URL 对象后添加了传入的一段路径参数。该方法会自动在原 URL 对象和新的 path 间加入/,如果 path 参数最后没有以/结尾,那么该方法会同步检测新 URL 对象指向的资源是否存在且是一个目录,如果路径指向网络挂载卷,这将会造成严重的性能损耗。

- URLByAppendingPathComponent:isDirectory:

功能同上一个方法,不过可以通过 isDirectory 参数具体指明新的 file URL 是否为一个目录,从而避免系统的同步检测。

- URLByAppendingPathExtension:

返回一个添加扩展名的 URL 对象,该方法会自动去掉原 URL 对象最后的/并添加.

URLByDeletingLastPathComponent

去掉最后一段 path 的 URL 对象

URLByDeletingPathExtension

去掉最后一段文件扩展名的 URL 对象

URLByResolvingSymlinksInPath

一个解析了 symbolic link 后的 URL

URLByStandardizingPath

将原 URL 对象表示的 file path 标准化,包括转换~标识符,去掉多余的空格和/,转换..等操作。

file URL 检测
  • fileURL,布尔值,指明 URL 是否使用file:///协议,无论是 file path URL 还是 file reference URL
  • - isFileReferenceURL,返回布尔值,说明 URL 对象是否为 file reference URL
  • - checkResourceIsReachableAndReturnError:,返回布尔值,说明 file URL 指向的文件资源是否可获取,若返回 NO,通过 error 参数可以获取更多信息
File System Resource Properties

当 URL 对象为 file URL 时,可以通过特定的 key 设置、获取及删除 URL 对应的某些资源。

系统内置的 key :

Common File System Resource Keys
File Property Keys
Ubiquitous Item Property Keys
Volume Property Keys

相应的方法:

// 获取指定 key 的资源内容,
- getResourceValue:forKey:error:
// 返回一个字典,包含了所有指定 key 的对应资源
- resourceValuesForKeys:error:
// 设置某一资源值,并直接持久化保存
- setResourceValue:forKey:error:
// 传入一个字典,设置多个资源值,持久化保存
- setResourceValues:error:
// 设置自定义资源 key 的值到内存中
- setTemporaryResourceValue:forKey:
// 删除缓存中所有资源 key 的值
- removeAllCachedResourceValues
// 删除缓存中指定资源 key 的值
- removeCachedResourceValueForKey:
Bookmarks

通过 NSURL 的 bookmarks 相关 API,可以持久化保存文件的路径。所谓 bookmark,是一种 NSData 类型的数据,描述了文件路径的信息。将 bookmark 持久化保存,当应用重新启动后,可通过 bookmark 获取到对应文件路径的 URL,即使期间文件被重新命名或移动到其他路径。

- bookmarkDataWithOptions:includingResourceValuesForKeys:relativeToURL:error:

创建一个 NSURL 对象对应的 bookmark。
参数 options 有两个值,NSURLBookmarkCreationMinimalBookmark指通过尽可能少的信息创建一个 bookmark,NSURLBookmarkCreationSuitableForBookmarkFile指创建的 bookmark 需要包含用于创建 Finder alias files 的属性。
参数 keys,通过传入 key 的数组,指明哪些 URL 资源需要保存到 bookmark 中
参数 relativeURL 指 bookmark 相对的 URL

+ resourceValuesForKeys:fromBookmarkData:

获取保存在 bookmark 中的 URL 资源。

+ URLByResolvingBookmarkData:options:relativeToURL:bookmarkDataIsStale:error:
- initByResolvingBookmarkData:options:relativeToURL:bookmarkDataIsStale:error:

通过解析 bookmark 转换成一个 NSURL 对象,额外的参数:
options,NSURLBookmarkResolutionWithoutUINSURLBookmarkResolutionWithoutMounting
relativeURL,bookmark 相对的 URL
isStale,指定转换后,bookmark 是否失效

+ writeBookmarkData:toURL:options:error:

指定一个 alias file 的路径,将 NSData 类型的 bookmark 持久化保存在其中,可以将这个 alias file 理解为一个 symbolic link。

+ bookmarkDataWithContentsOfURL:error:

从创建的 alias file 获取 bookmark

+ URLByResolvingAliasFileAtURL:options:error:

直接通过 alias file 的 URL 获取保存在其中的 bookmark 对应的真正 URL,options 参数指明了如何解析 bookmark。

NSURLComponents

NSURLComponents

NSURLComponents 是一个用于解析和构建 URL 的类,
通过 NSURLComponents 可以单独修改 URL 的某一部分,获取某一部分编码后的值。

创建一个 NSURLComponents 实例
// 通过传入的 URL string 创建
+ componentsWithString:
// 通过传入的 URL 对象创建,resolve 参数决定是否解析 URL 对象的 baseURL
+ componentsWithURL:resolvingAgainstBaseURL:
- init
- initWithString:
- initWithURL:resolvingAgainstBaseURL:
获取 NSURL 实例
  • string,返回 URL string
  • URL,返回 URL 对象
  • - URLRelativeToURL:,返回 URL 对象并相对于传入的 baseURL 参数
可读写的 URL 各部分的属性

fragment

host

password

path

port

query

queryItems

scheme

user

其中queryItems属性是一个包含 NSURLQueryItem 对象的数组,每一个 NSURLQueryItem 对象代表了 query string 中的一个键值对

百分号编码后的各部分的读写属性

percentEncodedFragment

percentEncodedHost

percentEncodedPassword

percentEncodedPath

percentEncodedQuery

percentEncodedUser

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,209评论 0 17
  • iOS网络编程读书笔记 Facade Tester客户端门面模式的实例(被动版本化) 被动版本化,所以硬编码URL...
    melouverrr阅读 1,575评论 3 7
  • 218.241.181.202 wxhl60 123456 192.168.10.253 wxhl66 wxhl6...
    CYC666阅读 1,286评论 0 5
  • 今夜天空等待等待着明月 远方远处里隐隐笙歌停歇 路灯拉下斜长斜长的身影 细雨秋风怎寄怎寄相思帖 你拉开了窗 听见了...
    YANandYAN阅读 248评论 0 0