SwiftUIを使って、Echonet Lite 機器をスキャンして、見つけ次第、リストに追加する実装を試みている。
以下が作成中のアプリの画面。scanの行の下に、検知デバイスをList形式で出したい。
が、、Stringを要素にもつArrayに対してForEachを使ってText()で追加しようとすると、ArrayはIdentifiableでないからダメと怒られる。ForEachで回す対象のデータ型はIDでアクセスできないとダメらしい(Identifiableプロトコルに準拠している必要があると理解)。Arrayもindexでアクセスしていると思うけど。。initを実行した時の要素数と、増減した時の要素数が違うから、配列のIndexは使えないということか??
List() { ForEach( 0..<deviceModel.data.count ){ index in Text(deviceModel.data[index]) } }
以下がエラーメッセージ
ForEach<Range<Int>, Int, Text> count (4) != its initial count (1). `ForEach(_:content:)` should only be used for *constant* data. Instead conform data to `Identifiable` or use `ForEach(_:id:content:)` and provide an explicit `id`!
KeyPathを引数に加えてForEachのInit処理のエラーを回避させる方法が紹介されているけど、 \.self 表記でエラーが出る。(Swiftが古いから??)
もう一つの解法として、Arrayを使うのをやめて、Identifableな型を定義してそれを使って実装する記事が出ている。自分にはこっちの方が理解しやすい。だから、、新しい型を定義して、ID付きのデバイスリストを作って、ForEachに渡そうと思う。ただし、、新たに作った構造体を要素に持つ配列の宣言等、どうSwiftで書いたらいいのか、ちょっとすぐにわからないので、今日はここまで。。
■追記
先人のブログを参考に、デバイス管理配列をIdentifiableにして、idも付けた。ソースは以下
import Foundation struct Device: Identifiable { var id: Int var name: String } class DeviceModel: ObservableObject { @Published var data:[Device] = [Device(id:0, name:"None")] var maxIndex:Int = 1 var deviceService:DeviceService = DeviceService() init(){ self.data[0].name = "ready to scan" }
モデル側はこのように改修して、ViewでForEachするとエラーが解消された。donguriさんに感謝。iOSアプリの表示は以下。ちょっとまだ細かい所はバグっているが、だいたいこんな感じで機器一覧が出たらいいなと。
残る作業は、UDPでマルチキャストしてデバイスを探すコードの実装。
■ForEachのエラー回避方法
SwiftUIでいこう! - List,identifiable。|donguri|note
donguriさんによるIdentifiable化する解消案