Swift-UIでは 一画面のGUI最大表示数は 20個くらいです。それを超える情報を表示するには Table object を使うしかない。 そこで Table object に初期値を表示するWEB記事は多数ありましたが、リアルタイム更新する事例が見受けられませんでした。もしかして出来ない??? と思い試した覚書です。Xcode 14.1 です。
結論からいうと @State変数 を割当てれば普通に使えました。例では Foreground と Background でサーバとの通信の統計を表示する例です。
まず表示値を格納する@State変数を宣言します。
// 内部用の表示項目
@State private var recvCnt : [Int32] = [0,0]
@State private var recvErr : [Int32] = [0,0]
@State private var sendCnt : [Int32] = [0,0]
@State private var sendErr : [Int32] = [0,0]
Tableの列定義は、リアルタイム表示したい列は@State変数を定義します。
// 統計コード列
struct TokeiColums: Identifiable {
let id = UUID()
let name: String
@State var value1: Int32
@State var value2: Int32
@State var value3: Int32
@State var value4: Int32
}
表示データの定義は、各列に表示値の@State変数を割当てます。
// 統計行定義
let TokeiInfo: [2] = [
TokeiColums(name: "Server受信",
value1: recvCnt[0], value2: recvErr[0], value3: recvCnt[1], value4: recvErr[1] ),
TokeiColums(name: "Server送信",
value1: sendCnt[0], value2: sendErr[0], value3: recvCnt[1], value4: recvErr[1] ), ]
Table object の定義コードは以下です。縦余裕がないとさり気なく下から表示されなくなるため、一行余裕のある高さを指定おくのががベターです。
/* 稼働統計 */
Table(TokeiInfo) {
TableColumn("項目") { locationColums in
Text(locationColums.name)
}
TableColumn("OK件数-FG") { locationColums in
Text("\(locationColums.value1)")
}
TableColumn("NG件数-FG") { locationColums in
Text("\(locationColums.value2)")
}
TableColumn("OK件数-BG") { locationColums in
Text("\(locationColums.value3)")
}
TableColumn("NG件数-BG") { locationColums in
Text("\(locationColums.value4)")
}
}
}
リアルタイム値の更新はタイマーで周期的に行います。
.onAppear {
// タイマで3秒周期に更新
updateDataTmr = Timer.scheduledTimer(withTimeInterval: 3,
repeats: true){ _ in
recvCnt[0] = 変更したい値
recvErr[0] = 変更したい値
sendCnt[0] = 変更したい値
sendErr[0] = 変更したい値
recvCnt[1] = 変更したい値
recvErr[1] = 変更したい値
sendCnt[1] = 変更したい値
sendErr[1] = 変更したい値
}
}
表示例は以下のとおりです。
iPadでは特に問題はなかったのですが、iPhone では表示が真っ白でした。これは table object そのものの課題なのかもしれません。またタイマーは View をCloseしても生きています。必ず解放します。さもない View 再表示毎にタイマーが溜まってヤバイことになります。他言語ではVewとともに解放されますが、、、自分で停止するタイマを作る場合、インスタンスをGlobal定義し、invalidateで停止させないと効きません。タイマloop内で return も flg 値==falseでも脱出でできません。以下コード例です。
var updateDataTmr:Timer? = nil // 位置情報更新タイマ
struct ビュー名: View {
:
中略
:
var body: some View {
:
中略
:
}
.onDisappear {
if updateDataTmr != nil {
updateDataTmr?.invalidate() // タイマ停止
updateDataTmr = nil
}
}