実験してたらまさかの watchOS 7 では正しく動くという。
onAppear
や onDisappear
が呼ばれないケースはみなさんご存知
特定のケースで onAppear
や onDisappear
のは多分だけど仕様だと思う。
それと同じように、watchOS 8 では onReceive
までもがその条件に当てはまる可能性が高い。
onAppear
や onDisappear
は LazyView
を作ることでいくらでも対処可能(基本的に子の初期化遅延して、init で View の binding 用データ作成)。
import SwiftUI struct LazyView<Content: View>: View { private let build: () -> Content init(_ build: @autoclosure @escaping () -> Content) { self.build = build } var body: Content { build() } }
どうやって対処しようか……
結構深刻だと思います。
UI が struct なので、Combine 側から assign して使うのもできないですしね……
とりあえず速報ということで。
Apple Watch Series 7 の記事は今夜書く予定です(予定は未定)。
追記: 一連の問題発生に関して
検索用: watchOS で TabView
と NavigationView
を併用する場合の注意点
これの問題の解決方法は、Root に NavigationView
配置すること。iOS のように Tab -> Nav みたいな Controller のイメージで配置をすると、ドツボにハマる。
ちなみに、watchOS 7 では onAppear
や onDisappear
、watchOS 8 では onAppear
や onDisappear
、onReceive
が効かなくなり、色々と動作もおかしくなる(例えば、NaviigationView に対する設定が 2 ページ目以降、つまり NavigationLink
で遷移した画面で設定している内容が反映されないなど)。
ということで一件落着。TabView
を Root に配置できないので、いつでもタブの繊維ができなくなる不便さがある。
さらに追記: 解決編
Nav -> Tab 構造の場合はレベル 2 のページで sheet
を非表示にした際、watchOS 8 のみ (watchOS 7 は発生しない) レベル 1 の画面に戻る不具合が発生した。そのため、上であげた方法は使えない。
解決方法としては、
import SwiftUI struct RootView: View { private(set) var content: RootViewModel @State private var selectedIndex: String = "home" var body: some View { TabView(selection: $selectedIndex) { ForEach(content.collection) { item in NavigationView { TimelineView(content: item) } .tag(item.id) } } } }
のように、selection
を受け取るようにすること。たったこれだけで全てがうまくいく。上で書いていた不具合も全部消えます。
モックの部分解決できたし、今から Apple イベントなんでちょうどいい!