When Importing Foundation Changes Swift’s Behavior


Greetings, traveler!

Swift is often described as a modern language with its own standard library, while Foundation comes from the Objective-C era and provides a wide set of APIs for working with strings, collections, dates, and more. What’s less obvious is that importing Foundation can actually change the behavior of methods you might think are purely part of Swift.

A recent example illustrates this well.

The String.contains Surprise

Consider the following code, without importing Foundation:

"".contains("")   // true
"string".contains("")  // true

Now, add import Foundation:

import Foundation

"".contains("")   // false
"string".contains("")  // false

The contains suddenly behaves differently for empty substrings.

Why This Happens

String in Swift is bridged to Objective-C’s NSString when you import Foundation. This means that many NSString instance methods become available directly on String. If NSString has a method with the same name and compatible signature as one in Swift’s standard library, the Objective-C method may take precedence in overload resolution.

In this case:

  • Without Foundation, contains refers to Swift’s native implementation, which returns true if the searched substring is empty.
  • With Foundation, contains resolves to NSString’s implementation, which returns false for an empty substring.

Practical Impact

In most real-world iOS projects, you have Foundation imported indirectly through UIKit, SwiftUI, or AppKit, so the Foundation behavior is what you’ll encounter. The “pure Swift” implementation is mostly visible in isolated Swift-only modules.

Takeaway

When working in Swift, especially in cross-platform or Swift-only contexts, be aware that importing Foundation can alter method resolution for bridged types. If a method starts behaving differently than you expect, check whether you’re calling the Swift or the Objective-C implementation.