質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
86.12%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

解決済

ネストしているTaskすべてをキャンセルしたい

DeepSea
DeepSea

総合スコア3

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

1回答

0リアクション

0クリップ

193閲覧

投稿2022/09/26 18:15

前提

ModalViewController表示時に無限ループするTask(MainTask)が動作し、MainTaskは更に無限ループするTask(ChildTask)を動作させます。
ModalViewControllerではMainTaskをメンバ変数に保持し、deinit時にMainTaskをキャンセルします。

実現したいこと

ModalViewControllerをdismissした際deinitが走り、MainTaskのカウントが停止します。
しかし、ChildTaskのカウントは動作し続けます。
ModalViewControllerが認知及びキャンセルの制御を行うのはMainTaskのみとした場合、ChildTaskをMainTaskのキャンセルと連動させる方法はございますでしょうか。

該当のソースコード

swift

class ModalViewController: UIViewController { private var task: Task<(), Error>? private var count = 0 deinit { print("ModalViewController deinit") task?.cancel() } override func viewDidLoad() { super.viewDidLoad() task = Task.detached { [weak self] in Task { var count = 0 while true { try await Task.sleep(nanoseconds: NSEC_PER_SEC) count += 1 print("ChildTask.count: \(count)") } } while true { guard let self = self else { return } try await Task.sleep(nanoseconds: NSEC_PER_SEC) await self.countIncrement() print(await "MainTask.count: \(self.count)") } } } func countIncrement() { count += 1 } @IBAction func onButtonTap(_ sender: Any) { dismiss(animated: true) } }

試したこと

Task.isCancelled判定やTask.checkCancellation()をChildTask中に追加しましたが、trueになりませんでした。

補足情報(FW/ツールのバージョンなど)

  • Xcode14.0

以下のような質問にはリアクションをつけましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

リアクションが多い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

xg63ex2b

2022/09/28 13:17

> 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になりませんでした。 こちらにつきましては、 「構造化された並行性」で使えるものみたいですので、 「構造化 "されていない" 並行性」では使えないみたいですね・・ --- 質問欄の該当のソースコードですと、 アプリとして達成したい目的があまり見えてこない気もしますので(質問用のコードのため?)、 もう少し具体的なコードにすると回答をしてくれる人がいるかもしれません(別の案なども含め?)。
DeepSea

2022/09/28 13:59

ご検討いただき、ありがとうございます。 引用いただいた情報も大変勉強になりました。 構造化されていない場合、何かしらの合図でタスクを止める仕組み自体を作る必要があると理解しました。 コードにつきまして、タスクの振る舞いを確認するために興味本位で作成したものである為、これといった目的等はございません。 引き続き構造化されていないタスクに中断シグナルを送る方法について調べていこうと思います。
xg63ex2b

2022/09/28 23:20

コメントありがとうございます。 > コードにつきまして、タスクの振る舞いを確認するために興味本位で作成したものである為、これといった目的等はございません。 そうだったのですね。 業務的な理由があるものと思ってしまいました・・・ --- * 「ModalViewControllerが認知及びキャンセルの制御を行うのはMainTaskのみ」(質問欄) * 「タスクのキャンセルや完了の管理を Swift ランタイム側に任せられず、自前で管理しないといけない」(記事の引用) これらは矛盾するように思いまして、 単純に考えると、 ChildTaskもModalViewControllerに保持するようにして、 deinitで一緒にキャンセルする感じになるのかなと思いました。 *業務的な理由などがないのでしたら1点目の方を変更する感じになるでしょうか

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
86.12%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています