两行代码,两种结果
是否 import Foundation | "".contains("") |
"abc".contains("") |
---|---|---|
❌ 纯 Swift | true |
true |
✅ + Foundation | false |
false |
同一个 API,返回值完全相反,而且大多数 iOS 项目会间接 import Foundation,所以你一直用的其实是 ObjC 版本!
幕后黑手:桥接与方法决议
- Swift.String 与 NSString 是 toll-free bridged。
- 一旦
import Foundation
,编译器会把同名方法 优先桥接到 NSString 的实现。 - 两个版本的
contains
签名兼容,但 行为不同:
实现 | 空子串规则 |
---|---|
Swift 原生 | 空字符串是任何字符串的子串 → true |
NSString | 空子串不存在 → false |
实战影响
- 绝大多数 iOS/SwiftUI 工程都会间接 import Foundation → 你看到的都是
false
。 - 纯 Swift Package / Linux Server 没 Foundation → 看到的是
true
。 - 跨平台库若依赖空子串行为,务必显式测试两种环境。
避坑清单
场景 | 建议 |
---|---|
写跨平台库 | 显式单元测试两种 import 状态 |
需要与 ObjC 对齐 | 直接使用 Foundation 行为并写注释 |
想要纯 Swift 行为 | 自建模块不 import Foundation,或用 Swift-only 方法 |
不确定当前行为 | 打印类型或查看 Quick Help 看是 String.contains 还是 NSString.contains |
一句话总结
只要 import Foundation,你就默认接受了 NSString 的行为。
在写通用逻辑 / 跨平台库 / 纯 Swift Package时,记得给空子串单独写测试,别被"同名不同魂"坑了。