渐进式编程课
KMP 目录
第 18 课2026.08.03

iOS 端需要为同一个 PreferenceStorage 接口提供实现。共享 LanguageRepository 因此可以保持不变,同时在 iPhone 和 iOS 模拟器上使用系统偏好存储。

第 18 课:实现 iOS 偏好存储

  • 日期:2026-08-03
  • 课程序号:18
  • 知识点:在 iosMain 中用 NSUserDefaults 实现共享接口

用途

iOS 端需要为同一个 PreferenceStorage 接口提供实现。共享 LanguageRepository 因此可以保持不变,同时在 iPhone 和 iOS 模拟器上使用系统偏好存储。

核心概念

  • Kotlin/Native 可以在 iosMain 直接调用 Foundation API。
  • NSUserDefaults.standardUserDefaults 提供应用的标准偏好存储。
  • stringForKey() 在键不存在或不能转换成字符串时返回 null。
  • setObject() 写入字符串,removeObjectForKey() 删除对应值。
  • iOS 实现仍通过组合根注入共享 Repository,不在 UI 中直接读写键名。

示例代码

iosMain/IosPreferenceStorage.kt:

kotlin
import platform.Foundation.NSUserDefaults

class IosPreferenceStorage(
    private val defaults: NSUserDefaults =
        NSUserDefaults.standardUserDefaults,
) : PreferenceStorage {
    override fun putString(key: String, value: String) {
        defaults.setObject(value, forKey = key)
    }

    override fun getString(key: String): String? {
        return defaults.stringForKey(key)
    }

    override fun remove(key: String) {
        defaults.removeObjectForKey(key)
    }
}

在 iOS 侧的共享组合入口中组装:

kotlin
fun createIosLanguageRepository(): LanguageRepository {
    return LanguageRepository(
        storage = IosPreferenceStorage(),
    )
}

使用方式与 Android 相同:

kotlin
val repository = createIosLanguageRepository()
repository.saveLanguage("zh-CN")

println(repository.loadLanguage()) // zh-CN

5 分钟练习

调用上一课实现的 clearLanguage(),再读取语言偏好,并写出预期结果。

参考答案

kotlin
val repository = createIosLanguageRepository()

repository.saveLanguage("zh-CN")
repository.clearLanguage()

val language = repository.loadLanguage()
println(language) // null

删除后 NSUserDefaults.stringForKey() 返回 null,与 PreferenceStorage 的共享契约一致。

与上一课的联系

上一课使用 Android SharedPreferences 实现接口;本课使用 iOS NSUserDefaults 实现同一接口。至此,共享业务、测试 Fake、Android 和 iOS 四个调用方都遵守同一份存储契约。

参考资料