前提
ModalViewController表示時に無限ループするTask(MainTask)が動作し、MainTaskは更に無限ループするTask(ChildTask)を動作させます。
ModalViewControllerではMainTaskをメンバ変数に保持し、deinit時にMainTaskをキャンセルします。
実現したいこと
ModalViewControllerをdismissした際deinitが走り、MainTaskのカウントが停止します。
しかし、ChildTaskのカウントは動作し続けます。
ModalViewControllerが認知及びキャンセルの制御を行うのはMainTaskのみとした場合、ChildTaskをMainTaskのキャンセルと連動させる方法はございますでしょうか。
該当のソースコード
swift
1class ModalViewController: UIViewController { 2 3 private var task: Task<(), Error>? 4 5 private var count = 0 6 7 deinit { 8 print("ModalViewController deinit") 9 task?.cancel() 10 } 11 12 override func viewDidLoad() { 13 super.viewDidLoad() 14 15 task = Task.detached { [weak self] in 16 Task { 17 var count = 0 18 while true { 19 try await Task.sleep(nanoseconds: NSEC_PER_SEC) 20 count += 1 21 print("ChildTask.count: \(count)") 22 } 23 } 24 25 while true { 26 guard let self = self else { return } 27 try await Task.sleep(nanoseconds: NSEC_PER_SEC) 28 await self.countIncrement() 29 print(await "MainTask.count: \(self.count)") 30 } 31 } 32 } 33 34 func countIncrement() { 35 count += 1 36 } 37 38 @IBAction func onButtonTap(_ sender: Any) { 39 dismiss(animated: true) 40 } 41}
試したこと
Task.isCancelled
判定やTask.checkCancellation()
をChildTask中に追加しましたが、trueになりませんでした。
補足情報(FW/ツールのバージョンなど)
- Xcode14.0
> ModalViewControllerが認知及びキャンセルの制御を行うのはMainTaskのみとした場合、ChildTaskをMainTaskのキャンセルと連動させる方法はございますでしょうか。
下に引用した記事の内容を見ますと、
「MainTaskのみとした場合、」だとちょっと難しいのでしょうか?
> タスクのキャンセル
> 構造化プログラミングでは、外側の処理が完了するときには必ず内側の処理も完了している、というルールがありました。これは構造化された並列性における親タスクと子タスクの関係においても同じです。
> ...省略...
> 構造化 "されていない" 並行性
> Swift に導入される構造化された並行性は、複数の並行処理を正しく効率的に管理するための優れた概念ですが、ときには構造化 "されていない" 並行性が必要な場合もあります。その理由として "Explore structured concurrency in Swift" セッションで挙げられているのは、ひとつは非同期的でないコンテキストから非同期的な処理を開始したい場合です。もうひとつは、構造化された並行性では子タスクのライフサイクルが親タスクを越えられないのに対して、親タスクのライフサイクルを越えて実行され続けるような処理を行いたい場合です。
> ...省略...
> また、構造化されていないタスクが必要となる理由の一つである、親のライフサイクルに縛られないという性質も持っています。この性質は、逆に言えばタスクのキャンセルや完了の管理を Swift ランタイム側に任せられず、自前で管理しないといけないということを意味します。
> https://zenn.dev/akkyie/articles/swift-concurrency
---
> Task.isCancelled判定やTask.checkCancellation()をChildTask中に追加しましたが、trueになりませんでした。
こちらにつきましては、
「構造化された並行性」で使えるものみたいですので、
「構造化 "されていない" 並行性」では使えないみたいですね・・
---
質問欄の該当のソースコードですと、
アプリとして達成したい目的があまり見えてこない気もしますので(質問用のコードのため?)、
もう少し具体的なコードにすると回答をしてくれる人がいるかもしれません(別の案なども含め?)。
ご検討いただき、ありがとうございます。
引用いただいた情報も大変勉強になりました。
構造化されていない場合、何かしらの合図でタスクを止める仕組み自体を作る必要があると理解しました。
コードにつきまして、タスクの振る舞いを確認するために興味本位で作成したものである為、これといった目的等はございません。
引き続き構造化されていないタスクに中断シグナルを送る方法について調べていこうと思います。
コメントありがとうございます。
> コードにつきまして、タスクの振る舞いを確認するために興味本位で作成したものである為、これといった目的等はございません。
そうだったのですね。
業務的な理由があるものと思ってしまいました・・・
---
* 「ModalViewControllerが認知及びキャンセルの制御を行うのはMainTaskのみ」(質問欄)
* 「タスクのキャンセルや完了の管理を Swift ランタイム側に任せられず、自前で管理しないといけない」(記事の引用)
これらは矛盾するように思いまして、
単純に考えると、
ChildTaskもModalViewControllerに保持するようにして、
deinitで一緒にキャンセルする感じになるのかなと思いました。
*業務的な理由などがないのでしたら1点目の方を変更する感じになるでしょうか
回答1件
あなたの回答
tips
プレビュー