在 Swift 应用里构造和修改 NSURL

作者:Nick Hanan,原文链接,原文日期:2016-03-17
译者:BigbigChai;校对:walkingway;定稿:CMB

许多应用程序都有访问文件的需求。也许是应用 bundle 或文件系统的文件,又或许是网上的资源。在代码里需要调用某些方法来指向这些文件。对于 Apple 平台而言,基本上只有两个选择:使用 String 或 NSURL。

使用过地址栏或任何终端的话,Swift 字符串将是一个非常容易理解的选择。我的意思是,所有的文本都是在地址栏的,对吧?Cocoa 和 Cocoa Touch SDK 中一些较旧的 API 都接收 NSURL 和字符串(通常在这些 API 中称为“路径”)作为参数,但是都越来越朝着只使用 NSURL 的方向发展。和 String 路径相比,NSURL 有许多优点,最明显的是可以访问 URL 各个部分的属性,而不必另外编写代码来从路径的字符串解析出这些组件。

请继续关注如何在 Swift 应用程序中学习创建和使用 NSURL。

在 Swift 中创建 NSURL

在 Swift 中,有几个构造器和工厂方法可以用于创建 NSURL,但是我只打算说明其中比较有用的一部分。

init?(string URLString: String)

这是最普通,也许也是最常用的方法。这需要 Swift 字符串版本的 URL,并将其转换为 NSURL 对象。 这个构造器允许失败,因为不是所有字符串都能生成合法的 URL。有一些字符无法在 URL 中使用,因此需要使用 % 编码,它的出现表示了可以在 URL 中发送的编码。我个人最常见的是 %20,”空格“字符。这个构造器只接收有效的字符,它不会另外做 % 编码。因此,如果任何无法转换为合法 URL 的内容或字符串出现时,该构造器将返回 nil。

    let NSHipster = NSURL(string: "http://nshipster.com/")                  //returns a valid URL
    let invalidURL = NSURL(string: "www.example.com/This is a sentence");   //Returns nil

这实际上是以下构造器的便利构造器。

init?(string URLString: String, relativeToURL baseURL: NSURL?)

这是允许定制的构造器。类似上一个构造器,它也是可失败的,接收类似的 URL Swift 字符串,同时也接受一个可选的 baseURL 对象(本身也是 NSURL)。如果 baseURL 为空,则完全使用 URLString 创建 URL,这也许就是第一个构造器的内在实现。

let NSHipsterTwo = NSURL(string: "http://nshipster.com/", relativeToURL: nil)   //Returns valid NSHipster URL
let article = NSURL(string: "ios9/", relativeToURL: NSHipster)

init(fileURLWithPath path: String, isDirectory isDir: Bool)

这类似于上面的构造器,只是用于指向本地文件或目录。我不确定为什么本地文件需要一个特殊版本,但我猜测它进行了一些优化(至少是以文件 scheme 开头,而不是 http 之类)。有另一个版本没有 isDirectory 参数,但已知路径是否目录的话,头文件建议使用这个方法。也许因为另一个版本将需要再执行检查,而这一个方法让用户提供了答案,能省下检查的步骤。

public init(fileURLWithPath path: String, isDirectory isDir: Bool, relativeToURL baseURL: NSURL?)

这是 iOS 9 中新增的方法。与上个方法类似,只是还加了 relativeToURL 参数。类似之前的构造器,这将返回一个NSURL,并将路径附加到 baseURL 后。如果有一个目录内的几个文件,有需求对这些文件进行迭代的时候,就可以利用这个方法了。可以提供文件所在的目录作为 baseURL,然后只需使用文件名作为 Swift 字符串路径创建 URL。

将 URL 转换回 Swift 字符串

有时候,特别是在处理较旧的 API 或要向用户展示时,需要将 NSURL 转换回 Swift 字符串。好在 NSURL 提供了一个简单的只读属性 absoluteString 来获取字符串。 NSURL 对象只需调用该属性就能获得:

let articleString = article?.absoluteString
//ArticleString now contains: "http://nshipster.com/ios9/"

在这种情况,接收了之前使用 relativeToURL 版本的构造器定义的 article 常量,从 scheme 直到结尾(在这种情况下是一个路径)把它解析成一个完整的 URL。如果一个 URL 包含文件扩展名(file extension),查询(query)和片段(fragment),也会把它们解析出来。可失败的构造器返回了原来的 article 对象,因此仍然有那个表示 Swift 可选链的问号。

修改 NSURL

这些函数都是基于被调用的 NSURL 返回一个新的、根据需求修改过的 NSURL。他们改变被调用的NSURL。

func URLByAppendingPathComponent(pathComponent: String, isDirectory: Bool) -> NSURL

这个方法给 URL 添加更多的路径组件,例如说你要添加一个文件到当前目录(存储在调用的 NSURL)。跟其他一些构造器一样,它有另一个没有 isDirectory 参数的版本。但如果能明确它是否为目录的话,建议使用这一个。因为这能省去用来确定是否目录的元数据检查。

var URLByDeletingLastPathComponent: NSURL? {get}

此属性将返回一个新的、删除了最后一个路径组件的 NSURL。这只修改 URL 的路径组件,URL 的其他组件(例如域名)不受影响。我们可以这样写:

//articleTwo now contains "http://nshipster.com/ios9/"
 
let deletePathComp = articleTwo?.URLByDeletingLastPathComponent
//deletePathComp now contains "http://nshipster.com/"

没有路径信息的话,结果可能会变得有点诡异。为了好玩,我链式调用了几个URLByDeletingLastPathComponent,但最后只是在后面附加了“../”,类似命令行(cd ..)返回上一个目录。

还有几个修改方法和属性,但这些可能是最常用的了。

Conclusion

All code in this post was tested in Xcode 7.3.1.

如果你好奇 URL 格式规范的细节,可以查看 Apple 的 NSURL 类型参考在处理 URL 部分提到的 RFC 文档。初始化 URL 时使用的字符串必须符合 RFC 2396,并且 URL 本身根据 RFC 1738RFC 1808 进行解析。这些规范内容很多,但你能找到所有可能关于 URL,URI 等的信息。

NSURL 中还有很多其他的属性。如果你想要一个完全解析的 NSURL,baseURL,主机(host),查询(query),片段(fragment)等,你可以查看 Apple 的 NSURL 类型参考。但对我个人而言,主要使用了 absoluteString,偶尔也会用到 pathExtension。

希望这篇文章对你有帮助。如果有,请在 Twitter 或任何社交媒体上分享这个帖子,每次分享都有裨益。当然,如果有任何问题,也请在联系页面 或 Twitter @CodingExplorer 上联系我,我会尽量解答的。谢谢!

参考来源

本文由 SwiftGG 翻译组翻译,已经获得作者翻译授权,最新文章请访问 http://swift.gg

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

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,597评论 18 139
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,019评论 4 62
  • Swift 介绍 简介 Swift 语言由苹果公司在 2014 年推出,用来撰写 OS X 和 iOS 应用程序 ...
    大L君阅读 3,174评论 3 25
  • “没能力,自己去学习 没人脉,自己去勾搭 没渠道,自己去建立 千万不要把自己的前途,建立在任何人身上。“ 以上几句...
    小小故事大智慧阅读 457评论 0 0
  • 我把公寓套房租给王女士。我的套房一房一厅,简单装修,已经使用了好几年了,又正好处在大楼的设计死角,房间呈三角形,因...
    陈旭山阅读 627评论 7 9