NSOperation
をSwiftでサブクラス化しており、isExecuting
をオーバーライドしているため、isFinished
プロパティとstart
プロパティをオーバーライドする必要があります。方法。
私が遭遇した問題は、これらのプロパティをオーバーライドできる一方で、Key-Value監視(KVO)をどのように保持するかです。
通常、Obj-Cでは、クラス拡張JSONOperation ()
定義でプロパティをreadwrite
として再宣言するのはかなり簡単です。ただし、Swiftにはこれと同じ機能はありません。
例:
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 }
}
もっと良い方法があると教えてください。 struct
全体の代わりにvar isExecuting
を作成できることはわかっていますが、あいまいさを導入し、公に書き込み可能にする(私は望まない)2つの同様の名前のプロパティがあります。
ああ、私がいくつかのアクセス修飾子キーワードに対して何をするか...
Swift本から:
サブクラスプロパティオーバーライドでゲッターとセッターの両方を提供することにより、継承された読み取り専用プロパティを読み取り/書き込みプロパティとして提示できます。
これが機能することがわかると思います。
override var executing : Bool {
get { return _executing }
set {
willChangeValueForKey("isExecuting")
_executing = newValue
didChangeValueForKey("isExecuting")
}
}
private var _executing : Bool
Davidが言ったように、サブクラスプロパティオーバーライドでgetterとsetterの両方を実装できます。
ただし、asynchronous
/concurrent
操作(つまり、非同期で完了する操作)を定義する場合は、will
およびdidChangeValueForKey
に対してisFinished
/isExecuting
を呼び出すことが重要です。そうしないと、操作が解放されず、依存関係が尊重されず、maxConcurrentOperationCount
などの問題が発生します)。
したがって、私は提案します:
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
メソッドなどを作成するときに役立つ場合があります。
更新:
何度も、人々はNSOperation.h
の新しいfinished
/executing
プロパティを指摘し、適切なKVOキーはfinished
/executing
であると結論付けました。一般に、KVO準拠のプロパティを作成する場合、それは正しいでしょう。
しかし、NSOperationQueue
はfinished
/executing
キーを監視しません。isFinished
/isExecuting
キーを監視します。 isFinished
/isExecuting
キーのKVO呼び出しを実行しないと、問題が発生する可能性があります(特に、非同期操作間の依存関係が失敗します)。それは迷惑ですが、それがどのように機能するかです。 並行実行プログラミングガイドの 操作キュー の章の並行実行のための操作の構成セクションは非常にisFinished
/isExecuting
KVO呼び出しを実行する必要があるというトピックを明確にします。
同時実行プログラミングガイドは日付が付けられていますが、isFinished
/isExecuting
KVOに関しては非常に明確です。また、ガイドが実際のNSOperation
の実装を反映していることを簡単に経験的に検証できます。デモンストレーションとして、NSOperation
で非同期/並行NSOperationQueue
サブクラスを使用する場合の 適切なKVOのこのGithubデモンストレーション の単体テストを参照してください。
Swift 3.0 Answer Update:
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")
}
}