• 注意:在 iOS 17 中 URL 的行为有所更改
  • 发布于 2个月前
  • 233 热度
    0 评论
  • LoveC
  • 1 粉丝 35 篇博客
  •   
前言
Xcode 15 以及 iOS 17 已经发布一段时间了,作为开发者,需要关注的是哪些 API 有所改动,特别是底层的 API,影响面可能会比较广,今天讲一个关于 URL 对象的 API 更改。

当我们打开 URL 的初始化方法的官方文档 https://developer.apple.com/documentation/foundation/url/3126806-init,会看到一个重要的提示:
For apps linked on or after iOS 17 and aligned OS versions, URL parsing has updated from the obsolete RFC 1738/1808 parsing to the same RFC 3986 parsing as URLComponents. This unifies the parsing behaviors of the URL and URLComponents APIs. Now, URL automatically percent- and IDNA-encodes invalid characters to help create a valid URL.

翻译一下就是 URL 解析已从过时的 RFC 1738/1808 解析更新为与 URLComponents 相同的 RFC 3986 解析。

什么是 RFC
RFC 是 Request for Comments 的首字母缩写,是互联网工程任务组 (IETF)的对于 URL 的规范出的文档,其中包含有关互联网和计算机网络相关主题(如路由、寻址和传输技术)的规范和组织说明。

针对新的标准,个人或团体可以向委员会提交内容,委员会工作组经过一系列审核并通过之后,RFC 生产中心 (RPC) 会为 RFC 分配一个唯一编号,并通过 RFC 编辑器发布。RFC 发布后,它永远不会更改。我们前面提到的 RFC 1738/1808 和 RFC 3986 就是他们发布的其中一个标准。

苹果的支持
在 iOS 17 之前,URL 初始化时支持的是较久的 RFC 1738/1808 标准,但是 URLComponents 支持的是 RFC 3986 标准,两个标准不同导致 iOS 开发者在某些时候比较困惑,所以苹果在今年的更新中,终于把标准统一了,统一支持 RFC 3986 标准。

变化是什么?
在 iOS 17 之前,URL(string: "Not an URL") 会返回 nil,因为这是一个无效的 URL 格式,但是在 iOS 17 上,这段代码将会返回 Not%an%URL,相当于是把中间的空格进行了一次 encode。
// iOS 16
let validURL = URL(string: "https://google.com") // 返回 https://google.com
let url = URL(string: "Not an URL")              // 返回 nil

// iOS 17
let validURL = URL(string: "https://google.com") // 返回 https://google.com
let url = URL(string: "Not an URL")              // 返回 Not%an%URL
新的行为对于老的项目可能不太友好,甚至可能出现非预期的行为,比如,之前可能会有这样的判断:
if let url = URL(string: "Not an URL") {
    // url 有效
}
但这段代码在 Xcode 15 中 iOS 17 上也会走进去,因此可能导致非预期的后果。

如何兼容
Apple 在 iOS 17 的 URL 初始化方法中,添加了一个带有 Bool (默认值 true)的新参数 encodingInvalidCharacters,这个参数代表是否 encoding 掉无效的字符,如果传 false,URL 的行为将会和 iOS 16 上一致。
public init?(string: String, encodingInvalidCharacters: Bool)
使用效果如下:
// iOS 16
let url = URL(string: "Not an URL") // => nil

// iOS 17
let url = URL(string: "Not an URL", encodingInvalidCharacters: false) // => nil
如果你不想改变 URL 的默认行为,从而兼容以前的代码,需要把之前使用 URL 初始化的方法加上 encodingInvalidCharacters: false 参数。

结论
虽然苹果使 URL 支持了新的标准,和 URLComponents 保持了一致,这是好事,但是一刀切直接把默认行为改掉,这点还是比较坑的。更保守的做法应该是开一个新的方法来支持新标准,并且将老的方法标记为过期,慢慢过渡。不得不说,苹果还是那个有些坑开发者的苹果。
用户评论