IOS Rxswift 使用 Kingfisher 预取 cell Image

Posted

技术标签:

【中文标题】IOS Rxswift 使用 Kingfisher 预取 cell Image【英文标题】:IOS Rxswift use Kingfisher to prefetch cell Image 【发布时间】:2018-10-14 13:34:47 【问题描述】:

我正在尝试在 Rxswift 项目中实现 Kingfisher 预取功能。问题在于这两个功能

collectionView.rx.prefetchItems
collectionView.rx.cancelPrefetchingForItems

Kingfishergithub 的指令很短

override func viewDidLoad() 
    super.viewDidLoad()
    collectionView?.prefetchDataSource = self


extension ViewController: UICollectionViewDataSourcePrefetching 
    func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) 
        let urls = indexPaths.flatMap  URL(string: $0.urlString) 
        ImagePrefetcher(urls: urls).start()
    

我们如何使用 Rxswift 实现?无论如何要从indexpath 的数组中获取models,然后是modelsurls。谢谢。

【问题讨论】:

【参考方案1】:

我将引导您了解我是如何找出解决方案的,以帮助您找出未来的解决方案...

我假设保存 URL 字符串的结构称为Item,并且您有一个当前用于加载集合视图的Observable<[Item]>。我还假设您的收藏中只有一个部分。

首先,我们知道当prefetchItemsAt 发送一个事件时需要发生一些事情,所以我们从那个开始:

let foo = collectionView.rx.prefetchItems

现在检查foo 的类型,看看它是ControlEvent<[IndexPath]>。 ControlEvent 是一种可观察的。我们只需要 IndexPaths 的items 部分,所以让map 这样做:

let foo = collectionView.rx.prefetchItems
    .map  $0.map  $0.item  

(双重映射是 Swift 不支持更高种类类型的不幸结果)现在检查 foo 的类型。它是一个可观察的整数数组。这些整数是我们项目数组的索引。所以我们需要访问最近发出的项目:

    (as above)
    .withLatestFrom(items)  indexes, elements in
        indexes.map  elements[$0] 
    

所以withLatestFrom 就像combineLatest 一样,只是它只在主要可观察对象发出值时触发,而不是在次要可观察对象发出值时触发。

现在,检查foo 的类型会发现它是一个Observable 数组。我们要发送到 ImagePrefetcher 的确切项目的 url。所以我们需要将 urlStrings 提取到 URLs 中。

    (as above)
    .map  $0.compactMap  URL(string: $0.urlString)  

这样,我们就有了希望 ImagePrefetcher 使用的 URL 数组。由于它消耗数据,因此需要将其包装在订阅块中。

    (as above)
    .subscribe(onNext: 
        ImagePrefetcher(urls: $0).start()
    )

此时,foo 是一次性的,因此只需将其收集到我们的 dispose 袋中...这是整个代码块。

collectionView.rx.prefetchItems
    .map  $0.map  $0.item  
    .withLatestFrom(items)  indexes, elements in
        indexes.map  elements[$0] 
    
    .map  $0.compactMap  URL(string: $0.urlString)  
    .subscribe(onNext: 
        ImagePrefetcher(urls: $0).start()
    )
    .disposed(by: bag)

最后一点让一切都变得干净......prefetchItemssubscribe 之间的所有内容都可以移动到 ViewModel 中(如果有的话)。

这里的关键点是您可以使用类型来指导您,并且您需要知道可用于操作 Observables 的运算符,您可以在 http://reactivex.io/documentation/operators.html 找到这些运算符

【讨论】:

首先。感谢您的详细解释。我设法按照您的指示进行操作。但是我们如何测试我们的实现是否真的有效呢? 将代码移动到视图模型后,您可以通过将值发送到输入并检查输出发出的值来对其进行测试。 我们是否需要 confrom 并将我们的视图控制器委托给 UICollectionViewDataSourcePrefetching ?我在订阅结束时设置了断点,但似乎从未被调用(顺便说一句,我应该在第一张地图之前更改为驱动程序吗?) 不,不要设置预取委托,也不要为 collectionView 的委托分配任何东西。 Rx 负责所有这些。如果您想使用 Driver,请在订阅前的最后一刻更改为它。 我在这里实现了完整的代码:pastebin.com/berJnTdL。但似乎没有迹象表明它工作(打印语句从不执行)。代码放在 viewdidload()

以上是关于IOS Rxswift 使用 Kingfisher 预取 cell Image的主要内容,如果未能解决你的问题,请参考以下文章

Swift高仿iOS网易云音乐Moya+RxSwift+Kingfisher+MVC+MVVM

Swift高仿iOS网易云音乐Moya+RxSwift+Kingfisher+MVC+MVVM

iOS的常用类库

加载图像时使用 iOS 中的 Kingfisher 库进行图像优化?

使用 RxSwift 的 UICollectionView 数据绑定 - iOS

iOS RxSwift - 如何使用 Amb 运算符?