Latest 1.2.0
Homepage https://github.com/ovrchk/TheChain
License MIT
Platforms ios 8.0
Authors

CI Status
Version
License
Platform

TheChain helps you write more clearer and readable async code:

override func viewDidLoad() {
    super.viewDidLoad()

    downloadImageData().onStart {
        print("Downloading started")
    }.onCompletion {
        print("Downloading finished")
    }.then(
        cacheDownloadedData
    ).then(
        readImageFromCache
    ).catch { (error) in
        print("❌ Failed to load image: (error.localizedDescription)")
    }.finally(on: .main) { (image) in
        self.imageView.image = image
    }
}

// MARK: - Async

private func downloadImageData() -> Link<Data> {
    return URLSession.shared.dataTaskLink(with: "https://lorempixel.com/1000/1000/")
}

private func cacheDownloadedData(_ data: Data) -> Link<Void> {
    return Link(on: .global(), {
        let url = try URL.imageDataFileUrl.orThrow(Error.fileUrlIsNil)

        try data.write(to: url)
    })
}

private func readImageFromCache() -> Link<UIImage> {
    return Link(onGlobalQueue: {
        let url = try URL.imageDataFileUrl.orThrow(Error.fileUrlIsNil)

        let data = try Data(contentsOf: url)

        return try UIImage(data: data).orThrow(Error.unableToInitImage)
    })
}

Basic usage

All you need is create new Link object with desired result type, run you async code and pass result or error when async work done.

func asyncMethod() -> Link<String> {
    let link = Link<String>()

    DispatchQueue.global().async {
        //Some async work goes here
        link.finish("Async work result")

        //or
        //link.throw(Error.someError)
    }

    return link
}

func someMethod() {
    asyncMethod().catch { (error) in
        // Handle error
    }.finally { (result) in
        // Handle the String result
    }
}

Chaining

You can create a chain using Links just like this:

func asyncFoo() -> Link<String> {
    ...
}

func asyncBar(_ input: String) -> Link<Double> {
    ...
}

func asyncBaz(_ input: Double) -> Link<Bool> {
    ...
}

asyncFoo().then(asyncBar).then(asyncBaz).catch { (error) in
    // Handle error
}.finally { (result) in
    // Handle the Bool result
}

Extensions

TheChain comes with some handy extensions which helps you write even more compact, boilerplate-free code.

DispatchQueue

func readImageFromCache() -> Link<UIImage> {
    return Link(onGlobalQueue: {
        let url = try URL.imageDataFileUrl.orThrow(Error.fileUrlIsNil)

        let data = try Data(contentsOf: url)

        return try UIImage(data: data).orThrow(Error.unableToInitImage)
    })
}

Instead of:

func readImageFromCache() -> Link<UIImage> {
    let link = Link<UIImage>()

    DispatchQueue.global().async {
        guard let url = URL.imageDataFileUrl else {
            return link.throw(Error.fileUrlIsNil)
        }

        do {
            let data = try Data(contentsOf: url)

            guard let image = UIImage(data: data) else {
                return link.throw(Error.unableToInitImage)
            }

            link.finish(image)
        } catch {
            link.throw(error)
        }
    }

    return link
}

URLSession

func loadPosts() -> Link<[Post]> {
    return URLSession.shared.dataTaskLink(with: "https://jsonplaceholder.typicode.com/posts")
}

Instead of:

func loadPosts() -> Link<[Post]> {
    let link = Link<[Post]>()

    guard let url = URL(string: "https://jsonplaceholder.typicode.com/posts") else {
        return link.throw(Error.unableToInitUrl)
    }

    URLSession.shared.dataTask(with: URLRequest(url: url)) { (data, _, error) in
        if let data = data {
            do {
                let posts = try JSONDecoder().decode([Post].self, from: data)

                link.finish(posts)
            } catch {
                link.throw(error)
            }
        } else if let error = error {
            link.throw(error)
        }
    }.resume()

    return link
}

Installation

TheChain is available through CocoaPods. To install
it, simply add the following line to your Podfile:

pod 'TheChain'

License

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

Latest podspec

{
    "name": "TheChain",
    "version": "1.2.0",
    "summary": "Async Swift tasks chaining",
    "homepage": "https://github.com/ovrchk/TheChain",
    "license": {
        "type": "MIT",
        "file": "LICENSE"
    },
    "authors": {
        "Dmitry": "[email protected]"
    },
    "source": {
        "git": "https://github.com/ovrchk/TheChain.git",
        "tag": "1.2.0"
    },
    "platforms": {
        "ios": "8.0"
    },
    "swift_version": "5.0",
    "source_files": "TheChain/Classes/**/*"
}

Pin It on Pinterest

Share This