You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI Combine:发送前加索引/UUID解决List的RandomAccessCollection错误

解决Combine发送CBPeripheral时的索引/UUID添加及List集合适配问题

一、为CBPeripheral添加UUID或索引

直接发送CBPeripheral无法携带额外标识,你可以通过包装结构体实现,同时让结构体遵循Identifiable协议,方便后续List组件使用:

方案1:使用UUID作为唯一标识

// 定义包装结构体
struct IdentifiedPeripheral: Identifiable {
    let id: UUID
    let peripheral: CBPeripheral
    let rssi: NSNumber // 可按需加入广告数据等其他信息
}

// 修改Subject类型
var peripheralSubject: PassthroughSubject<IdentifiedPeripheral, Never> = .init()

// 发现外设时发送包装后的对象
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
    let wrappedPeripheral = IdentifiedPeripheral(
        id: UUID(),
        peripheral: peripheral,
        rssi: RSSI
    )
    peripheralSubject.send(wrappedPeripheral)
}

方案2:使用自增索引作为标识

如果需要按发现顺序生成索引,可维护一个计数器:

private var peripheralIndex = 0

struct IndexedPeripheral: Identifiable {
    let id: Int
    let peripheral: CBPeripheral
    let rssi: NSNumber
}

var peripheralSubject: PassthroughSubject<IndexedPeripheral, Never> = .init()

func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
    let wrappedPeripheral = IndexedPeripheral(
        id: peripheralIndex,
        peripheral: peripheral,
        rssi: RSSI
    )
    peripheralIndex += 1
    peripheralSubject.send(wrappedPeripheral)
}

二、解决List的RandomAccessCollection错误

List要求数据源遵循RandomAccessCollection协议,同时元素需具备唯一标识。你需要将Subject的输出收集到数组中,再绑定给List:

// 定义用于展示的数组
@Published var discoveredPeripherals: [IdentifiedPeripheral] = []
var cancellables = Set<AnyCancellable>()

// 在初始化方法中订阅Subject,将数据存入数组
init() {
    peripheralSubject
        .receive(on: DispatchQueue.main) // 切换到主线程更新UI
        .sink { [weak self] wrappedPeripheral in
            self?.discoveredPeripherals.append(wrappedPeripheral)
        }
        .store(in: &cancellables)
}

// 界面中使用List
List(discoveredPeripherals) { item in
    VStack(alignment: .leading) {
        Text(item.peripheral.name ?? "未命名外设")
        Text("RSSI: \(item.rssi)")
            .font(.caption)
            .foregroundColor(.secondary)
    }
}

内容的提问来源于stack exchange,提问作者stoney

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 20:32:12