The doc of URLComponents.init(url:resolvingAgainstBaseURL:)
says:
Returns the initialized URL components object, or nil if the URL could not be parsed.
Knowing that:
- Swift URL/NSURL is for URLs based on RFC 1808, RFC 1738, and RFC 2732 [BEFORE iOS 17 / macOS 14]: https://developer.apple.com/documentation/foundation/nsurl
- Swift URLComponents/NSURLComponents is for URLs based on RFC 3986: https://developer.apple.com/documentation/foundation/nsurlcomponents
I assume that the initialization of URLComponents
will fail when the URL is conforming to RFC 1808/1738/2732 but not RFC 3986. What kind of URL is that? Any example?
The only hint I have so far as a difference may be related to different reserved characters?
[update since iOS 17 and macOS 14]
Since iOS 17, URL/NSURL now conforms to the RFC 3986 and no more to the obsolete RFC 1738/1808. Consequently, there are no more examples where URL would build successfully but where URLComponents would fail.
Answer for versions BEFORE iOS 17 / macOS 14
Let's explore it from its source code, as Swift Foundation is open-source.
The
URLComponents
initializer is implemented in apple/swift – URLComponents.swift and apple/swift-corelibs-foundation – URLComponents.swift and simply calls the initializer ofNSURLComponents
.The
NSURLComponents
initializer is implemented in apple/swift-corelibs-foundation – NSURL.swift and simply calls_CFURLComponentsCreateWithURL
._CFURLComponentsCreateWithURL
is implemented in apple/swift-corelibs-foundation – CFURLComponents.c and does:CFURLCopyAbsoluteURL
_CFURLComponentsCreateWithString
which calls:_CFURIParserParseURIReference
+ a failable_CFURIParserURLStringIsValid
CFURLCopyAbsoluteURL
is implemented in apple/swift-corelibs-foundation – CFURL.c and only fails for:The implementation of
CFURLCreateFilePathURL
is in opensource.apple.com/source/CF – CFURL.c, and my understanding is that it will only fail if there is no scheme or no path, which shouldn't be possible as we previously tested for a file scheme or file existence withCFURLIsFileReferenceURL
._CFURIParserParseURIReference
is implemented in apple/swift-corelibs-foundation – CFURLComponents_URIParser.c and will only fail if the URL length is more than 2 GB, which I believe is unrelated to RFC specifications._CFURIParserURLStringIsValid
will essentially call_CFURIParserValidateComponent
for each component and fail for invalid characters or escape sequences. This is possibly the most relevant part.Now, with a bit of experiments, we know we need a scheme (for instance,
https://
or simplya://
) and we play with the reserved characters to come up with examples such as:Trying the alternative initializer of
URLComponents
will also fail, so don't try to think it's different:Conclusion (before iOS 17)
"a://@@"
is an example of valid NSURL but invalid RFC 3986.On a side note, some Swift people seem to wish for the future to unify the support of URL and URLComponents (no more RFC differences) as seen in URL.swift:
I'm not sure how they plan to do this, as it would mean that eitherURL(string: "a://@@")
would fail orURLComponents(string: "a://@@")
would succeed.Well history shows that, since iOS 17,
URL(string: "a://@@")
is now returningnil
.