2

TLDR:UndoManagerバックグラウンド スレッドから使​​用する場合、実行ループに基づく自動取り消しグループ化がどのように影響を受けるか、およびこれに対する私の最良のオプションは何か疑問に思っています。


iOS と macOS の両方をターゲットとするカスタム Swift フレームワークでUndoManager(以前は)を使用しています。NSUndoManager

フレームワーク内では、かなりの量の作業がバックグラウンドの GCD シリアル キューで行われます。UndoManager実行ループ サイクルごとに最上位の登録済み取り消しアクションが自動的にグループ化されることは理解していますが、さまざまなスレッド状況がそれにどのように影響するかはわかりません。

私の質問:

  • UndoManager次の状況は、登録された元に戻すアクションの実行ループのグループ化にどのような影響を与えますか?
  • 元に戻す登録を必要とするすべての変更が単一のバックグラウンド シリアル ディスパッチ キューで行われると仮定すると、自然なグループ化を提供するのに理想的な状況 (実行不可能な状況 1 を除く) はどれですか?

以下のすべての状況では、and は空想的ではないと仮定methodCausingUndoRegistration()anotherMethodCausingUndoRegistration()UndoManager.registerUndoディスパッチなしで呼び出されたスレッドから呼び出します。

状況 1: メインスレッドでのインライン化

// Assume this runs on main thread
methodCausingUndoRegistration()
// Other code here
anotherMethodCausingUndoRegistration()
// Also assume every other undo registration in this framework takes place inline on the main thread

私の理解:これは、UndoManager使用されることを期待する方法です。上記の両方の取り消し登録は、同じ実行ループ サイクルで行われるため、同じ取り消しグループに配置されます。

状況 2: メインスレッドでの同期ディスパッチ

// Assume this runs on an arbitrary background thread, possibly managed by GCD.
// It is guaranteed not to run on the main thread to prevent deadlock.
DispatchQueue.main.sync {
    methodCausingUndoRegistration()
}
// Other code here
DispatchQueue.main.sync {
    anotherMethodCausingUndoRegistration()
}

// Also assume every other undo registration in this framework takes place
// by syncing on main thread first as above

私の理解: 明らかに、同期ディスパッチはほとんどの状況で優れたアイデアではないため、このコードを本番環境で使用したくありません。ただし、タイミングを考慮して、これら 2 つのアクションが別々の実行ループ サイクルに配置される可能性があると思います。

状況 3: メインスレッドでの非同期ディスパッチ

// Assume this runs from an unknown context. Might be the main thread, might not.
DispatchQueue.main.async {
    methodCausingUndoRegistration()
}
// Other code here
DispatchQueue.main.async {
    anotherMethodCausingUndoRegistration()
}

// Also assume every other undo registration in this framework takes place
// by asyncing on the main thread first as above

私の理解: これが状況 1 と同じ効果を生み出すことを望んでいますが、これが状況 2と同様の未定義のグループ化を引き起こす可能性があると思います。

状況 4: バックグラウンド スレッドでの単一の非同期ディスパッチ

// Assume this runs from an unknown context. Might be the main thread, might not.
backgroundSerialDispatchQueue.async {
    methodCausingUndoRegistration()
    // Other code here
    anotherMethodCausingUndoRegistration()
}

// Also assume all other undo registrations take place
// via async on this same queue, and that undo operations
// that ought to be grouped together would be registered
// within the same async block.

私の理解: がこの同じバックグラウンド キューから排他的に使用されている限り、これが状況 1と同じように動作することを本当に願っています。UndoManagerただし、特にGCDキュー(またはそのマネージドスレッド)が常に(あるとしても)実行ループを取得するとは思わないため、グループ化が未定義になるいくつかの要因があるのではないかと心配しています。

4

1 に答える 1