Переопределяет свойство NSOperation (isExecuting / isFinished)

я подклассы NSOperation в Swift и нужно переопределить isExecuting и isFinished свойства, так как я переопределяя start метод.

проблема, с которой я сталкиваюсь, заключается в том, как сохранить наблюдение за значением ключа (KVO), а также переопределить эти свойства.

обычно в Obj-C это было бы довольно легко переопределить свойства как readwrite в расширении класса JSONOperation () определение. Однако я не вижу такой же возможности в Быстрый.

пример:

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

Итак, вот решение, которое я придумал, но оно кажется ужасно уродливым и избитым:

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

Пожалуйста, скажите мне, что есть лучший путь. Я знаю, что могу сделать var isExecuting вместо всего struct, но тогда у меня есть два одноименных свойства, которые вводят двусмысленность, а также делают его общедоступным для записи (чего я не хочу).

о, что бы я сделал для некоторых ключевых слов модификатора доступа...

3 ответов


из книги swift:

наследуемое свойство только для чтения можно представить как свойство чтения и записи, предоставив как геттер, так и сеттер в переопределении свойства подкласса.

Я думаю, вы обнаружите, что это работает:

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

как сказал Дэвид, вы можете реализовать как геттер, так и сеттер в переопределении свойства подкласса.

но, при определении asynchronous/concurrent операции (т. е. те операции, которые будут выполняться асинхронно), важно назвать will/didChangeValueForKey на isFinished и isExecuting. Если вы этого не сделаете, операции не будут выпущены, зависимости не будут соблюдены, у вас будут проблемы maxConcurrentOperationCount, etc.).

поэтому я бы предлагаю:

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

кстати, проверяя, если _executing и _finished изменились не критично, но иногда это может быть полезно при написании пользовательского cancel методы или тому подобное.


обновление:

не раз люди указывали на новое finished/executing свойства NSOperation.h и пришел к выводу, что соответствующие ключи KVO будут finished/executing. Как правило, при написании свойств, совместимых с KVO, это было бы правильно.

но NSOperationQueue не наблюдает finished/executing ключи. отмечается isFinished/isExecuting ключи. Если вы не выполняете вызовы KVO для isFinished/isExecuting ключи, у вас могут быть проблемы (в частности, зависимости между асинхронными операциями не удастся). Это раздражает, но так это работает. The настройка операций для параллельного выполнения на Очереди Операции глава Руководство По Программированию Параллелизма очень ясно на тему необходимости выполнения isFinished/isExecuting кво звонки.

пока Руководство По Программированию Параллелизма датировано, это довольно ясно относительно isFinished/isExecuting кво. И можно легко эмпирически подтвердить, что руководство по-прежнему отражает фактическое NSOperation реализация. В качестве демонстрации см. модульные тесты в это GitHub демонстрация соответствующего кво при использовании асинхронного / параллельного NSOperation подкласс в NSOperationQueue.


Swift 3.0 Обновление Ответа:

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