I'm not an expert on the topic, but I have managed to find a couple of URL strings that the two methods will parse differently:
let urlString = "http://www.foo.com/file;.html"
URLComponents will escape the semicolon here, whereas URL will not:
print(URLComponents(string: urlString)?.url as Any)
print(URL(string: urlString) as Any)
outputs:
Optional(http://www.foo.com/file%3B.html)
Optional(http://www.foo.com/file;.html)
Additionally, URL will attempt to parse a URL with the invalid character [ in path, even though this is invalid:
let urlString = "http://www.foo.com/file[.html"
print(URLComponents(string: urlString)?.url as Any)
print(URL(string: urlString) as Any)
outputs:
nil
Optional(http://www.foo.com/file%5B.html)
EDIT: URLComponents seems to be a lot better about sanity-checking in general; it rejects blatantly incorrect URIs which URL does not, such as:
[ and ] other than in a IPv6 address: http://www.foo.com/file[.html
non-numerics in the port number: http://www.foo.com:1~2
two @s in the user portion: http://user@user@www.foo.com/
colons where they don't belong: http://www.f:oo.com/
Notice how the board software gives up on parsing the above URLs as soon as it hits the incorrect part, since they're invalid URLs—but URL(string:) will try to parse them anyway.
There's probably more; I'm far from an expert on the subject. For me the bottom line, though, is the fact that RFC 3986 is the current standard for URIs, and that the older RFCs 2732, 2396, and 1808 are all marked obsolete as per the specification. It is not considered acceptable to have String follow an obsolete version of the Unicode standard; why should this be any different?