AppDependency 是一个 Swift 包,它以线程安全、类型安全且 SwiftUI 友好的方式简化了应用程序依赖项的管理。AppDependency 具有用于管理依赖项的专用结构体类型,可轻松且协调地访问应用程序中的依赖项。此外,该软件包还包含内置的日志记录机制,以帮助调试和跟踪错误。 AppDependency 软件包还拥有一个基于缓存的系统,可以在任何给定时间持久存储和检索任何应用程序范围的数据。
AppDependency 只是 AppState 的一个依赖项镜像。
要求: iOS 15.0+ / watchOS 8.0+ / macOS 11.0+ / tvOS 15.0+ / visionOS 1.0+ | Swift 5.9+ / Xcode 15+
非 Apple 平台支持: Linux & Windows
(🍎 仅限 Apple OS)
@ObservedObject
提供支持,以便将更改发布到 SwiftUI 视图。要将 AppDependency 集成到您的 Swift 项目中,您需要使用 Swift Package Manager (SPM)。 SPM 可以轻松管理 Swift 包依赖项。这是你需要做的
Package.swift
文件中dependencies: [
.package(url: "https://github.com/0xLeif/AppDependency.git", from: "1.0.0")
]
如果您正在使用 App 项目,请在 Xcode 中打开您的项目。导航到 File > Swift Packages > Add Package Dependency...
并输入 https://github.com/0xLeif/AppDependency.git
。
成功添加 AppDependency 作为依赖项后,您需要将 AppDependency 导入到要使用的 Swift 文件中。这是一个代码示例
import AppDependency
Dependency
是 AppDependency 提供的一个功能,允许您在应用程序中定义共享资源或服务。
要定义依赖项,您应该扩展 Application
对象。这是一个定义 networkService
依赖项的示例
extension Application {
var networkService: Dependency<NetworkServiceType> {
dependency(NetworkService())
}
}
在此示例中,Dependency<NetworkServiceType>
表示 NetworkService
的类型安全容器。
定义依赖项后,您可以在应用程序中的任何位置访问它
let networkService = Application.dependency(\.networkService)
这种方法允许您以类型安全的方式处理依赖项,避免手动处理与不正确类型相关的错误。
AppDependency 提供了 @AppDependency
属性包装器,可以简化对依赖项的访问。 当您使用 @AppDependency
注释属性时,它会直接从 Application
对象中获取相应的依赖项。
struct ContentView: View {
@AppDependency(\.networkService) var networkService
// Your view code
}
在这种情况下,ContentView 可以访问 networkService 依赖项,并且可以在其代码中使用它。
当您的依赖项是一个 ObservableObject
时,对它的任何更改都会自动更新您的 SwiftUI 视图。 请确保您的服务符合 ObservableObject
协议。 为此,你不应该使用 @AppDependency
属性包装器,而应该使用 @ObservedDependency
属性包装器。
这是一个例子
class DataService: ObservableObject {
@Published var data: [String]
func fetchData() { ... }
}
extension Application {
var dataService: Dependency<DataService> {
dependency(DataService())
}
}
struct ContentView: View {
@ObservedDependency(\.dataService) private var dataService
var body: some View {
List(dataService.data, id: \.self) { item in
Text(item)
}
.onAppear {
dataService.fetchData()
}
}
}
在此示例中,每当 DataService
中的数据发生更改时,SwiftUI 都会自动更新 ContentView
。
在 AppDependency 中使用 Dependency
的一个巨大优势是能够在测试期间用 Mock 版本替换依赖项。 这对于隔离应用程序的各个部分以进行单元测试非常有用。
您可以通过调用 Application.override
函数来替换依赖项。 此函数返回一个 DependencyOverride
,您需要保留此 token,只要您希望 Mock 依赖项有效。 当 token 被释放时,依赖项会恢复到其原始状态。
这是一个例子
// Real network service
extension Application {
var networkService: Dependency<NetworkServiceType> {
dependency(NetworkService())
}
}
// Mock network service
class MockNetworkService: NetworkServiceType {
// Your mock implementation
}
func testNetworkService() {
// Keep hold of the `DependencyOverride` for the duration of your test.
let networkOverride = Application.override(\.networkService, with: MockNetworkService())
let mockNetworkService = Application.dependency(\.networkService)
// Once done, you can allow the `DependencyOverrideen` to be deallocated
// or call `networkOverride.cancel()` to revert back to the original service.
}
要在 SwiftUI 预览中覆盖依赖项,必须使用 Environment.preview 函数并将依赖项覆盖传递给内容。
class Service {
var title: String { "Live Service" }
}
class MockService: Service {
override var title: String { "Mock Service" }
}
extension Application {
var service: Dependency<Service> {
dependency(Service())
}
}
struct ContentView: View {
@AppDependency(\.service) private var service
var body: some View {
Text(service.title)
}
}
#Preview {
Application.preview(
Application.override(\.service, with: MockService()),
Application.override(\.userDefaults, with: UserDefaults())
) {
ContentView()
}
}
AppDependency 在 MIT 许可证下发布。 有关更多信息,请参见LICENSE。