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