ios macos swift nsoperation

ios - Anulaciones de propiedad NSOperation(isExecuting/isFinished)



macos swift (3)

Estoy subclasificando NSOperation en Swift y necesito anular las propiedades isExecuting y isFinished ya que estoy anulando el método de start .

El problema con el que me encuentro es cómo conservar la observación de valores-clave (KVO) y al mismo tiempo ser capaz de anular estas propiedades.

Normalmente, en Obj-C, esto sería bastante fácil de readwrite a readwrite las propiedades como readwrite en la readwrite de la extensión de clase JSONOperation () . Sin embargo, no veo esta misma capacidad en Swift.

Ejemplo:

class JSONOperation : NSOperation, NSURLConnectionDelegate { var executing : Bool { get { return super.executing } set { super.executing } // ERROR: readonly in the superclass } // Starts the asynchronous NSURLConnection on the main thread override func start() { self.willChangeValueForKey("isExecuting") self.executing = true self.didChangeValueForKey("isExecuting") NSOperationQueue.mainQueue().addOperationWithBlock( { self.connection = NSURLConnection(request: self.request, delegate: self, startImmediately: true) }) } }

Así que aquí está la solución que se me ha ocurrido, pero se siente terriblemente fea y falsa:

var state = Operation() struct Operation { var executing = false var finished = false } override var executing : Bool { get { return state.executing } set { state.executing = newValue } } override var finished : Bool { get { return state.finished } set { state.finished = newValue } }

Por favor, dime que hay una mejor manera. Sé que podría hacer una var isExecuting lugar de toda la struct , pero luego tengo dos propiedades con nombres similares que introducen ambigüedad y también hacen que pueda escribirse públicamente (lo que no quiero).

Oh, qué haría para algunas palabras clave modificadoras de acceso ...


Como dijo David, puede implementar tanto un getter como un setter en la anulación de la propiedad de la subclase.

Pero, al definir operaciones asynchronous / concurrent (es decir, aquellas operaciones que se completarán de forma asíncrona), es crítico llamar a will / didChangeValueForKey para isFinished y isExecuting . Si no lo hace, no se liberarán las operaciones, no se maxConcurrentOperationCount dependencias, tendrá problemas en maxConcurrentOperationCount , etc.).

Por lo tanto, yo sugeriría:

private var _executing: Bool = false override var executing: Bool { get { return _executing } set { if _executing != newValue { willChangeValueForKey("isExecuting") _executing = newValue didChangeValueForKey("isExecuting") } } } private var _finished: Bool = false; override var finished: Bool { get { return _finished } set { if _finished != newValue { willChangeValueForKey("isFinished") _finished = newValue didChangeValueForKey("isFinished") } } }

Por cierto, la verificación para ver si _executing y _finished han cambiado no es crítica, pero a veces puede ser útil al escribir métodos personalizados de cancel o similares.

Actualizar:

Más de una vez, la gente ha señalado las nuevas propiedades finished / executing en NSOperation.h y concluyó que las claves KVO apropiadas estarían finished / executing . Generalmente, cuando se escriben propiedades compatibles con KVO, eso sería correcto.

Pero NSOperationQueue no observa las teclas finished / executing . Observa las teclas isFinished / isExecuting . Si no realiza las llamadas KVO para las claves isFinished / isExecuting , puede tener problemas (en particular, las dependencias entre las operaciones asíncronas fallarán). Es molesto, pero así es como funciona. La sección Operaciones de configuración para la ejecución simultánea del capítulo Colas de operaciones de la Guía de programación concurrente es muy clara sobre el tema de la necesidad de realizar las isFinished isExecuting isFinished / isExecuting .

Si bien la Guía de programación de concurrencia está fechada, es bastante explícita con respecto a isFinished / isExecuting KVO. Y uno puede validar empíricamente que la guía aún refleja la implementación real de NSOperation . A modo de demostración, vea las pruebas unitarias en esta demostración de Github del KVO apropiado cuando se usa la subclase de NSOperation asíncrona / concurrente en NSOperationQueue .


Del libro rápido:

Puede presentar una propiedad de solo lectura heredada como una propiedad de lectura y escritura al proporcionar tanto un captador como un definidor en la anulación de la propiedad de su subclase.

Creo que encontrarás que esto funciona:

override var executing : Bool { get { return _executing } set { willChangeValueForKey("isExecuting") _executing = newValue didChangeValueForKey("isExecuting") } } private var _executing : Bool


Swift 3.0 Respuesta Actualización:

private var _executing : Bool = false override var isExecuting : Bool { get { return _executing } set { guard _executing != newValue else { return } willChangeValue(forKey: "isExecuting") _executing = newValue didChangeValue(forKey: "isExecuting") } } private var _finished : Bool = false override var isFinished : Bool { get { return _finished } set { guard _finished != newValue else { return } willChangeValue(forKey: "isFinished") _finished = newValue didChangeValue(forKey: "isFinished") } }