What is a URL in Foundation, and what does URL(string:) accept?

2.3.1 · L1 · Interview

Predict first

What does this print on iOS 17 / macOS 14 or later?

print(URL(string: "https://example.com/a b") as Any)
  • nil
  • Optional(https://example.com/a%20b)
  • Crash

Predict first

What does this print?

let u = URL(string: "https://user@example.com:8080/p/a/t/h?x=1#frag")!
print(u.host!, u.port!, u.lastPathComponent)
  • example.com 8080 h
  • user 8080 h
  • example.com:8080 h

Mental model. A URL is a postal address written in a standard layout. It tells you where something is, not what is inside.

URL is a value type that holds a parsed address: scheme, host, port, path, query and fragment. It does not fetch anything; it is just a structured name. URL(string:) returns an optional because the text may not be a valid URL.

What counts as valid changed. Since iOS 17 and macOS 14, URL(string:) follows the newer standard and percent-encodes characters that used to be rejected, such as a space, so "https://x.com/a b" now succeeds. On older systems it returned nil. Pass encodingInvalidCharacters: false for strict parsing, and test on your oldest deployment target.

Newer Foundation percent-encodes the space instead of rejecting the string. Older versions returned nil.

host excludes the user and port, which have their own properties.

Common traps

  • “URL(string:) returns nil for bad input.” It depends on the OS: iOS 17 and later fix up spaces instead of failing.
  • Force-unwrapping a URL built from user input. Keep the optional and handle it.

They might follow up with

  • Is URL thread-safe to share? Yes. It is an immutable value.
  • What is the difference between URL and URLRequest? A request adds method, headers, body and cache policy to the address.

Related questions

  • 2.3.4 Why use URLComponents and URLQueryItem, and what do they still not encode for you?
  • 2.3.2 What is the difference between a file URL and a web URL, and URL(fileURLWithPath:) and URL(string:)?

What is the difference between a file URL and a web URL, and… →