• Stars
    star
    148
  • Rank 249,931 (Top 5 %)
  • Language
    Swift
  • License
    MIT License
  • Created over 7 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

RxSwift extensions for Nuke

This repository contains RxSwift extensions for Nuke as well as examples of common use cases solved by Rx.

Usage

RxNuke provides a set of reactive extensions for Nuke:

extension Reactive where Base: ImagePipeline {
    public func loadImage(with url: URL) -> Single<ImageResponse>
    public func loadImage(with request: ImageRequest) -> Single<ImageResponse>
}

A Single is a variation of Observable that, instead of emitting a series of elements, is always guaranteed to emit either a single element or an error. The common use case of Single is to wrap HTTP requests. See Traits for more info. {:.info}

Here's a basic example where we load an image and display the result on success:

ImagePipeline.shared.rx.loadImage(with: url)
    .subscribe(onSuccess: { imageView.image = $0.image })
    .disposed(by: disposeBag)

Going From Low to High Resolution

Let's say you want to show a user a high-resolution image that takes a while it loads. You can show a spinner while the high-resolution image is downloaded, but you can improve the user experience by quickly downloading and displaying a thumbnail.

As an alternative, Nuke also supports progressive JPEG. To learn about it, see a dedicated guide. {:.info}

You can implement it using concat operator. This operator results in a serial execution. It starts a thumbnail request, waits until it finishes, and only then starts a request for a high-resolution image.

Observable.concat(pipeline.rx.loadImage(with: lowResUrl).orEmpty,
                  pipeline.rx.loadImage(with: highResUtl).orEmpty)
    .subscribe(onNext: { imageView.image = $0.image })
    .disposed(by: disposeBag)

orEmpty is a custom property that ignores errors and completes the sequence instead (equivalent to func catchErrorJustComplete() from RxSwiftExt. {:.info}

public extension RxSwift.PrimitiveSequence {
    var orEmpty: Observable<Element> {
        asObservable().catchError { _ in .empty() }
    }
}

Loading the First Available Image

Let's say you have multiple URLs for the same image. For example, you uploaded the image from the camera to the server; you have the image stored locally. When you display this image, it would be beneficial to first load the local URL, and if that fails, try to download from the network.

This use case is very similar to Going From Low to High Resolution, except for the addition of the .take(1) operator that stops the execution when the first value is received.

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)

Load Multiple Images, Display All at Once

Let's say you want to load two icons for a button, one icon for a .normal state, and one for a .selected state. You want to update the button, only when both icons are fully loaded. This can be achieved using a combineLatest operator.

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)

Showing Stale Image While Validating It

Let's say you want to show the user a stale image stored in disk cache (Foundation.URLCache) while you go to the server to validate if the image is still fresh. It can be implemented using the same append operator that we covered previously.

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)

See "Image Caching" to learn more about HTTP cache. {:.info}

Auto Retry

Auto-retry with an exponential backoff of other delay options (including immediate retry when a network connection is re-established) using smart retry.

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)

Tracking Activities

Suppose you want to show an activity indicator while waiting for an image to load. Here's how you can do it using ActivityIndicator class provided by RxSwiftUtilities:

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)

In a Table or Collection View

Here's how you can integrate the code provided in the previous examples into your table or collection view cells:

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)
    }
}

Requirements

RxNuke Swift Xcode Platforms
RxNuke 5.0 Swift 5.6 Xcode 13.3 iOS 13.0 / watchOS 6.0 / macOS 10.15 / tvOS 13.0
RxNuke 4.0 Swift 5.6 Xcode 13.3 iOS 13.0 / watchOS 6.0 / macOS 10.15 / tvOS 13.0
RxNuke 3.0 Swift 5.3 Xcode 12.0 iOS 11.0 / watchOS 4.0 / macOS 10.13 / tvOS 11.0

License

RxNuke is available under the MIT license. See the LICENSE file for more info.

More Repositories

1

Nuke

Image loading system
Swift
8,112
star
2

Pulse

Network logger for Apple platforms
Swift
6,307
star
3

DFImageManager

Image loading, processing, caching and preheating
Objective-C
1,180
star
4

Get

Web API client built using async/await
Swift
941
star
5

Preheat

Automates prefetching of content in UITableView and UICollectionView
Swift
629
star
6

PulsePro

A macOS app for viewing logs from Pulse
Swift
482
star
7

Align

Intuitive and powerful Auto Layout library
Swift
350
star
8

Future

Streamlined Future<Value, Error> implementation
Swift
317
star
9

FetchImage

Makes it easy to download images using Nuke and display them in SwiftUI apps
Swift
212
star
10

Regex

Open source regex engine
Swift
211
star
11

Arranged

Open source replacement of UIStackView for iOS 8 (100% layouts supported)
Swift
208
star
12

VPN

Sample custom VPN client/server in Swift
Swift
182
star
13

Formatting

Swift
179
star
14

DFCache

Composite LRU cache with fast metadata using UNIX extended file attributes
Objective-C
162
star
15

CreateAPI

Delightful code generator for OpenAPI specs
Swift
142
star
16

SwiftSQL

Swift API for SQLite
Swift
131
star
17

ThreeColumnNavigation

A minimal example of three-column navigation for iPad and macOS using SwiftUI
Swift
127
star
18

Stacks

A micro UIStackView convenience API inspired by SwiftUI
Swift
73
star
19

Nuke-FLAnimatedImage-Plugin

FLAnimatedImage plugin for Nuke
Swift
53
star
20

RxUI

Auto-binding for RxSwift inspired by SwiftUI
Swift
45
star
21

Nuke-Alamofire-Plugin

Alamofire plugin for Nuke
Swift
40
star
22

NukeDemo

Nuke Demo
Swift
34
star
23

DFJPEGTurbo

Objective-C libjpeg-turbo wrapper
C
33
star
24

ImagePublisher

Combine publishers for Nuke
Swift
25
star
25

NukeUI

Lazy image loading for Apple platforms: SwiftUI, UIKit, AppKit
Swift
19
star
26

articles

Articles for kean.github.io
19
star
27

URLQueryEncoder

URL query encoder with support for all OpenAPI serialization options
Swift
17
star
28

NukeBuilder

A fun and convenient way to use Nuke
Swift
14
star
29

ScrollViewPrefetcher

Prefetching for SwiftUI
Swift
14
star
30

PulseLogHandler

SwiftLog Extension for Pulse
Swift
12
star
31

HTTPHeaders

Parsing Simple HTTP Headers
Swift
11
star
32

OctoKit

GitHub API client built with Fuse
Swift
8
star
33

PulseApps

Base Pulse macOS and iOS apps and a few demo projects
Swift
7
star
34

kean

1
star