自从文档更新以支持更新的语言特性(async/await)以来,此软件包已发生更改。要支持旧版本的操作系统,请参阅已弃用的分支。
Loadability 是一个用于 Swift 的高级网络和缓存库,它允许您轻松地在您的应用程序中实现自定义的网络和/或缓存堆栈,并原生支持 Combine 和 SwiftUI。
Loadability 使用 Apple 的 Combine 框架来发布加载的对象和错误,并内置了 SwiftUI 支持来创建视图,这些视图可以在加载内容时显示占位符。
Loadability 支持 iOS 14+、macOS 11+ 和 watchOS 7+。它没有任何依赖项。
您可以使用 Loadability 作为 Swift Package,或者手动将其添加到您的项目中。
Swift Package Manager 是一种将依赖项添加到您的应用程序的方式,并与 Xcode 原生集成。
要使用 SPM 添加 Loadability,请点击 File ► Swift Packages ► Add Package Dependency...,然后键入此 Github 仓库的 URL。 然后,Xcode 会将该软件包添加到您的项目并执行所有必要的工作来构建它。
https://github.com/julianschiavo/Loadability
或者,将该软件包添加到您的 Package.swift 文件中。
let package = Package(
// ...
dependencies: [
.package(url: "https://github.com/julianschiavo/Loadability.git", from: "1.0.0")
],
// ...
)
请参阅 SPM 文档 以了解更多信息。
如果您不想使用 SPM,您还可以通过从此存储库构建库来将 Loadability 添加为普通框架。(有关执行此操作的说明,请参阅其他来源。)
Loadability 声明了基本的协议和类,您可以在应用程序中扩展这些协议和类来构建加载器和缓存。 它还有一个(可选的)SwiftUI 集成(请参阅下方),用于视图加载其数据并在加载时显示占位符。
该库具有 广泛的文档。如果您希望深入了解该库,或者实现下面未讨论的内容,请在提交 issue 之前查阅内联文档。
请注意,本节中的代码片段为了简洁起见省略了一些代码; 有关完整的代码示例,请参阅示例部分。
Loadability 网络以加载器的概念为中心。 Loader 从某个来源加载数据并将其作为 ObservableObject 发布,您可以手动观察它或通过 SwiftUI 支持集成。
要创建一个加载器,您可以创建一个符合抽象 Loader 协议的类,或者符合实现默认行为的子协议之一,例如 SimpleNetworkLoader 和 CachedLoader。
加载器有一些最少的共享要求,包括已发布的对象属性和加载时可能发生的错误,以及加载数据的方法。您可以扩展加载器以符合您自己的自定义要求。
这是一个加载器的示例。每个加载器都有一个关联类型,用于加载的对象类型,以及加载器用于标识要加载的对象的 key。
class YourLoader: Loader {
@Published var object: YourObject?
@Published var error: IdentifiableError?
func createRequest(for key: YourKey) -> URLRequest {
URLRequest(url: /* some URL */)
}
func createPublisher(key: YourKey) -> AnyPublisher<YourObject, Error>? {
let request = createRequest(for: key)
return URLSession.shared
.dataTaskPublisher(for: request)
.retry(3)
.tryMap { data, response in
try self.decode(data, key: key)
}
.eraseToAnyPublisher()
}
private func decode(_ data: Data, key: YourKey) throws -> YourObject {
/* decode the data, for example, using a JSONDecoder */
}
}
如前所述,加载器会自动符合 ObservableObject; 您可以自己观察已发布的属性或使用 SwiftUI 集成。
Loadability 具有一些特定的内置加载器,这些加载器实现了常见的需求,从而减少了某些实现所需的代码。 如果特定的内置加载器满足您的需求,您可以子类化该加载器,而不是通用的 Loader 协议。
SimpleNetworkLoader 实现了基本的网络加载器,并具有可选的预定义 Codable 解码支持。您可以在需要默认网络加载器的情况下使用此加载器。
此处显示了此加载器的示例; 如您所见,它比完整的 Loader 子类更容易实现,仅使用您创建的 URLRequest 为您处理网络代码。 您可以创建自定义解码实现来解码从网络请求收到的 Data,或者,如果您的对象类型符合 Codable,则可以利用使用 JSONDecoder 的预定义解码实现。
class YourLoader: SimpleNetworkLoader {
@Published var object: YourObject?
@Published var error: IdentifiableError?
func createRequest(for key: YourKey) -> URLRequest {
URLRequest(url: /* some URL */)
}
func decode(_ data: Data, key: YourKey) throws -> YourObject {
/* optional custom decoding implementation */
}
}
CachedLoader 使用下面讨论的缓存系统来实现缓存加载数据的加载器。 我们鼓励您在想要缓存数据而不是实现自己的缓存加载器时使用此加载器,因为它处理诸如预加载缓存数据和在加载后异步更新缓存之类的任务。
这是 CachedLoader 子类的示例(请参阅缓存部分,了解如何创建 Cache)。
class YourLoader: CachedLoader {
@Published var object: YourObject?
@Published var error: IdentifiableError?
var cache = YourCache.self /* a SharedCache or SharedSerializableCache type */
func createRequest(for key: YourKey) -> URLRequest {
URLRequest(url: /* some URL */)
}
func createPublisher(key: YourKey) -> AnyPublisher<YourObject, Error>? {
/* see the Loader example above */
}
private func decode(_ data: Data, key: YourKey) throws -> YourObject {
/* see the Loader example above */
}
}
代码与 Loader 代码段类似,因为缓存由库在内部处理; 您只需要提供将使用的 Cache。
除了网络之外,Loadability 还支持缓存,它是一个建立在 Apple 的 NSCache 之上的 Swift 实现,具有许多附加功能,包括序列化支持(将缓存保存到磁盘以供重用)。
基本的 Cache 类是 NSCache 的基本包装器,支持与 Objective-C 版本相同的功能。 创建 Cache 的实例,并使用下标来访问、修改或删除值,如下所示
let cache = Cache<YourKey, YourObject>()
cache[key] = YourObject() // Add value
cache[key] = YourObject(someParameter: true) // Modify value
let object = cache[key] // YourObject?, Access cached value
cache[key] = nil // Remove value
SerializableCache 子类化了基类 Cache,以添加对将缓存保存到磁盘的支持,这允许您在应用程序重新启动或类似事件时重新加载旧的缓存。 每个 SerializableCache 都有一个名称,该名称在每个应用程序中必须是唯一的,并且每次初始化时都必须相同,以标识磁盘上的缓存。 请注意,可序列化缓存的 key 和对象类型必须符合 Codable。
您可以使用类方法 load(name:) 而不是直接创建实例,该方法尝试从磁盘加载现有缓存,如果现有缓存无效或不存在,则回退到创建新缓存,例如在首次初始化时。 该方法的未来调用(例如在随后的应用程序重新启动时)从磁盘加载并解码先前保存的缓存。
let sCache = SerializableCache<YourKey, YourObject>.load(name: "Name")
缓存值的访问、修改和删除方式与使用普通 Cache 相同。 save() 方法对缓存进行编码并将其写入磁盘; 这是在写入和修改时自动调用的,因此在正常的实现中不需要自己调用它。
创建新的缓存实例,尤其是 SerializableCache 的实例,成本高昂且耗能。 此外,创建多个缓存实例将导致缓存的数据未在您的应用程序中共享,从而导致不必要的网络请求。
Loadability 支持“共享”缓存,这是一种类似单例的模式,允许您为拥有的每种类型的缓存在整个应用程序中使用相同的缓存。
您可以通过子类化 SharedCache 或 SharedSerializableCache 来创建共享缓存,具体取决于您想要的功能。
struct YourCache: SharedSerializableCache {
typealias Key = YourKey
typealias Value = YourValue
static let shared = SerializableCache<YourKey, YourObject>.load(name: "Name")
}
每次需要该缓存时,都使用 shared 实例,而不是创建多个缓存实例。
如上文加载器下的CachedLoader部分中所讨论的,Loadability 在缓存和加载器之间进行了集成。 虽然您可以直接将缓存实例与自定义加载器一起使用,但强烈建议使用共享缓存和 CachedLoader,因为根据定义,加载器是为加载的每个对象创建的。
按照前一节关于共享缓存的代码创建一个共享缓存,并将加载器中的 cache 变量设置为该类的类型(例如 YourCache.self)。
Loadability 对 SwiftUI 具有原生支持; 在视图中加载数据变得非常简单。 创建任何类型的 Loader 后,通过符合 LoadableView 使您的视图可加载。 该协议处理加载数据并在加载时显示您的占位符内容,然后将一个 non-nil 对象传递给您实现的新的 body(with:) 方法来创建您的主体内容。
您只需要实现一些基本要求; 创建加载器类型、传递 key,以及实现占位符和主体方法。
以下显示了创建可加载视图的示例。 请注意以下几个关键点
@StateObject 注释,否则加载器的发布者将不会按预期更新视图body 变量,并传入 LoadableView 生成的 loaderViewstruct YourView: View, LoadableView {
@StateObject var loader = YourLoader() // must be annotated by @StateObject
var body: some View {
loaderView // required
}
func body(with object: YourObject) -> some View {
/* create a body with the object */
}
func placeholder() -> some View {
ProgressView("Loading...")
}
}
Loadability 还公开了 Load,它是 LoadableView 内部使用的一种视图类型。 如果您需要自定义实现,请使用此视图来更好地控制加载行为。 但是,请首先尝试 LoadableView。
Loadability Examples 存储库包含实际的应用程序示例,演示了如何使用该库。 COVID-19 应用程序项目显示了 Loadability 的实现,并支持缓存,并使用了上面讨论的缓存和网络加载器。
欢迎任何人贡献代码和提交 pull 请求! 如果您发现 Loadability 存在问题,请提交 Github Issue,或者,如果您知道如何修复它,请提交一个 pull 请求。
Loadability 最初由 Julian Schiavo 在业余时间创建,并根据 MIT 许可证提供。 如果您发现该库有用,请考虑在 Github 上赞助我,这有助于开发和学习资源,并使我能够继续制作像这样的炫酷的东西!
Loadability 的灵感来自 John Sundell 关于 处理 SwiftUI 视图中的加载状态 和 Swift 中的缓存 的深入博客文章(并经许可使用代码),因此感谢 John 提供的灵感和示例。 如果您想更好地了解 Swift 中的加载或缓存,我强烈建议您查看上面链接的文章,以及他的许多其他文章!
根据 MIT 许可证提供。 有关更多信息,请参阅许可证。