一个类型安全的键值存储解决方案,可以用几行代码将 Codable
类型存储在各种持久层中,例如用户默认设置(User Defaults)、文件系统、Core Data、Keychain 等!
Codable
类型。在使用 composable architecture 开发应用程序时,我喜欢 reducers 如何使用环境(environment)类型来保存该功能所需的所有依赖项,例如 API 客户端、分析客户端等。
Stores 尝试抽象存储的概念,并提供各种可以在这种环境中注入的实现,并在运行测试或基于远程标志时可以轻松交换。
这一切都归结为 SingleObjectStore
和 MultiObjectStore
这两个协议,它们定义在 Blueprints 层中,提供了可以存储单个或多个泛型 Codable
对象的存储的抽象概念。
这两个协议然后在不同的模块中实现,如下表所示
假设您有一个 User
结构体定义如下
struct User: Codable {
let id: Int
let name: String
}
以下是如何使用 Stores 存储它
Identifiable
协议这是使存储将对象与其 ID 相关联所必需的。
extension User: Identifiable {}
属性 id
可以是任何 Hashable
类型。阅读更多。
Stores 预先配备了以下存储
// Store for multiple objects
let store = MultiUserDefaultsStore<User>(suiteName: "users")
// Store for a single object
let store = SingleUserDefaultsStore<User>(suiteName: "users")
// Store for multiple objects
let store = MultiFileSystemStore<User>(path: "users")
// Store for a single object
let store = SingleFileSystemStore<User>(path: "users")
// Store for multiple objects
let store = MultiCoreDataStore<User>(databaseName: "users")
// Store for a single object
let store = SingleCoreDataStore<User>(databaseName: "users")
// Store for multiple objects
let store = MultiKeychainStore<User>(identifier: "users")
// Store for a single object
let store = SingleKeychainStore<User>(identifier: "users")
// Store for multiple objects
let store = MultiObjectStoreFake<User>()
// Store for a single object
let store = SingleObjectStoreFake<User>()
您可以通过实现 Blueprints
中的协议来创建自定义存储
// Store for multiple objects
final class MultiRealmStore<Object: Codable & Identifiable>: MultiObjectStore {
// ...
}
// Store for a single object
final class SingleRealmStore<Object: Codable>: SingleObjectStore {
// ...
}
// Store for multiple objects
final class MultiSQLiteStore<Object: Codable & Identifiable>: MultiObjectStore {
// ...
}
// Store for a single object
final class SingleSQLiteStore<Object: Codable>: SingleObjectStore {
// ...
}
假设我们有一个使用存储来获取数据的视图模型
struct UsersViewModel {
let store: AnyMultiObjectStore<User>
}
注入适当的存储实现
let coreDataStore = MultiCoreDataStore<User>(databaseName: "users")
let prodViewModel = UsersViewModel(store: coreDataStore.eraseToAnyStore())
或
let fakeStore = MultiObjectStoreFake<User>()
let testViewModel = UsersViewModel(store: fakeStore.eraseToAnyStore())
let john = User(id: 1, name: "John Appleseed")
// Save an object to a store
try store.save(john)
// Save an array of objects to a store
try store.save([jane, steve, jessica])
// Get an object from store
let user = store.object(withId: 1)
// Get an array of object in store
let users = store.objects(withIds: [1, 2, 3])
// Get an array of all objects in store
let allUsers = store.allObjects()
// Check if store has an object
print(store.containsObject(withId: 10)) // false
// Remove an object from a store
try store.remove(withId: 1)
// Remove multiple objects from a store
try store.remove(withIds: [1, 2, 3])
// Remove all objects in a store
try store.removeAll()
请在 Swift Package Index 阅读完整文档。
您可以通过将其添加为包依赖项来将 Stores 添加到 Xcode 项目中。
Stores
:整个库,包含所有存储。UserDefaultsStore
:使用用户默认设置(User Defaults)来持久化数据。FileSystemStore
:通过将其保存到文件系统来持久化数据。CoreDataStore
:使用 Core Data 数据库来持久化数据。KeychainStore
:在 Keychain 中安全地持久化数据。Blueprints
:仅协议,如果您不想使用任何提供的存储并构建您自己的存储,这是一个不错的选择。StoresTestUtils
:在您的测试目标中使用模拟数据(fakes)。Stores 在 MIT 许可证下发布。有关更多信息,请参见 LICENSE。