Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

A collection of handy classes, extensions and global functions to handle being in the background using Swift.

License

NotificationsYou must be signed in to change notification settings

BellAppLab/Backgroundable

Repository files navigation

PlatformsSwift supportCocoaPods CompatibleCarthage compatibleSwift Package Manager compatibleTwitter

Backgroundable

Backgroundable is a collection of handy classes, extensions and global functions to handle being in the background using Swift.

It's main focus is to add functionalities to existingOperations andOperationQueues, without adding overheads to the runtime (aka it's fast) nor to the developer (aka there's very little to learn).

It's powerful because it's simple.

Specs

  • iOS 10+
  • tvOS 10+
  • macOS 10.12+
  • Swift 4.2+
  • Objective-C ready

Executing Code in the Background

Transform this:

letqueue=OperationQueue()varbgTaskId= UIBackgroundTaskInvalidbgTaskId=UIApplication.shared.beginBackgroundTask{()->Voidin    bgTaskId= UIBackgroundTaskInvalid}queue.addOperation(BlockOperation(block:{()->Voidin    //do something in the backgroundUIApplication.shared.endBackgroundTask(bgTaskId)}))

Into this:

inTheBackground{    //move to the background and get on with your life}

Operation Queues

Backgroundable exposes a nifty way to enqueue several operations that should be executed sequentially:

varsequentialOperations=[Operation]()sequentialOperations.append(AsyncOperation({(op)inprint("Executing sequential operation 1")    op.finish()}))sequentialOperations.append(BlockOperation({print("Executing sequential operation 2")    //The sequential operations work with any Operation objects, not just AsyncOperations}))sequentialOperations.append(BlockOperation({(op)inprint("Executing sequential operation 3")    op.finish()}))OperationQueue.background.addSequentialOperations(sequentialOperations, waitUntilFinished:false)

Background Queue

Backgroundable also provides a global background operation queue (similar to the existingOperationQueue.main):

OperationQueue.background.addOperation{    //do something}

This background queue is an instance of theBackgroundQueue 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.

Sequential operations are guaranteed to be executed one after the other.

Background Queue Delegate

TheBackgroundQueue class accepts aBackgroundQueueDelegate, which is notified whenever the queuebackgroundQueueWillStartOperations(_:) and whenbackgroundQueueDidFinishOperations(_:).

This 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!

Asyncronous Operations

AnAsyncOperation is an easy way to perform asynchronous tasks in anOperationQueue. 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, theAsyncOperation is removed from the queue.

Say we have an asynchronous function we'd like to execute in the background:

self.loadThingsFromTheInternet(callback:{(result, error)in    //process the result})

If we wrapped this in anOperation object, we would have one small problem:

operationQueue.addOperation(BlockOperation({[weak self]in    //We're on a background thread now; NICE!self?.loadThingsFromTheInternet(callback:{(result, error)in        //process the result        //who knows in which thread this function returns...})    //Aaaand... As soon as we call the load function, the operation will already be finished and removed from the queue    //But we haven't finished what we wanted to do!    //And the queue will now start executing its next operation!    //Sigh...}))

TheAsyncOperation class solves this issue by exposing the operation object itself to its execution block and only changing itsisFinished property once everything is done:

operationQueue.addOperation(AsyncOperation({[weak self](op)in    //We're on a background thread now; NICE!self?.loadThingsFromTheInternet(callback:{(result, error)in        //process the result        //then move to the main threadonTheMainThread{            //go to the backgroundinTheBackground{                //do more stuff                 //once everything is done, finish                op.finish()                //only now the queue will start working on the next thing}}})}))

Nice, huh?

Timeouts

There's no way for anAsyncOperation to know when it's done (hence, we need to callop.finish() when its work is done). But sometimes, we developers - ahem - forget things.

Thus, in order to cover for the case whereop.finish() may never be called (consequently blocking theOperationQueue),AsyncOperations come with a timeout (defaulting to 10 seconds). After the timeout elapses, the operation is automaticallt finished and removed from the queue.

It may be the case that yourAsyncOperation's workload takes longer than the default timeout. If that's the case, you can define a new timeout like this:

AsyncOperation(timeout:20,{(op)in    //perform very long task    op.finish()})

Optionally, you can set theonTimeoutCallback: when instantiating a newAsyncOperation to be notified when your operations times out.

Cancelations

As perApple's documentation, 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:

AsyncOperation({(op)in     //do some workguard !op.isCancelledelse{return} //No need to call finish() in this case        //do some more work})

Uniqueness Policy

The uniqueness policy dictates whetherAsyncOperations with the samename should co-exist in aBackgroundQueue. This is great for deduplicating operations, for example:

@IBActionfunc refresh(_ sender:UIRefreshControl){letop=AsyncOperation(name:"Call to API endpoint /xyz", uniquenessPolicy:.drop){ opin        //make the call to the API        op.finish()}OperationQueue.background.addOperation(op)}

This 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.

Neat!

Installation

Cocoapods

pod'Backgroundable','~> 1.4'

Thenimport Backgroundable where needed.

Carthage

github"BellAppLab/Backgroundable"~>1.4

Thenimport Backgroundable where needed.

Swift Package Manager

dependencies:[.package(url:"https://github.com/BellAppLab/Backgroundable", from:"1.4")]

Thenimport Backgroundable where needed.

Git Submodules

cd toYourProjectsFoldergit submodule add -b submodule --name Backgroundable https://github.com/BellAppLab/Backgroundable.git

Then drag theBackgroundable folder into your Xcode project.

Author

Bell App Lab,apps@bellapplab.com

Credits

Logo image byBecris fromThe Noun Project

License

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


[8]ページ先頭

©2009-2025 Movatter.jp