layout | title | category | tag | excerpt | author | translator |
---|---|---|---|---|---|---|
post |
NSURL /<br/>NSURLComponents |
Cocoa |
popular |
在所有的一维数据类型中,URI有着至高地位。单独就人类可阅读的字符串这一点来说,它存在并将永远存在于计算机中任何你能够想象到的对位置信息进行编码的数据中。 |
Mattt |
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]({% asset nsurl.png @path %})
对网络编程的扎实理解植根于对于 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/
NSURL
根据 RFC 2396 的定义提供accessor方法用于获取URL每一部分的值:
– absoluteString
– absoluteURL
– baseURL
– fileSystemRepresentation
– fragment
– host
– lastPathComponent
– parameterString
– password
– path
– pathComponents
– pathExtension
– port
– query
– relativePath
– relativeString
– resourceSpecifier
– scheme
– standardizedURL
– user
NSURL
官方文档 中的文档和样例是让你熟悉各种URL组成部分的绝佳参考。
虽然_可以_通过URL来存储用户名和密码,但建议用
NSURLCredential
装载用户名和密码,用keychain来存储它们更适合。
苹果在 iOS 7 和 OS X Mavericks 中悄悄添加了 NSURLComponents
,这样就可以完美替代 NSMutableURL
了。但文档还不是很完善,所以这个类仍然是近期Foundation新增类中隐晦的一块。
创建 NSURLComponents
实例和创建 NSURL
实例的方法差不多,通过一个 NSString
和一个非必需的base URL参数创建(+componentsWithString:
& +componentsWithURL:resolvingAgainstBaseURL:
)。也可以用 alloc init
创建一个空的容器,和 NSDateComponents
差不多。
NSURL
和 NSURLComponents
的不同之处在于,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...
NSURL
对 CFURLRef
的转换是 无缝的。底层的 C API 有 NSURL
的所有功能。包括 CFURLCreateStringByAddingPercentEscapes
和 CFURLCreateStringByReplacingPercentEscapesUsingEncoding
异常:
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 的,bookmard URL 可以在应用多次启动间安全地引用文件。可以认为是一种对 文件描述符 的持久化。
一个bookmark是一个唯一的数据类型,包含一个描述文件位置的
NSData
对象。鉴于path和文件引用URL在多次启动间可能被破坏,bookmark就可以被用来重建某个文件的URL地址,即使文件被改名或移动了位置也可以。
你可以在苹果官方的文件系统编程指南的"Locating Files Using Bookmarks"部分中阅读更多关于 bookmark URL 的内容。
忘记喷射火箭背包,忘记会飞的汽车吧,看看我对未来的设想:所有的东西都有一个 URL,以 Markdown 编码,用 Git 存储!如果你对_宇宙_资源定位器有兴趣的话,你会同意我的想法的!
像超文本一样,通用标识就是一个哲学概念,通用标识理念早于计算机时代被提出,也将长存于人类信息体系中。这些通用标示合在一起便可以代表我们信息时代的架构:一个用来把我们对于宇宙每一点了解都encode为一个网络中实体的框架,这很酷,很像我们的大脑中存在很多神经元一样。
我们处在物理计算的寒武纪大爆发险境边缘。用不了多久就会出现这样的情景:在Internet组成的世界中,我们生活中的每一部分都有一个URL,也都有一个电子化的大脑,都有数字化的精神和意识。虽然不能说是奇点迫近,但是,我们,就正在某些未知但难以置信的奇妙事物边缘,马上就要感受到它的来临。
世界总是这样的:互相交换猫咪照片的技术,总是蕴含着无比高深的哲学含义。