A partir de iOS13, se puede monitorear el progreso de OperationQueue usando la propiedad progress . La documentación establece que solo las operaciones que no anulan start() cuentan cuando se realiza un seguimiento del progreso. Sin embargo, las operaciones asincrónicas deben anular start() y no llamar a super() según la documentación.
¿Significa esto que las operaciones asynchronous y progress son mutuamente excluyentes (es decir, solo las operaciones sincrónicas se pueden usar con el progreso)? Esto parece una gran limitación si este es el caso.
En mi propio proyecto, eliminé mi anulación de start() y todo parece funcionar bien (por ejemplo, las dependencias solo se inician cuando isFinished se establece en true en la operación dependiente internamente en mi clase base de operación asíncrona). PERO, esto parece arriesgado ya que Operation establece explícitamente anular start() .
¿Pensamientos?
Referencias de documentación:
https://developer.apple.com/documentation/foundation/operationqueue/3172535-progress
De manera predeterminada, OperationQueue no informa sobre el progreso hasta que se establece totalUnitCount. Cuando se establece totalUnitCount, la cola comienza a informar sobre el progreso. Cada operación en la cola contribuye con una unidad de finalización al progreso general de la cola para las operaciones que finalizan al final de main(). Las operaciones que anulan start() y no invocan super no contribuyen al progreso de la cola.
https://developer.apple.com/documentation/foundation/operation/1416837-start
Si está implementando una operación simultánea, debe anular este método y usarlo para iniciar su operación. Su implementación personalizada no debe llamar a super en ningún momento. Además de configurar el entorno de ejecución para su tarea, su implementación de este método también debe realizar un seguimiento del estado de la operación y proporcionar las transiciones de estado adecuadas.
Actualización: terminé abandonando mi AysncOperation por una simple SyncOperation que espera hasta que se llama a finish() (usando un semáforo).
/// A synchronous operation that automatically waits until `finish()` is called. open class SyncOperation: Operation { private let waiter = DispatchSemaphore(value: 0) /// Calls `work()` and waits until `finish()` is called. public final override func main() { work() waiter.wait() } /// The work of the operation. Subclasses must override this function and call `finish()` when their work is done. open func work() { preconditionFailure("Subclasses must override `work()` and call `finish()`") } /// Finishes the operation. /// /// The work of the operation must be completed when called. Failing to call `finish()` is a programmer error. final public func finish() { waiter.signal() } }Estás combinando dos conceptos diferentes pero relacionados; asíncrono y concurrencia.
Una OperationQueue siempre envía Operations a un subproceso separado, por lo que no es necesario que las haga explícitamente asincrónicas y no es necesario anular start() . Debe asegurarse de que su main() no regrese hasta que se complete la operación. Esto significa bloquear si realiza tareas asincrónicas, como operaciones de red.
Es posible ejecutar una Operation directamente. En el caso de que desee la ejecución simultánea de esas operaciones, debe hacerlas asincrónicas. Es en esta situación en la que anularía start()
Si desea implementar una operación simultánea, es decir, una que se ejecute de forma asíncrona con respecto al subproceso de llamada, debe escribir código adicional para iniciar la operación de forma asíncrona. Por ejemplo, puede generar un subproceso separado, llamar a una función de sistema asincrónico o hacer cualquier otra cosa para asegurarse de que el método de inicio inicie la tarea y regrese inmediatamente y, con toda probabilidad, antes de que finalice la tarea.
La mayoría de los desarrolladores nunca deberían necesitar implementar objetos de operaciones concurrentes. Si siempre agrega sus operaciones a una cola de operaciones, no necesita implementar operaciones simultáneas. Cuando envía una operación no concurrente a una cola de operaciones, la propia cola crea un subproceso en el que ejecutar su operación. Por lo tanto, agregar una operación no concurrente a una cola de operaciones aún da como resultado la ejecución asincrónica de su código de objeto de operación. La capacidad de definir operaciones simultáneas solo es necesaria en los casos en que necesita ejecutar la operación de forma asincrónica sin agregarla a una cola de operaciones.
En resumen, asegúrese de que sus operaciones estén sincronizadas y no anule el start si desea aprovechar progress .
Actualizar
Si bien el consejo normal es no intentar hacer síncronas las tareas asincrónicas, en este caso es lo único que puedes hacer si quieres aprovechar progress . El problema es que si tiene una operación asíncrona, la cola no puede saber cuándo está realmente completa. Si la cola no puede saber cuándo se completa una operación, entonces no puede actualizar progress con precisión para esa operación.
Debe considerar el impacto en el grupo de subprocesos de hacer esto.
La alternativa es no utilizar la función progress incorporada y crear su propia propiedad que actualice desde sus tareas.