Swift-UIでTable内容をリアルタイム更新する

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
        }
    }

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です