{"id":19252212,"url":"https://github.com/bellapplab/backgroundable","last_synced_at":"2026-03-01T09:32:26.289Z","repository":{"id":36002547,"uuid":"40295303","full_name":"BellAppLab/Backgroundable","owner":"BellAppLab","description":"A collection of handy classes, extensions and global functions to handle being in the background using Swift.","archived":false,"fork":false,"pushed_at":"2020-08-13T12:40:25.000Z","size":297,"stargazers_count":9,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-10-09T19:32:30.894Z","etag":null,"topics":["carthage","cocoapods","enqueue","ios","linux","macos","operation","operationqueue","osx","queue","swift","swift-package-manager","thread","tvos"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BellAppLab.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-08-06T09:02:24.000Z","updated_at":"2025-08-25T16:31:40.000Z","dependencies_parsed_at":"2022-08-21T01:50:53.782Z","dependency_job_id":null,"html_url":"https://github.com/BellAppLab/Backgroundable","commit_stats":null,"previous_names":[],"tags_count":51,"template":false,"template_full_name":null,"purl":"pkg:github/BellAppLab/Backgroundable","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BellAppLab%2FBackgroundable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BellAppLab%2FBackgroundable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BellAppLab%2FBackgroundable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BellAppLab%2FBackgroundable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BellAppLab","download_url":"https://codeload.github.com/BellAppLab/Backgroundable/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BellAppLab%2FBackgroundable/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279001960,"owners_count":26083244,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-09T02:00:07.460Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["carthage","cocoapods","enqueue","ios","linux","macos","operation","operationqueue","osx","queue","swift","swift-package-manager","thread","tvos"],"created_at":"2024-11-09T18:25:52.787Z","updated_at":"2025-10-09T19:33:22.500Z","avatar_url":"https://github.com/BellAppLab.png","language":"Swift","readme":"# Backgroundable [![Version](https://img.shields.io/badge/Version-1.4.1-black.svg?style=flat)](#installation) [![License](https://img.shields.io/cocoapods/l/Backgroundable.svg?style=flat)](#license)\n\n[![Platforms](https://img.shields.io/badge/Platforms-iOS|tvOS|macOS|Linux-brightgreen.svg?style=flat)](#installation)\n[![Swift support](https://img.shields.io/badge/Swift-4.2%20%7C%205.3-red.svg?style=flat)](#swift-versions-support)\n[![CocoaPods Compatible](https://img.shields.io/cocoapods/v/Backgroundable.svg?style=flat\u0026label=CocoaPods)](https://cocoapods.org/pods/Backgroundable)\n[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n[![Swift Package Manager compatible](https://img.shields.io/badge/SPM-compatible-orange.svg?style=flat)](https://github.com/apple/swift-package-manager)\n[![Twitter](https://img.shields.io/badge/Twitter-@BellAppLab-blue.svg?style=flat)](http://twitter.com/BellAppLab)\n\n![Backgroundable](./Images/backgroundable.png)\n\nBackgroundable is a collection of handy classes, extensions and global functions to handle being in the background using Swift.\n\nIt's main focus is to add functionalities to existing `Operation`s and `OperationQueue`s, without adding overheads to the runtime (aka it's fast) nor to the developer (aka there's very little to learn).\n\nIt's powerful because it's simple.\n\n## Specs\n\n* iOS 10+\n* tvOS 10+\n* macOS 10.12+\n* Swift 4.2+\n* Objective-C ready\n\n## Executing Code in the Background\n\nTransform this:\n\n```swift\nlet queue = OperationQueue()\nvar bgTaskId = UIBackgroundTaskInvalid\nbgTaskId = UIApplication.shared.beginBackgroundTask { () -\u003e Void in\n    bgTaskId = UIBackgroundTaskInvalid\n}\nqueue.addOperation(BlockOperation(block: { () -\u003e Void in\n    //do something in the background\n    UIApplication.shared.endBackgroundTask(bgTaskId)\n}))\n```\n    \n**Into this**:\n\n```swift\ninTheBackground {\n    //move to the background and get on with your life\n}\n```\n\n## Operation Queues\n\nBackgroundable exposes a nifty way to enqueue several operations that should be executed sequentially:\n\n```swift\nvar sequentialOperations = [Operation]()\nsequentialOperations.append(AsyncOperation({ (op) in\n    print(\"Executing sequential operation 1\")\n    op.finish()\n}))\nsequentialOperations.append(BlockOperation({ \n    print(\"Executing sequential operation 2\")\n    //The sequential operations work with any Operation objects, not just AsyncOperations\n}))\nsequentialOperations.append(BlockOperation({ (op) in\n    print(\"Executing sequential operation 3\")\n    op.finish()\n}))\nOperationQueue.background.addSequentialOperations(sequentialOperations, waitUntilFinished: false)\n```\n\n### Background Queue\n\nBackgroundable also provides a global background operation queue (similar to the existing `OperationQueue.main`):\n\n```swift\nOperationQueue.background.addOperation {\n    //do something\n}\n```\n\nThis background queue is an instance of the `BackgroundQueue` class, which automatically handles background task identifiers. Whenever an operation is enqueued, a background task identifier is generated and whenever the queue is empty, the queue automatically invalidates it. \n\nSequential operations are guaranteed to be executed one after the other.\n\n### Background Queue Delegate\n\nThe `BackgroundQueue` class accepts a `BackgroundQueueDelegate`, which is notified whenever the queue `backgroundQueueWillStartOperations(_:)` and when `backgroundQueueDidFinishOperations(_:)`. \n\nThis is quite handy if you want to show the network activity indicator or save a database or anything else really. The sky is the limit!\n\n## Asyncronous Operations\n\nAn `AsyncOperation` is an easy way to perform asynchronous tasks in an `OperationQueue`. It's designed to make it easy to perform long-running tasks on an operation queue regardless of how many times its task needs to jump between threads. Only once everything is done, the `AsyncOperation` is removed from the queue. \n\nSay we have an asynchronous function we'd like to execute in the background:\n\n```swift\nself.loadThingsFromTheInternet(callback: { (result, error) in\n    //process the result\n})\n```\n\nIf we wrapped this in an `Operation` object, we would have one small problem:\n\n```swift\noperationQueue.addOperation(BlockOperation({ [weak self] in\n    //We're on a background thread now; NICE!\n    self?.loadThingsFromTheInternet(callback: { (result, error) in\n        //process the result\n        //who knows in which thread this function returns... \n    })\n    //Aaaand... As soon as we call the load function, the operation will already be finished and removed from the queue\n    //But we haven't finished what we wanted to do!\n    //And the queue will now start executing its next operation!\n    //Sigh...\n}))\n```\n\nThe `AsyncOperation` class solves this issue by exposing the operation object itself to its execution block and only changing its `isFinished` property once everything is done:\n\n```swift\noperationQueue.addOperation(AsyncOperation({ [weak self] (op) in\n    //We're on a background thread now; NICE!\n    self?.loadThingsFromTheInternet(callback: { (result, error) in\n        //process the result\n        //then move to the main thread\n        onTheMainThread {\n            //go to the background\n            inTheBackground {\n                //do more stuff \n                //once everything is done, finish\n                op.finish()\n                //only now the queue will start working on the next thing\n            }\n        }\n    })\n}))\n```\n\nNice, huh?\n\n### Timeouts\n\nThere's no way for an `AsyncOperation` to know when it's done (hence, we need to call `op.finish()` when its work is done). But sometimes, we developers - ahem - forget things. \n\nThus, in order to cover for the case where `op.finish()` may never be called (consequently blocking the `OperationQueue`), `AsyncOperation`s come with a timeout (**defaulting to 10 seconds**). After the timeout elapses, the operation is automaticallt finished and removed from the queue. \n\nIt may be the case that your `AsyncOperation`'s workload takes longer than the default timeout. If that's the case, you can define a new timeout like this:\n\n```swift\nAsyncOperation(timeout: 20, { (op) in\n    //perform very long task\n    op.finish()\n})\n```\n\nOptionally, you can set the `onTimeoutCallback:` when instantiating a new `AsyncOperation` to be notified when your operations times out.\n\n### Cancelations\n\nAs per [Apple's documentation](https://developer.apple.com/documentation/foundation/operation/1408418-iscancelled), it's always a good idea to check if your operation has been cancelled during the execution of its closure and shortcircuit it prematurely if needed. For example:\n\n```swift\nAsyncOperation({ (op) in \n    //do some work\n    \n    guard !op.isCancelled else { return } //No need to call finish() in this case\n    \n    //do some more work\n})\n```\n\n### Uniqueness Policy\n\nThe uniqueness policy dictates whether `AsyncOperation`s with the same `name` should co-exist in a `BackgroundQueue`. This is great for deduplicating operations, for example:\n\n```swift\n@IBAction func refresh(_ sender: UIRefreshControl) {\n    let op = AsyncOperation(name: \"Call to API endpoint /xyz\", uniquenessPolicy: .drop) { op in\n        //make the call to the API\n        op.finish()\n    }\n    OperationQueue.background.addOperation(op)\n}\n```\n\nThis first time the user activates the refresh control, the operation will be added to the queue as normal, because there are no other operations with the name `\"Call to API endpoint /xyz\"` there yet. But if the user activates the control again before the first call to the API returns, then the `.drop` policy will make sure that a second operation is not added to the queue, since there's one operation with that name in there already. If `.replace` is set, then the previous operation is cancelled and the new one replaces it. \n\nNeat! \n\n## Installation\n\n### Cocoapods\n\n```ruby\npod 'Backgroundable', '~\u003e 1.4'\n```\n\nThen `import Backgroundable` where needed.\n\n### Carthage\n\n```swift\ngithub \"BellAppLab/Backgroundable\" ~\u003e 1.4\n```\n\nThen `import Backgroundable` where needed.\n\n### Swift Package Manager\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/BellAppLab/Backgroundable\", from: \"1.4\")\n]\n```\n\nThen `import Backgroundable` where needed.\n\n### Git Submodules\n\n```shell\ncd toYourProjectsFolder\ngit submodule add -b submodule --name Backgroundable https://github.com/BellAppLab/Backgroundable.git\n```\n\nThen drag the `Backgroundable` folder into your Xcode project.\n\n## Author\n\nBell App Lab, apps@bellapplab.com\n\n### Credits\n\n[Logo image](https://thenounproject.com/search/?q=flow\u0026i=1469609#) by [Becris](https://thenounproject.com/Becris) from [The Noun Project](https://thenounproject.com/)\n\n## License\n\nBackgroundable is available under the MIT license. See the LICENSE file for more info.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbellapplab%2Fbackgroundable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbellapplab%2Fbackgroundable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbellapplab%2Fbackgroundable/lists"}