Bolts is a collection of low-level libraries designed to make developing mobile apps easier.

Related tags

EventBus Bolts-Swift
Overview

Bolts in Swift

Platforms Swift Version License

Podspec Carthage compatible Swift Package Manager compatible

Build Status Coverage Status

Bolts is a collection of low-level libraries designed to make developing mobile apps easier. Bolts was designed by Parse and Facebook for our own internal use, and we have decided to open source these libraries to make them available to others.

Tasks

Bolts Tasks is a complete implementation of futures/promises for iOS/OS X/watchOS/tvOS and any platform that supports Swift. A task represents the result of an asynchronous operation, which typically would be returned from a function. In addition to being able to have different states completed/faulted/cancelled they provide these benefits:

  • Tasks consume fewer system resources, since they don't occupy a thread while waiting on other Tasks.
  • Tasks could be performed/chained in a row which will not create nested "pyramid" code as you would get when using only callbacks.
  • Tasks are fully composable, allowing you to perform branching, parallelism, and complex error handling, without the spaghetti code of having many named callbacks.
  • Tasks allow you to arrange code in the order that it executes, rather than having to split your logic across scattered callback functions.
  • Tasks don't depend on any particular threading model. So you can use concepts like operation queues/dispatch queues or even thread executors.
  • Tasks could be used synchronously or asynchronously, providing the same benefit of different results of any function/operation.

Getting Started

Add the following line to your Podfile:

pod 'Bolts-Swift'

Run pod install, and you should now have the latest parse release.

Add the following line to your Cartfile:

github "BoltsFramework/Bolts-Swift"

Run carthage update, and you should now have the latest version of Bolts in your Carthage folder.

  • Using Bolts as a sub-project

    You can also include Bolts as a subproject inside of your application if you'd prefer, although we do not recommend this, as it will increase your indexing time significantly. To do so, just drag and drop the BoltsSwift.xcodeproj file into your workspace.

  • Import Bolts

    Now that you have the framework linked to your application - add the folowing line in every .swift that you want to use Bolts from:

    import BoltsSwift
    

Chaining Tasks

There are special methods you can call on a task which accept a closure argument and will return the task object. Because they return tasks it means you can keep calling these methods – also known as chaining – to perform logic in stages. This is a powerful approach that makes your code read as a sequence of steps, while harnessing the power of asynchronous execution. Here are 3 key functions you should know:

  1. Use continueWith to inspect the task after it has ran and perform more operations with the result
  2. Use continueWithTask to add more work based on the result of the previous task
  3. Use continueOnSuccessWith to perform logic only when task executed without errors

For full list of available methods please see source code at Task+ContinueWith.swift

continueWith

Every Task has a function named continueWith, which takes a continuation closure. A continuation will be executed when the task is complete. You can the inspect the task to check if it was successful and to get its result.

save(object).continueWith { task in
  if task.cancelled {
    // Save was cancelled
  } else if task.faulted {
    // Save failed
  } else {
    // Object was successfully saved
    let result = task.result
  }
}

continueOnSuccessWith

In many cases, you only want to do more work if the previous task was successful, and propagate any error or cancellation to be dealt with later. To do this, use continueOnSuccessWith function:

save(object).continueOnSuccessWith { result in
  // Closure receives the result of a succesfully performed task
  // If result is invalid throw an error which will mark task as faulted
}

Underneath, continueOnSuccessWith is calling continueOnSuccessWithTask method which is more powerful and useful for situations where you want to spawn additional work.

continueOnSuccessWithTask

As you saw above, if you return an object from continueWith function – it will become a result the Task. But what if there is more work to do? If you want to call into more tasks and return their results instead – you can use continueWithTask. This gives you an ability to chain more asynchronous work together.

In the following example we want to fetch a user profile, then fetch a profile image, and if any of these operations failed - we still want to display an placeholder image:

fetchProfile(user).continueOnSuccessWithTask { task in
  return fetchProfileImage(task.result);
}.continueWith { task in
  if let image = task.result {
    return image
  }
  return ProfileImagePlaceholder()
}

Creating Tasks

To create a task - you would need a TaskCompletionSource, which is a consumer end of any Task, which gives you an ability to control whether the task is completed/faulted or cancelled. After you create a TaskCompletionSource, you need to call setResult()/setError()/cancel() to trigger its continuations and change its state.

func fetch(object: PFObject) -> Task<PFObject> {
  let taskCompletionSource = TaskCompletionSource<PFObject>()
  object.fetchInBackgroundWithBlock() { (object: PFObject?, error: NSError?) in
    if let error = error {
      taskCompletionSource.setError(error)
    } else if let object = object {
      taskCompletionSource.setResult(object)
    } else {
      taskCompletionSource.cancel()
    }
  }
  return taskCompletionSource.task
}

Tasks in Parallel

You can also perform several tasks in parallel and chain the result of all of them using whenAll() function.

let query = PFQuery(className: "Comments")
find(query).continueWithTask { task in
  var tasks: [Task<PFObject>] = []
  task.result?.forEach { comment in
    tasks.append(self.deleteComment(comment))
  }
  return Task.whenAll(tasks)
}.continueOnSuccessWith { task in
  // All comments were deleted
}

Task Executors

Both continueWith() and continueWithTask() functions accept an optional executor parameter. It allows you to control how the continuation closure is executed. The default executor will dispatch to global dispatch queue, but you can provide your own executor to schedule work in a specific way. For example, if you want to continue with work on the main thread:

fetch(object).continueWith(Executor.mainThread) { task in
  // This closure will be executor on the main application's thread
}

How Do I Contribute?

We want to make contributing to this project as easy and transparent as possible. Please refer to the Contribution Guidelines.

Comments
  • Xcode 9 -

    Xcode 9 - "Task" error

    I just upgraded Xcode, now with Swift 4 and an error has occurred at the Task swift file! See picture below:

    screenshot at sep 23 15-09-58

    It seems the success case needs an argument... Have in mind I already have upgraded the SDK with cocoapods.

    Thanks in advance!

    opened by Samigos 13
  • Conversion to Swift 5

    Conversion to Swift 5

    • All the content from @bpisano-luna PR
    • Remove the added SWIFT_VERSION build setting in project file
    • Run Swift 5 tests on Xcode 10.2
    • Change swift_version in podspec
    CLA Signed 
    opened by antoinelamy 6
  • Add support cancellation token for Task

    Add support cancellation token for Task

    Hi team,

    First of all, thank you for your great work. I've used Bolts-ObjC and now migrating to BoltsSwift, I used BFCancellationToken on the old project, so I've tried to implement the CancellationToken for this Swift version. Please help to review it and suggest me to fix or improve it. This is the first time I create the Pull Request. So please patient if I missed somethings.

    Thanks

    CLA Signed 
    opened by pddkhanh 5
  • Use of undeclared type 'Task'

    Use of undeclared type 'Task'

    I have used Bolts with Objective-C before but when I installed this (through Cocoapods) I can't seem to use them.

    I'm trying to create a Task of my own but when I use the code from the README...

    func doSomethingAsync() -> Task<PFObject> {
    }
    

    I just get the error "Use of undeclared type 'Task'"

    I don't think the README is correct as PFObject is not found in the entire project.

    I can't seem to find an import that works.

    Am I doing something wrong?

    question 
    opened by oliverfoggin 5
  • [TravisCI] fix it, test with Swift 4.0 and 4.2 (5.0 prepared)

    [TravisCI] fix it, test with Swift 4.0 and 4.2 (5.0 prepared)

    Motivation

    I see that a lot of PRs are not accepted because of red Travis CI builds. This leads to three open Swift 5.0 upgrade PRs.

    Description

    This PR makes all travis matrix builds green. Furthermore it makes it possible to test this project with a range of Swift versions.

    Configured matrix:

    | SDK | SWIFT_VERSION | Xcode | | --- | --- | --- | | ios | 4.0 | 9.0| |ios|4.2|10.0| |ios|5.0|10.2 (commented out because the project is not buildable with Swift 5.0 yet)| |macos|4.0|9.0| |appletv|5.0|9.0|

    CLA Signed 
    opened by HeEAaD 4
  • Swift 4 Updates with Explicit Tuple Parameters

    Swift 4 Updates with Explicit Tuple Parameters

    What

    • Updates compile error for non-implicit tuple parameter for an empty task with a success state.
    • Resolves empty parameter deprecated warnings for Task execution class methods.

    Why

    • To conform to the Swift 4 evolution of using explicit tuples described here
    CLA Signed 
    opened by akwilliamson 4
  • Conversion for Swift 5

    Conversion for Swift 5

    Ready for Swift 5 :

    • Removed empty parameter in enum TaskState
    • Updated project setting for base localization
    • Removed warning in print by casting Void value to String
    CLA Signed 
    opened by bpisano-luna 3
  • Bolts Swift macOS Compiler Error in Xcode 10

    Bolts Swift macOS Compiler Error in Xcode 10

    I just installed Parse via Cocoapods on Xcode 10. I'm using this Podfile:

    def shared
      use_frameworks!
      pod 'Parse'
      pod 'ParseLiveQuery'  
    end
    
    target 'MyApp Mac' do
      shared
    end
    
    target 'MyApp iOS' do
      shared
    end
    

    ...and my Mac app files to compile with the error:

    Missing argument for parameter #1 in call - Task.swift

    Screenshot: error

    I've tried deleting /DerivedData, cleaning the build folder, removing Podfile caches and reinstalling, and restarting Xcode.

    Any ideas of what else I can try?

    opened by cliftonlabrum 3
  • Swift 4.0 Support

    Swift 4.0 Support

    Includes all the changes required to support Swift 4.0 Also cleans up tests, since it's finally possible with Swift 4.

    Superseds and closes #62 Fixes #59 Fixes #61

    enhancement CLA Signed 
    opened by nlutsenko 3
  • Chaining tasks of different types

    Chaining tasks of different types

    I have tried all kinds of combinations, but it seems impossible to me to chain several tasks (in series) where the tasks have different result types and whereby each task upon error needs to stop the execution of all subsequent tasks. It's compile time error galore for me.

    I also think the docs are lacking. They don't really show how to chain multiple tasks using the success/error handlers. The paragraph chaining tasks doesn't even show how to acutally chain tasks.

    question 
    opened by ir-fuel 3
  • Deprecated API Usage: UIWebView

    Deprecated API Usage: UIWebView

    Whenever I submit a new build, Apple sends me the following email:

    "ITMS-XXXXX: Deprecated API Usage - Apple will stop accepting submissions of app updates that use UIWebView APIs starting from December 2020. See https://developer.apple.com/documentation/uikit/uiwebview for more information."

    It looks like Bolts uses the UIWebView to parse HTML. I'm not sure if this is even a smart thing to do, especially given the fact that December is coming up soon.

    opened by HackShitUp 2
  • Swift 5.2 Support?

    Swift 5.2 Support?

    Will Bolts be supporting Swift 5.2? With new XCode and Carthage i have error of compiling: Module compiled with Swift 5.0 cannot be imported by the Swift 5.2 compiler

    opened by Rjayone 0
  • How to bring persistence

    How to bring persistence

    How to bring persistence with DB(SQLite or realm etc)?.

    Say like i have a Task in which trying to hit one REST API, before making network call i am killing the App. When i reopen the app i wanted my task to be resumed.

    opened by SureshSc 0
  • How to know which task fails in chain of tasks?

    How to know which task fails in chain of tasks?

    Hi all! Thanks for really helpful lib!

    Can anybody help me?

    I have chain of 3 tasks ( request to BE) . Every task/request can return error with code 401 . But I need to know which task failed , because in case 401 I need to perform different steps depending on which task failed.

    Code sample:

            let verifyTask = interactor.verifySMSCode(verificationID: verification.codeID, code: smsCode)
            verifyTask.continueOnSuccessWithTask { token -> Task<LoginResponse> in
                self.interactor.saveSMSToken(token: token)
                return self.interactor.login(phone: self.user.phoneNumber)
                }.continueOnSuccessWithTask { loginResponse -> Task<UserDetails> in
                    self.interactor.saveAuthData(authData: loginResponse)
                    return self.interactor.requestUserDetails(userID: loginResponse.userID)
                }.continueOnSuccessWith(Executor.mainThread) { [weak self] userDetails in
                    self?.view.hideActivityIndicator()
                    self?.interactor.saveUserDetails(userDetails: userDetails)
                    self?.moduleOutput.didLoginSuccessfuly()
                }.continueOnErrorWith(Executor.mainThread) { [weak self] error in
                    self?.view.hideActivityIndicator()
                    if (error as NSError).code == 401 {
                       // every of 3 requests / task can return me error code == 401 
                       // How can I understand which of previous 3 task failed??? 
                    }
                    self?.view.showError(title: nil, message: error.localizedDescription, buttonTitile: "OK")
            }
    

    Are there any ways to separate which task are failed in continueOnErrorWith block ??

    P.S. I want to use chain of tasks to make code look better. I don't wont to use :

            verifyTask.continueWith { task in
                if let result = task.result {
                    self.interactor.login(phone: user.phoneNumber).continueWith { task in
                        self.interactor.requestUserDetails(userID: result.userID).continueWith {
                            if ///
                        }
                    }
                } else if let err = task.error {
                    //
                }
            }
    
    opened by Igorsnaki 0
  • Enabling local datastore causes constant PFConsistencyAssert

    Enabling local datastore causes constant PFConsistencyAssert

    (Hello!? Anyone home? πŸ‘€)

    I've been using Bolts-Swift for a bit but recently enabled the local datastore in the Parse SDK to be able to pin models locally. Now Bolts-Swift is constantly throwing the following assert:

    PFConsistencyAssert(existing == nil || existing == object,
                               @"Attempted to change an objectId to one that's already known to the OfflineStore.");
    

    I'm not quite sure how to work around this. It seemed when I called TaskCompletionSources asyncly in a DispatchQueue, the complaint went away, but this brought other problems so I'd rather not do that.

    Any ideas what's going on and how to handle?

    Thanks! πŸ€“πŸ‘

    opened by simpleshadow 1
  • Continue block not executing for success case

    Continue block not executing for success case

    In below code, continue block is executing only for failure cases but not for success cases.

    QMServicesManager().authService.signUpAndLogin(with: user).continue({ (users: BFTask!) -> Any? in if users.isFaulted || (users.error != nil) { let alert = UIAlertController(title: "Error!", message: "Some error occurred on server", preferredStyle: UIAlertControllerStyle.alert) alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil)) self.present(alert, animated: true, completion: nil) } else if users.isCancelled { let alert = UIAlertController(title: "Error!", message: "User registration is not completed", preferredStyle: UIAlertControllerStyle.alert) alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil)) self.present(alert, animated: true, completion: nil) } else if users.result != nil { let alert = UIAlertController(title: "Done!", message: "User (users.result!.fullName) registration is successful", preferredStyle: UIAlertControllerStyle.alert) alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil)) self.present(alert, animated: true, completion: nil) } return nil })

    opened by randhirkumarcse 0
Releases(1.5.0)
Owner
Bolts is a collection of low-level libraries designed to make developing mobile apps easier.
null
A dead-simple abstraction over the iOS BackgroundTask API to make background tasks easy to isolate, maintain and schedule

A dead-simple abstraction over the iOS BackgroundTask API to make background tasks easy to isolate, maintain and schedule. Designed to be as lightweight and flexible as possible while tightly integrating with the system APIs. And It's built with Swift Concurrency in mind.

Sam Spencer 31 Dec 11, 2022
Collection of Cosmos series chain

protobuf & gRPC for Cosmos based chains convert .proto files for other languages(java, swift, etc) cosmos default iris native & mode akash ... How to

Cosmostation 2 Sep 13, 2022
Bolts is a collection of low-level libraries designed to make developing mobile apps easier.

Bolts in Swift Bolts is a collection of low-level libraries designed to make developing mobile apps easier. Bolts was designed by Parse and Facebook f

null 1.3k Nov 11, 2022
Blueprints is a collection of flow layouts that is meant to make your life easier when working with collection view flow layouts.

Blueprints is a collection of flow layouts that is meant to make your life easier when working with collection view flow layouts. It comes

Christoffer Winterkvist 982 Dec 7, 2022
This app is a sample app that recognizes specific voice commands such as "make it red", "make it blue", "make it green", and "make it black" and change the background color of the view in the frame.

VoiceOperationSample This app is a sample app that recognizes specific voice commands such as "make it red", "make it blue", "make it green", and "mak

Takuya Aso 3 Dec 3, 2021
SugarRecord is a persistence wrapper designed to make working with persistence solutions like CoreData in a much easier way.

What is SugarRecord? SugarRecord is a persistence wrapper designed to make working with persistence solutions like CoreData in a much easier way. Than

Modo 2.1k Dec 29, 2022
A mobile application project designed for everybody which provides the easiest way to make searchs for public services

A mobile application project designed for everybody which provides the easiest way to make searchs for public services

null 0 Nov 23, 2021
MbientLab 2 Feb 5, 2022
RxAlamoRecord combines the power of the AlamoRecord and RxSwift libraries to create a networking layer that makes interacting with API's easier than ever reactively.

Written in Swift 5 RxAlamoRecord combines the power of the AlamoRecord and RxSwift libraries to create a networking layer that makes interacting with

Dalton Hinterscher 9 Aug 7, 2020
Blueprints - A framework that is meant to make your life easier when working with collection view flow layouts.

Description Blueprints is a collection of flow layouts that is meant to make your life easier when working with collection view flow layouts. It comes

Christoffer Winterkvist 982 Dec 7, 2022
A Collection of useful Swift property wrappers to make coding easier

Swift Property Wrappers A Collection of useful Swift property wrappers to make c

Gordan GlavaΕ‘ 2 Jan 28, 2022
SwiftUI Backports - Introducing a collection of SwiftUI backports to make your iOS development easier

SwiftUI Backports Introducing a collection of SwiftUI backports to make your iOS development easier. Many backports support iOS 13+ but where UIKIt fe

Shaps 530 Dec 28, 2022
Gauntlet is a collection of testing utility methods that aims to make writing great tests easier.

Gauntlet What is Gauntlet? Gauntlet is a collection of testing utility methods that aims to make writing great tests easier and with more helpful and

null 11 Dec 17, 2022
Switchboard - easy and super light weight A/B testing for your mobile iPhone or android app. This mobile A/B testing framework allows you with minimal servers to run large amounts of mobile users.

Switchboard - easy A/B testing for your mobile app What it does Switchboard is a simple way to remote control your mobile application even after you'v

Keepsafe 287 Nov 19, 2022
Movies is a collection of a few UI/UX ideas that came up whilst developing an iOS app

Movies Introduction: Movies is a collection of a few UI/UX ideas that came up whilst developing an iOS app called Wattmo You'll find tableviews, detai

Kevin Mindeguia 861 Nov 19, 2022
ChainPageCollectionView A custom View with two level chained collection views and fancy transition animation

ChainPageCollectionView A custom View with two level chained collection views and fancy transition animation. Demo Requirements iOS 9.0+ Xcode 8 Insta

Yansong Li 775 Dec 7, 2022
Sinatra-like DSL for developing web apps in Swift

Swiftra Swiftra is a library that provides DSLs like Sinatra. System Requirements DEVELOPMENT-SNAPSHOT-2016-02-08-a Example See swiftra-example. impor

Shun Takebayashi 262 Jun 29, 2022
CS193p---Assignments - Assignment Solutions for Stanford CS193p - Developing Apps for iOS

Assignment Solutions for Stanford CS193p - Developing Apps for iOS Note: This is ongoing work Task done Programming Assignment 1 x Programming Assignm

null 0 Jan 12, 2022
A type-safe, high-level networking solution for Swift apps

What Type-safe network calls made easy Netswift offers an easy way to perform network calls in a structured and type-safe way. Why Networking in Swift

Dorian Grolaux 23 Apr 27, 2022
iOS tweak to display toasts for Low Power alerts and charging

Electrode iOS tweak to display toasts for Low Power alerts and charging. Localization Want to help translate Electrode to your language? Sumbit a pull

null 8 Sep 7, 2022