6

的文档URLComponents.init(url:resolvingAgainstBaseURL:)说:

返回初始化的 URL 组件对象,如果无法解析 URL,则返回 nil。

知道:

我假设URLComponents当 URL 符合 RFC 1808/1738/2732 但不符合 RFC 3986 时,初始化将失败。那是什么类型的 URL?有什么例子吗?

到目前为止,我唯一的提示可能与不同的保留字符有关?

4

1 回答 1

11

让我们从它的源代码来探索它,因为 Swift Foundation 是开源的。

  1. URLComponents初始化器在 apple/swift – URLComponents.swift 和 apple/swift-corelibs-foundation – URLComponents.swift 中实现,简单调用NSURLComponents.

  2. NSURLComponents初始化器在apple /swift-corelibs-foundation - NSURL.swift中实现,并且简单地调用_CFURLComponentsCreateWithURL.

  3. _CFURLComponentsCreateWithURLapple/swift-corelibs-foundation – CFURLComponents.c中实现并执行以下操作:

    • 一个失败的副本CFURLCopyAbsoluteURL
    • 一个失败的创作,_CFURLComponentsCreateWithString它调用:
      • _CFURIParserParseURIReference+ 失败的_CFURIParserURLStringIsValid
  4. CFURLCopyAbsoluteURLapple/swift-corelibs-foundation – CFURL.c中实现,仅在以下情况下失败:

    #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
        if ( base && CFURLIsFileReferenceURL(base) && !CFURLHasDirectoryPath(base) ) {
            // 16695827 - If the base URL is a file reference URL which doesn't end with a slash, we have to convert it to a file path URL before we can make it absolute.
            base = CFURLCreateFilePathURL(alloc, base, NULL);
            if ( !base ) {
                // could not convert file reference URL to file path URL -- fail will NULL
                return NULL;
            }
        }
    #endif
    

    的实现CFURLCreateFilePathURLopensource.apple.com/source/CF – CFURL.c中,我的理解是只有在没有方案或没有路径的情况下才会失败,这应该是不可能的,因为我们之前测试了一个文件方案或文件存在CFURLIsFileReferenceURL

  5. _CFURIParserParseURIReferenceapple/swift-corelibs-foundation – CFURLComponents_URIParser.c中实现,并且仅当 URL 长度超过 2 GB 时才会失败,我认为这与 RFC 规范无关。

  6. _CFURIParserURLStringIsValid本质上将调用_CFURIParserValidateComponent每个组件,并因无效字符或转义序列而失败。这可能是最相关的部分。

现在,通过一些实验,我们知道我们需要一个方案(例如,https://或者简单地说a://),并且我们使用保留字符来提出示例,例如:

// OK
let url = URL(string: "a://@@")!
// CRASH
let components = URLComponents(url: url, resolvingAgainstBaseURL: true)!

尝试替代初始化器URLComponents也会失败,所以不要试图认为它是不同的:

// CRASH
let components = URLComponents(string: url.absoluteString)!

结论

"a://@@"是一个有效的 NSURL 但无效的 RFC 3986 的例子。


在旁注中,一些 Swift 人似乎希望未来统一对 URL 和 URLComponents 的支持(不再有 RFC 差异),如 URL.swift 所示

// 未来的实现说明:
// NSURL(实际上是 CFURL,它提供了它的实现)在处理一些更深奥(和一些不那么深奥)的字符串时有很多怪癖。我们希望将其中的大部分内容转移到更现代的 NSURLComponents 中,但是二进制兼容性问题使这变得困难。
// 希望很快,我们可以将下面的一些对 NSURL 的委托替换为对 NSURLComponents 的委托。它不能零碎完成,否则我们会从 API 中得到不一致的结果。

我不确定他们打算如何做到这一点,因为这意味着要么URL(string: "a://@@")失败,要么URLComponents(string: "a://@@")成功。

于 2019-04-11T07:52:29.790 回答