此仓库包含 RxSwift 扩展,用于 Nuke,以及由 Rx 解决的常用 用例示例。
用例
入门
用法
RxNuke 为 Nuke 提供一系列响应式扩展
extension Reactive where Base: ImagePipeline {
public func loadImage(with url: URL) -> Single<ImageResponse>
public func loadImage(with request: ImageRequest) -> Single<ImageResponse>
}
Single
是Observable
的一种变体,它不会发射一系列元素,而是始终保证发射单个元素或错误。使用Single
的常见用例是包装 HTTP 请求。有关更多信息,请参阅 特性。
以下是基本示例,我们加载一张图片并在成功时显示结果
ImagePipeline.shared.rx.loadImage(with: url)
.subscribe(onSuccess: { imageView.image = $0.image })
.disposed(by: disposeBag)
从低分辨率到高分辨率
假设您想向用户展示一个高分辨率但下载速度较慢的图片。而不是让他们长时间盯着占位符,您可以快速下载一个小缩略图。
您可以使用concat
操作符来实现这一点,这将导致顺序执行。它将首先启动缩略图请求,等待其完成,然后才开始请求高分辨率图片。
Observable.concat(pipeline.rx.loadImage(with: lowResUrl).orEmpty,
pipeline.rx.loadImage(with: highResUtl).orEmpty)
.subscribe(onNext: { imageView.image = $0.image })
.disposed(by: disposeBag)
orEmpty
是一个自定义属性,它忽略错误并完成序列(相当于RxSwiftExt中的func catchErrorJustComplete()
)。extension RxSwift.PrimitiveSequence { public var orEmpty: Observable<Element> { return self.asObservable().catchError { _ in .empty() } } }
加载第一个可用的图片
假设您有一个相同图片的多个URL。例如,您可能已经上传了从相机拍摄的图片。在这种情况下,首先尝试获取本地URL,如果失败,再尝试获取网络URL是有益的。下载我们可能已经本地的图片是可耻的。
该用例与从低分辨率到高分辨率非常相似,但添加了.take(1)
保证我们一收到第一个结果就会停止执行。
Observable.concat(pipeline.rx.loadImage(with: localUrl).orEmpty,
pipeline.rx.loadImage(with: networkUrl).orEmpty)
.take(1)
.subscribe(onNext: { imageView.image = $0.image })
.disposed(by: disposeBag)
加载多个图片,一次性显示全部
假设您想为按钮加载两个图标,一个用于.normal
状态,一个用于.selected
状态。只有当这两个图标都加载好时,您才能向用户展示按钮。这可以使用combineLatest
操作符实现。
Observable.combineLatest(pipeline.rx.loadImage(with: iconUrl).asObservable(),
pipeline.rx.loadImage(with: iconSelectedUrl).asObservable())
.subscribe(onNext: { icon, iconSelected in
button.isHidden = false
button.setImage(icon.image, for: .normal)
button.setImage(iconSelected.image, for: .selected)
}).disposed(by: disposeBag)
在验证图片的同时显示过时的图片
假设您想在去服务器验证它的时候,向用户展示一个存储在磁盘缓存(Foundation.URLCache
)中的过时图像。这个用例实际上与从低分辨率到高分辨率进行转换类似。
let cacheRequest = URLRequest(url: imageUrl, cachePolicy: .returnCacheDataDontLoad)
let networkRequest = URLRequest(url: imageUrl, cachePolicy: .useProtocolCachePolicy)
Observable.concat(pipeline.rx.loadImage(with: ImageRequest(urlRequest: cacheRequest).orEmpty,
pipeline.rx.loadImage(with: ImageRequest(urlRequest: networkRequest)).orEmpty)
.subscribe(onNext: { imageView.image = $0.image })
.disposed(by: disposeBag)
了解更多关于HTTP缓存的信息,请参阅图片缓存。
自动重试
使用另外的延迟选项进行指数退避自动重试,包括网络连接重新建立时的立即重试,通过智能重试。
pipeline.rx.loadImage(with: request).asObservable()
.retry(3, delay: .exponential(initial: 3, multiplier: 1, maxDelay: 16))
.subscribe(onNext: { imageView.image = $0.image })
.disposed(by: disposeBag)
跟踪活动
假设您想在等待图像加载时显示一个活动指示器。您可以如何使用RxSwiftUtilities提供的ActivityIndicator
类来完成这个任务。
let isBusy = ActivityIndicator()
pipeline.rx.loadImage(with: imageUrl)
.trackActivity(isBusy)
.subscribe(onNext: { imageView.image = $0.image })
.disposed(by: disposeBag)
isBusy.asDriver()
.drive(activityIndicator.rx.isAnimating)
.disposed(by: disposeBag)
在表格或集合视图中
以下是您如何将前例中提供的代码集成到表格或集合视图中。
final class ImageCell: UICollectionViewCell {
private var imageView: UIImageView!
private var disposeBag = DisposeBag()
// <.. create an image view using your preferred way ..>
func display(_ image: Single<ImageResponse>) {
// Create a new dispose bag, previous dispose bag gets deallocated
// and cancels all previous subscriptions.
disposeBag = DisposeBag()
imageView.image = nil
// Load an image and display the result on success.
image.subscribe(onSuccess: { [weak self] response in
self?.imageView.image = response.image
}).disposed(by: disposeBag)
}
}
需求
RxNuke | Swift | Xcode | 平台 |
---|---|---|---|
RxNuke 1.0 | Swift 5.1 | Xcode 11.0 | iOS 11.0 / watchOS 4.0 / macOS 10.13 / tvOS 11.0 |
RxNuke 0.8 | Swift 4.2 – 5.0 | Xcode 10.1 – 10.2 | iOS 10.0 / watchOS 3.0 / macOS 10.12 / tvOS 10.0 |
RxNuke 0.7 | Swift 4.0 – 4.2 | Xcode 9.2 – 10.1 | iOS 9.0 / watchOS 2.0 / macOS 10.10 / tvOS 9.0 |
许可证
RxNuke 在 MIT 许可证下可用。有关更多信息,请参阅 LICENSE 文件。