Backgroundable 1.4.1

背景处理 1.4.1

测试已测试
Lang语言 SwiftSwift
许可证 MIT
已发布最后发布2020 年 8 月
SPM支持 SPM

Bell App Lab 维护。




Backgroundable 版本 许可证

Platforms Swift support CocoaPods Compatible Carthage compatible Swift Package Manager compatible Twitter

Backgroundable

Backgroundable 是一组方便的类、扩展和全局函数,用于用 Swift 处理后台处理。

它的主要重点是向现有的 OperationOperationQueue 添加功能,而不向运行时(即速度快)或开发者(即学习得很少)添加开销。

它之所以强大,是因为它简单。

规范

  • iOS 10+
  • tvOS 10+
  • macOS 10.12+
  • Swift 4.2+
  • 准备就绪的 Objective-C

在后台执行代码

将此转换为此

let queue = OperationQueue()
var bgTaskId = UIBackgroundTaskInvalid
bgTaskId = UIApplication.shared.beginBackgroundTask { () -> Void in
    bgTaskId = UIBackgroundTaskInvalid
}
queue.addOperation(BlockOperation(block: { () -> Void in
    //do something in the background
    UIApplication.shared.endBackgroundTask(bgTaskId)
}))

变为此:

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

操作队列

Backgroundable提供了一个方便的方法,用于顺序执行多个操作

var sequentialOperations = [Operation]()
sequentialOperations.append(AsyncOperation({ (op) in
    print("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) in
    print("Executing sequential operation 3")
    op.finish()
}))
OperationQueue.background.addSequentialOperations(sequentialOperations, waitUntilFinished: false)

后台队列

Backgroundable还提供了一个全局的后台操作队列(类似于现有OperationQueue.main

OperationQueue.background.addOperation {
    //do something
}

这是一个BackgroundQueue类的实例,它自动处理后台任务标识符。每次将操作入列时,都会生成一个后台任务标识符,当队列空时,队列会自动使其失效。

顺序操作将保证一个接一个执行。

后台队列代理

BackgroundQueue类接受一个BackgroundQueueDelegate,在队列《backgroundQueueWillStartOperations(_:)》和当《backgroundQueueDidFinishOperations(_:)》时通知。

如果你想要显示网络活动指示器或保存数据库或其他某些内容,这非常方便。天空是无限的!

异步操作

AsyncOperation是执行异步任务的一种简单方式,其中在OperationQueue中执行。该类旨在简化在操作队列上执行长时间运行的任务,无论其任务需要在多个线程之间多频繁地跳转。只有当所有事情都完成时,AsyncOperation才会从队列中移除。

假设我们有一个需要在后台执行的非同步函数

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

如果我们把这段代码包装在一个Operation对象中,我们会遇到一个小问题

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

AsyncOperation类通过访求操作对象本身来解决这个问题,并在一切完成后只更改它的isFinished属性

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 thread
        onTheMainThread {
            //go to the background
            inTheBackground {
                //do more stuff 
                //once everything is done, finish
                op.finish()
                //only now the queue will start working on the next thing
            }
        }
    })
}))

非常好,不是吗?

超时

异步操作(AsyncOperation)无法知道何时完成(因此,在其工作完成后需要调用op.finish())。但是,有时开发者——嗯——会忘记这些事情。

因此,为了应对op.finish()可能永远不会被调用(从而阻碍OperationQueue)的情况,AsyncOperation带有超时功能(默认为10秒)。在超时过后,操作将被自动完成并从队列中移除。

可能存在这样的情况,即你的AsyncOperation的工作负载需要比默认超时更长时间。如果发生这种情况,你可以像这样定义一个新的超时:

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

可选地,你可以在创建新的AsyncOperation时设置onTimeoutCallback,以便在操作超时时得到通知。

取消

根据Apple的文档[href="https://developer.apple.com/documentation/foundation/operation/1408418-iscancelled"],在执行闭包的过程中,始终检查操作是否已被取消,并在需要时提前短路是一个好主意。例如

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

唯一性策略

唯一性策略决定了具有相同name的AsyncOperation是否可以在BackgroundQueue中同时存在。这对于去重操作非常有用,例如

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

第一次用户激活刷新控件时,操作将正常添加到队列中,因为没有其他名为“调用API端点/xyz”的操作。但是,如果用户在第一次调用API返回之前再次激活控件,那么.drop策略将确保不再将第二个操作添加到队列中,因为在其中已经有了一个同名的操作。如果设置了.replace,则取消之前的操作,并替换为新操作。

真酷!

安装

Cocoapods

pod 'Backgroundable', '~> 1.4'

然后,在需要的地方导入import Backgroundable

Carthage

github "BellAppLab/Backgroundable" ~> 1.4

然后,在需要的地方导入import Backgroundable

Swift包管理器

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

然后,在需要的地方导入import Backgroundable

Git子模块

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

然后将Backgroundable文件夹拖放到您的Xcode项目。

作者

Bell App Lab,[email protected]

致谢

标志图像Becris 提供,来自 名词项目

许可证

Backgroundable 在 MIT 许可下可用。有关更多信息,请参阅 LICENSE 文件。