NSURL /
NSURLComponents

Mattt Thompson撰写、 Croath Liu翻译、 发布于

这里有一个直观的描述来解释什么是“一维数据类型”:number或string被格式化为多种多样的值,可以通过数学运算或某种转换方法可以算出它们的值。比如:十六进制的颜色值 #EE8262红绿蓝三原色的值通过掩码或移位运算得出;正则表达式可以通过少量字符中复杂的样本中进行匹配。

在所有的一维数据类型中,URI 有着至高地位。单独就人类可阅读的字符串这一点来说,它存在并将永远存在于计算机中任何你能够想象到的对位置信息进行编码的数据中。

它最基础的表示法中,URI 由一个 scheme 和一个 hierarchical part 组成,带有 query 和 fragment(后两者非必需):

<scheme name> : <hierarchical part> [ ? <query> ] [ # <fragment> ]

很多像HTTP的协议中会定义有一定的规范结构,例如:username、password、port, 以及hierarchical part 中的 path:

URL Structure

对网络编程的扎实理解植根于对于 URL 各个部分的完全的熟悉。作为软件开发工程师,这意味着在你的编程语言标准库中存在着对URI进行指挥功能的命令。

如果某门语言在标准库中没有 URL 模块,你要跑着离开这门语言(不能用走的!一定要跑!),这不是一门真正的编程语言。


在 Foundation 库中,NSURL用来代表 URL。

NSURL 可以通过 URLWithString: 类方法实例化。

NSURL *url = [NSURL URLWithString:@"http://example.com"];

如果传入值不是合法URL,这个方法会返回一个 nil 值。

我们几周前提到过 NSString 也有一些关于path处理的残留功能,但这些功能对于处理 NSURL 实在是太麻烦了。把 NSString 转化为 NSURL 带来的额外转化成本让这件事并不那么方便,你总是要花时间在这个上面。如果一个值就是一个URL,那么它就应该被保存为 NSURL,把这两种类型搞混是懒惰而鲁莽的API设计。

附加提示:@@ 是创建 NSURL 的字面量的绝佳方法(例如:@@"http://example.com"),怎么样,很方便吧?

NSURL 也有一个类方法 +URLWithString:relativeToURL: 可以根据一个 base URL 地址和关联字符串来构造 URL。这个方法的行为由于其对子目录的/符号的处理而变得非常混乱无序。

这里有一些这个方法用法的典型参考:

NSURL *baseURL = [NSURL URLWithString:@"http://example.com/v1/"];

[NSURL URLWithString:@"foo" relativeToURL:baseURL];
// http://example.com/v1/foo

[NSURL URLWithString:@"foo?bar=baz" relativeToURL:baseURL];
// http://example.com/v1/foo?bar=baz

[NSURL URLWithString:@"/foo" relativeToURL:baseURL];
// http://example.com/foo

[NSURL URLWithString:@"foo/" relativeToURL:baseURL];
// http://example.com/v1/foo

[NSURL URLWithString:@"/foo/" relativeToURL:baseURL];
// http://example.com/foo/

[NSURL URLWithString:@"http://example2.com/" relativeToURL:baseURL];
// http://example2.com/

URL Components

NSURL 根据 RFC 2396 的定义提供accessor方法用于获取URL每一部分的值:

absoluteStringabsoluteURLbaseURLfileSystemRepresentationfragmenthostlastPathComponentparameterStringpasswordpathpathComponentspathExtensionportqueryrelativePathrelativeStringresourceSpecifierschemestandardizedURLuser

NSURL官方文档 中的文档和样例是让你熟悉各种URL组成部分的绝佳参考。

虽然可以通过URL来存储用户名和密码,但建议用 NSURLCredential 装载用户名和密码,用keychain来存储它们更适合。

NSURLComponents

苹果在 iOS 7 和 OS X Mavericks 中悄悄添加了 NSURLComponents,这样就可以完美替代 NSMutableURL 了。但文档还不是很完善,所以这个类仍然是近期Foundation新增类中隐晦的一块。

创建 NSURLComponents 实例和创建 NSURL 实例的方法差不多,通过一个 NSString 和一个非必需的base URL参数创建(+componentsWithString: & +componentsWithURL:resolvingAgainstBaseURL:)。也可以用 alloc init 创建一个空的容器,和 NSDateComponents 差不多。

NSURLNSURLComponents 的不同之处在于,URL component 属性是 readwrite 的。它提供了安全直接的方法来修改URL的各个部分:

  • scheme
  • user
  • password
  • host
  • port
  • path
  • query
  • fragment

如果尝试赋值一个非法的scheme或port,会抛出一个异常。

另外,NSURLComponents 也有 readwrite 属性对每个 component 进行 [percent-encoded]。

  • percentEncodedUser
  • percentEncodedPassword
  • percentEncodedHost
  • percentEncodedPath
  • percentEncodedQuery
  • percentEncodedFragment

对这些 percent encoding 属性的 get 操作可能会造成 retain 增加。set 操作会默认认为该 component 已经正确 encode 了。试图赋值一个非法的 percent encode 值会抛出异常。虽然 ';' 是一个合法的路径字符,但建议还是percent-encoded一下来兼容NSURL(传递给-stringByAddingPercentEncodingWithAllowedCharacters: URLPathAllowedCharacterSet参数 会将所有的 ';' 字符 percent-encode)。

Percent-Encoding

说起 percent-encoding...

NSURLCFURLRef 的转换是 无缝的。底层的 C API 有 NSURL 的所有功能。包括 CFURLCreateStringByAddingPercentEscapesCFURLCreateStringByReplacingPercentEscapesUsingEncoding 异常:

  • CFURLCreateStringByAddingPercentEscapes:创建一个字符串的复制,用同义的 percent-encoded 字符代替原有的字符。
CFStringRef CFURLCreateStringByAddingPercentEscapes (
   CFAllocatorRef   allocator,
   CFStringRef      originalString,
   CFStringRef      charactersToLeaveUnescaped,
   CFStringRef      legalURLCharactersToBeEscaped,
   CFStringEncoding encoding
);
  • CFURLCreateStringByReplacingPercentEscapesUsingEncoding: 创建一个新字符串,用同义的percent-encoded字符代替原有的所有可替换字符。
CFStringRef CFURLCreateStringByReplacingPercentEscapesUsingEncoding (
   CFAllocatorRef   allocator,
   CFStringRef      origString,
   CFStringRef      charsToLeaveEscaped,
   CFStringEncoding encoding
);

Bookmark URL

最后一个话题是关于 bookmark URL 的,bookmard URL 可以在应用多次启动间安全地引用文件。可以认为是一种对 文件描述符 的持久化。

一个bookmark是一个唯一的数据类型,包含一个描述文件位置的 NSData 对象。鉴于path和文件引用URL在多次启动间可能被破坏,bookmark就可以被用来重建某个文件的URL地址,即使文件被改名或移动了位置也可以。

你可以在苹果官方的文件系统编程指南的"Locating Files Using Bookmarks"部分中阅读更多关于 bookmark URL 的内容。


忘记喷射火箭背包,忘记会飞的汽车吧,看看我对未来的设想:所有的东西都有一个 URL,以 Markdown 编码,用 Git 存储!如果你对宇宙资源定位器有兴趣的话,你会同意我的想法的!

超文本一样,通用标识就是一个哲学概念,通用标识理念早于计算机时代被提出,也将长存于人类信息体系中。这些通用标示合在一起便可以代表我们信息时代的架构:一个用来把我们对于宇宙每一点了解都encode为一个网络中实体的框架,这很酷,很像我们的大脑中存在很多神经元一样。

我们处在物理计算的寒武纪大爆发险境边缘。用不了多久就会出现这样的情景:在Internet组成的世界中,我们生活中的每一部分都有一个URL,也都有一个电子化的大脑,都有数字化的精神和意识。虽然不能说是奇点迫近,但是,我们,就正在某些未知但难以置信的奇妙事物边缘,马上就要感受到它的来临。

世界总是这样的:互相交换猫咪照片的技术,总是蕴含着无比高深的哲学含义。