异步块 (Async Block)

并发运行大量异步操作可能导致线程爆炸,并经常导致崩溃。最好限制活动操作的数量,以便并发队列不会在其他线程等待时创建额外的线程。使用带有maxConcurrentOperationCountOperationQueue将限制操作的数量。Apple的BlockOperation不会异步运行,而此实现会异步运行,并且isAsynchronous设置为 true。

操作队列 (Operation Queues)

自从 iOS 2.0 首次向开发者提供 SDK 时,Apple 就包含了 OperationQueue。它早于 iOS 4.0 中包含的 Dispatch (即 Grand Central Dispatch)。它添加了更多并发功能,以取代经典的线程编程技术,目标是调整为平台编写的代码,以便运行时队列可以处理 Apple 在未来几年内从 2 核增加到更多核心的工作。 使用带有 OperationQueueOperation 仍然有很多优点。 一个关键的优势是设置 maxConcurrentOperationCount 来限制并发任务的数量。 使用 Dispatch,要么工作以串行方式运行(一次一个),要么并发运行且没有限制。

一个 Operation 可以具有依赖关系,这些依赖关系是其他操作。 可以根据需要设置一系列操作以支持正在完成的工作,并在设置了最大值的 OperationQueue 上运行它。

Combine

Apple 在 iOS 13.0 和所有其他 Apple 平台上推出了 Combine。 它支持发布者 (Publishers) 和订阅者 (Subscribers),它们可以使用一种称为反压 (back pressure) 的技术动态控制正在完成的工作量。 不是具有固定限制,而是可以在处理运行时更改 Demand

状态转换 (State Transitions)

运行异步操作需要管理状态转换。 操作有 4 种状态:就绪 (ready)、执行中 (executing)、已完成 (finished) 和已取消 (cancelled)。 状态的更改通过 KVO 报告,这是一种非常有效的机制。异步与同步操作涵盖了如何处理这些状态转换。

但是,如果您手动执行操作,您可能希望将操作对象定义为异步的。 定义异步操作需要更多的工作,因为您必须监视任务的持续状态并使用 KVO 通知报告该状态的更改。 但是,在您希望确保手动执行的操作不会阻塞调用线程的情况下,定义异步操作非常有用。

在此代码中,KVO 更改由 transition(to:) 函数处理,同时可以提供一个闭包,该闭包将被赋予一个 done 闭包。 一旦完成异步工作,就应该使用该闭包。 它将触发状态转换为 .finished,以便 OperationQueue 知道该操作已完成,并且可以启动另一个操作。 除了限制并发操作的数量之外,这种机制还允许随时将操作添加到队列中。

每个状态转换都涉及 2 个状态,它们由计算属性表示。 当操作开始时,isReadyisExecuting 都会发生变化。 稍后,当调用 done() 闭包时,isExecutingisFinished 会发生变化,因此 transition(to:) 函数会为 newStatestate 调用 willChangeValuedidChangeValue。 OperationQueue 可以观察到这些变化并立即做出反应,因为 KVO 非常有效。

Start 和 Main 函数

对于异步操作,只覆盖了 start 函数,而没有覆盖 main 函数,正如文档中所述。 异步工作将在 start 函数中启动,并在完成后将状态转换为已完成。

取消 (Cancellation)

就像 cancel 函数DispatchWorkItem 上一样,在操作上调用 cancel 函数不会停止已启动的操作。 如果已排队的操作在启动之前被取消,它将阻止该操作启动。

取消会导致将来尝试执行工作项的操作立即返回。 取消不会影响已经开始执行的工作项的执行。