NSKeyedArchiver
を使用してアーカイブするタイプSet<CostumObject>
のインスタンスがあります。カスタムオブジェクトのセットをスレッドセーフでアーカイブする方法はありますか?
customObject1: CostumObject
とcustomObject2: CostumObject
がどこかでインスタンス化されていると仮定します。
私は、次のステートメントを使用する場合:
let setOfCostomObjects: Set<CostumObject> = [customObject1, customObject2]
let data = NSKeyedArchiver.archivedData(withRootObject: setOfCostomObjects)
NSKeyedArchiver
アーカイブ順次そのプロパティを再帰的にアーカイブされ、両方のカスタムオブジェクトを。
アーカイブ中に別のスレッドがカスタムオブジェクトとそのプロパティの両方を変更できるため、スレッドセーフではありません。
私はスレッドセーフできるアーカイブをカスタムオブジェクトの各プロパティを、同時は以下のようにセットするためのバリアとの同時キューを使用することにより、唯一の単一のセット許可されていますように、と思う:
private let concurrentPropertyAccessQueue = DispatchQueue(label: "concurrentPropertyAccessQueue", attributes: .concurrent)
…
private var safeProperty = CostumProperty.init()
public private(set) var property: CostumProperty {
get {
var result = CostumProperty.init()
concurrentPropertyAccessQueue.sync { result = safeProperty } // sync, because result is returned
return result
} // get
set { concurrentPropertyAccessQueue.async(flags: .barrier) { safeProperty = newValue } // executes locked after all gets
} // set
}
…
public func threadSafeArchiveOfProperty() -> Data {
var data = Data.init()
concurrentPropertyAccessQueue.sync { // sync, because result is returned
data = NSKeyedArchiver.archivedData(withRootObject: self.safeProperty)
}
return data
}
private let concurrentObjectAccessQueue = DispatchQueue(label: "concurrentObjectAccessQueue", attributes: .concurrent)
…
public func encode(with aCoder: NSCoder) {
concurrentObjectAccessQueue.async(execute: {
aCoder.encode(self.property forKey: "property")
…
})
}
問題がまだアーカイブカスタムオブジェクトのセットをセーフにスレッドする方法を、次のとおりです。私はまた、同様の方法でスレッドセーフアーカイブ全体のカスタムオブジェクトをすることができると思います。
これにより、アーカイブ中にセットの要素への書き込みアクセスがロックアウトされている必要があります。そうする
一つの方法は、世界的な同時キュー定義することはおそらくです:アーカイブ中にセットし、そのすべての要素をロックするには
public let globalConcurrentAccessQueue = DispatchQueue(label: "globalConcurrentAccessQueue", attributes: .concurrent)
を、1はおそらくfunc threadSafeArchiveOfSet()
を定義Set
型に拡張を書くことができます上記のように。
この関数は、globalConcurrentAccessQueue
がロックされるように、セットのencode(with aCoder: NSCoder)
をオーバーライドします。
これは正しい方法ですか?
これは標準的な解決策が必要な標準的な問題だと思います。
@Robお返事ありがとうございます。私はそれらを理解しなければならず、戻ってくるだろう。 –
@Robプロパティレベルの同期に関して:あなたは完全に正しいです:オブジェクトを全体として一貫性のあるものにするためには、オブジェクトレベルで自身またはそのプロパティを同期させ、プロパティレベルの同期を廃止する必要があります。非同期エンコーディングに関して:あなたはもう一度です:呼び出し元NSKeyedArchiverは、すべての個々のアーカイブ結果が1つの最終データオブジェクトに結合されるため、おそらくエンコーディングがシーケンシャルプロセスであると仮定します。 –
@Robシンクパターンの簡略化について:興味深い!私はこれを知らなかった。あなたの提案はうまくいきますが、[docs](https://developer.apple.com/documentation/dispatch/dispatchqueue/1452870-sync)で見つけられません。同期しないでください戻り値がありますか? –