IOS Rxswift use Kingfisher to prefetch cell Image

99封情书 提交于 2019-12-08 07:26:33

I will walk you thru how I figured out the solution to help you figure out future solutions...

I'm assuming that the struct that holds the URL strings is called Item and that you have an Observable<[Item]> that you are currently using to load up the collection view. I'm also assuming that you only have one section in your collection.

First, we know that something needs to happen when the prefetchItemsAt sends an event so we start with that:

let foo = collectionView.rx.prefetchItems

Now inspect the type of foo to see that it is a ControlEvent<[IndexPath]>. A ControlEvent is a kind of observable. We just need the items part of the IndexPaths, so lets map that:

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

(The double map is an unfortunate consequence of Swift not supporting higher kinded types) Now inspect the type of foo. It is an Observable array of ints. Those ints are indexes into our items array. So we need access to the most recently emitted items:

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

So withLatestFrom is like combineLatest except it only fires when the primary observable emits a value, not when the secondary observable does.

Now, inspecting the type of foo will find that it's an Observable array of Items. The exact items who's urls' we want to send to the ImagePrefetcher. So we need to extract the urlStrings into URLs.

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

And with that, we have the array of URLs we want ImagePrefetcher to consume. Since it consumes data, it needs to be wrapped it in a subscribe block.

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

At this point, foo is a disposable so it just needs to be collected in our dispose bag... Here is the entire block of code.

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)

One last bit to make everything clean... Everything between prefetchItems and the subscribe can be moved into the ViewModel if you have one.

The key takeaway here is that you can use the types to guide you, and you need to know what operators are available to manipulate Observables which you can find at http://reactivex.io/documentation/operators.html

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!