Swift UIで画面遷移時にタイマーを停止したい。
前提
ソースコード TobusDataViewModelクラス内にTimer.scheduledTimer()で15秒おきに処理を繰り返すタイマーを設置しておりますが、メモリ解放のため、ContentViewが画面遷移で非表示になった際にタイマー(myTimer)の破棄をするプログラムを実装しております。
ContentView内のVStack()直下の.onDisappear()でTobusDataViewModelクラス内のmyTimerプロパティを呼び出し、invalidate()でタイマーの破棄を試みました。
発生している問題・エラーメッセージ
コンソールでタイマーが停止しているか、確認を行いましたが、タイマーが停止していない(処理が続いている)ことがわかりました。
該当のソースコード
Swift
1 2 3struct TopView: View{ 4 var routes: [Route] = routeData 5 var body: some View { 6 NavigationStack { 7 ScrollView { 8 LazyVGrid(columns: [GridItem()], spacing: 0.0) { 9 ForEach(0 ..< routes.count ,id: \.self) { index in 10 NavigationLink(value: index){ 11 Text(routes[index].title) 12 } 13 } 14 } 15 } 16 .navigationBarTitle(Text("ホーム"),displayMode: .inline) 17 .navigationDestination(for: Int.self) { value in 18 ContentView(id: routes[value].note, busroute: routes[value].busroute, buspole: routes[value].title, startpole1: routes[value].startpole1, startpole2: routes[value].startpole2) 19 } 20 } 21 } 22} 23 24struct ContentView: View { 25 @ObservedObject private var tobusDataVM = TobusDataViewModel() 26 var body: some View { 27 VStack() { 28 Text("text") 29 } 30 .onDisappear(perform:{ 31 self.tobusDataVM.myTimer.invalidate() 32 print("タイマー停止") 33 }) 34 .toolbar { 35 ToolbarItem(placement: .navigationBarTrailing) { 36 Button(action: { 37 self.tobusDataVM.myTimer.invalidate() 38 }, label: { 39 Text("タイマー停止") 40 }) 41 } 42 } 43 } 44 } 45 46class TobusDataViewModel: ObservableObject { 47 var myTimer: Timer! 48 init() { 49 myTimer = Timer.scheduledTimer(withTimeInterval:15, repeats: true, block: { (time:Timer) in 50 //処理 51 }) 52 } 53 //処理 54}
試したこと
onDisappear()内に print("タイマー停止") を記述し、画面遷移時にアクションが実行可能か、確認を行いましたところ、アクションは実行可能である事が分かりました。
しかしながら、該当のソースコードでは、タイマーの破棄が実行されません。
原因が分かる方がいらっしゃいましたら、ご教示いただけますと幸いです。
補足情報(FW/ツールのバージョンなど)
ここにより詳細な情報を記載してください。
これは、どこか別のViewからContentViewに画面遷移してきていて、ContentViewから元の画面に戻る時にタイマーを止めたいということですか? そうであれば、今のコードで問題なさそうに思います。それとも、ContentViewから別の画面に遷移する処理があって、その別画面への遷移時にタイマーを止めたいということですか? そうであれば、 `.onDisappear` は呼び出されないので`invalidate()`も`print("タイマー停止")`も実行されず、タイマーが停止しないまま画面遷移するように思います。いずれにしても、画面遷移時にタイマーを停止したいということであれば、問題が発生する状況が再現できるコード(画面遷移元と画面遷移先の両方の画面遷移処理を含めたコード)を提示する必要があると思います。
TakeOneさんコメントありがとうございます。ソースコードにTopViewを追加致しました。当方がやりたいのは、TopViewからContentViewに画面遷移してきていて、ContentViewからTopViewに戻る時にタイマーを止めたいということです。今回新たに`.onDisappear`の下に`.toolbar`を設置し、タイマー停止ボタンを作成致しました(トップの画像参照)。ボタンをクリックしたところ、View上はデータの更新が停止している事がわかったのですが、コンソール上ではデータの更新が続いています。やはりこれはタイマーが停止ていないと考えるのが正しいでしょうか。
画面遷移元のコードが追加されましたが、提示されたコードだけで正常にビルド/実行できますか? `Route` 型や `routeData` が存在していないし、ContentViewの引数にidやbusroute等を指定していますが、それを受け取る変数がContentViewに見当たりません。問題と関係ないと思われる部分は省略してかまいませんが、省略したコードでアプリをビルド/実行して、問題が再現することを確認してから質問していますか?
あと、タイマーを起動する処理の直前に `print("タイマー開始")` を入れると、何が起きているか見えてくると思います。
回答1件
あなたの回答
tips
プレビュー
