我认为你的情况是一个很好的例子。我用 ReactiveKit 整理了一个简单的例子,你可以看看。反应套件非常简单,对于这种情况来说绰绰有余。您也可以使用任何其他反应式库。我希望它有所帮助。
ReactiveKit:https://github.com/DeclarativeHub/ReactiveKit
邦德:https://github.com/DeclarativeHub/Bond
安装 reactiveKit 依赖后,您可以在工作区中运行以下代码:
import UIKit
import Bond
import ReactiveKit
class ViewController: UIViewController {
var jobHandler : JobHandler!
var jobs = [Job(name: "One", state: nil), Job(name: "Two", state: nil), Job(name: "Three", state: nil), Job(name: "Four", state: nil), Job(name: "Five", state: nil)]
override func viewDidLoad() {
super.viewDidLoad()
self.jobHandler = JobHandler()
self.run()
}
func run() {
// Initialize jobs with queue state
_ = self.jobs.map({$0.state.value = .queue})
self.jobHandler.jobs.insert(contentsOf: jobs, at: 0)
self.jobHandler.queueJobs(limit: 2) // Limit of how many jobs you can start with
}
}
// Job state, I added a few states just as test cases, change as required
public enum State {
case queue, running, completed, fail
}
class Job : Equatable {
// Initialize state as a Reactive property
var state = Property<State?>(nil)
var name : String!
init(name: String, state: State?) {
self.state.value = state
self.name = name
}
// This runs the current job
typealias jobCompletion = (State) -> Void
func runJob (completion: @escaping jobCompletion) {
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.state.value = .completed
completion(self.state.value ?? .fail)
return
}
self.state.value = .running
completion(.running)
}
// To find the index of current job
static func == (lhs: Job, rhs: Job) -> Bool {
return lhs.name == rhs.name
}
}
class JobHandler {
// The array of jobs in an observable form, so you can see event on the collection
var jobs = MutableObservableArray<Job>([])
// Completed jobs, you can add failed jobs as well so you can queue them again
var completedJobs = [Job]()
func queueJobs (limit: Int) {
// Observe the events in the datasource
_ = self.jobs.observeNext { (collection) in
let jobsToRun = collection.collection.filter({$0.state.value == .queue})
self.startJob(jobs: Array(jobsToRun.prefix(limit)))
}.dispose()
}
func startJob (jobs: [Job?]) {
// Starts a job thrown by the datasource event
jobs.forEach { (job) in
guard let job = job else { return }
job.runJob { (state) in
switch state {
case .completed:
if !self.jobs.collection.isEmpty {
guard let index = self.jobs.collection.indexes(ofItemsEqualTo: job).first else { return }
print("Completed " + job.name)
self.jobs.remove(at: index)
self.completedJobs.append(job)
self.queueJobs(limit: 1)
}
case .queue:
print("Queue")
case .running:
print("Running " + job.name)
case .fail:
print("Fail")
}
}
}
}
}
extension Array where Element: Equatable {
func indexes(ofItemsEqualTo item: Element) -> [Int] {
return enumerated().compactMap { $0.element == item ? $0.offset : nil }
}
}