Prior to 18.x, this has worked for years. However, if a port is included, the behavior in 18.x is to return "///some/path". In all previous versions it correctly returns "/some/path".
Is this a bug, or documented change we missed?
func relativeURLString(for urlString: String) -> String? {
guard var components = URLComponents(string: urlString) else { return nil }
components.host = nil
components.scheme = nil
// WE FOUND IF YOU NIL THE PORT BEFORE HOST AND SCHEME, IT WORKS
components.port = nil
return components.string
}
Thanks for filing FB16336663
.
Foundation is in the process of some major refactoring [1], so weird problems like this aren’t 100% unexpected. And your code is really exploring an edge case — namely, URLs without a scheme — so that makes things harder.
Still, the fact that the behaviour changes depends on the order in which you set the properties is clearly problematic, and should be look at by the Foundation team.
Note that your code fails, regardless of the system version, if the original URL contains a user name or password. Try this https://mrgumby:opendoor@aHost.com:7443/path/to/module?a=1#blah
.
Reading between the lines, it looks like you’re trying to get the path and later components of the URL, so the path, query, and fragment. Here’s how I’d do that:
func relativeURLString(for urlString: String) -> String? {
guard let components = URLComponents(string: urlString) else { return nil }
var result = URLComponents()
result.path = components.path
result.queryItems = components.queryItems
result.fragment = components.fragment
return result.string
}
I think the following a more direct representation of your goal, and it should work regardless of this bug.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
[1] If you’re curious, watch the first half of Swift & Interoperability.
https://youtu.be/%77%6e6C_XEv1Mo