如何让SwiftUI数组同步Objective-C类中NSMutableArray的动态变化
问题根因
你当前写法的核心问题是:NSArray as! [PcapCppPacketWrappper] 这个操作是值拷贝,Swift的Array是值类型,你初始化时只是把当前ObjC的NSMutableArray里的元素拷贝了一份存到本地packets变量里,之后ObjC侧的NSMutableArray变更完全不会同步到Swift侧的这个packets变量。
可行解决方案
方案1:用Combine框架做同步(推荐)
- 第一步:在Swift侧创建可观察对象,用来同步ObjC侧的数组内容
import Combine class PacketObserver: ObservableObject { @Published var packets: [PcapCppPacketWrappper] = [] private var device: PcapCppDevWrapper init(device: PcapCppDevWrapper) { self.device = device } // 供ObjC侧新增包时主动调用,或者你也可以加个Timer定时轮询同步 @objc func syncPackets() { let newPackets = device.getPacketArray() as! [PcapCppPacketWrappper] // 仅在内容有变化时更新,避免无用渲染 if newPackets.count != packets.count { DispatchQueue.main.async { self.packets = newPackets } } } }
- 第二步:修改SwiftUI视图的代码,使用可观察对象渲染内容
struct CaptureView: View { @StateObject private var packetObserver: PacketObserver @Binding var captureWindowIsOpen: Bool init(device: PcapCppDevWrapper, captureWindowIsOpen: Binding<Bool>) { self._packetObserver = StateObject(wrappedValue: PacketObserver(device: device)) self._captureWindowIsOpen = captureWindowIsOpen } var body: some View { ScrollView { LazyVStack(alignment: .leading) { ForEach(packetObserver.packets, id: \.self) { packet in // 此处替换为你自己的单条数据包渲染逻辑 Text(packet.description) } } } } }
- 第三步(性能最优):修改ObjC侧的
PcapCppDevWrapper代码,每次往NSMutableArray中添加完数据包之后,调用Swift侧PacketObserver的syncPackets方法触发同步即可,不需要定时轮询。
方案2:KVO监听同步
如果不想加Combine依赖,也可以用KVO实现:
- 修改ObjC侧
PcapCppDevWrapper的代码,给数组属性增加KVO触发逻辑:
// .h文件声明 @interface PcapCppDevWrapper : NSObject @property (nonatomic, strong, readonly) NSMutableArray *packetArray; @end // .m文件插入数据包的位置增加KVO通知 [self willChangeValueForKey:@"packetArray"]; [_packetArray addObject:newPacket]; [self didChangeValueForKey:@"packetArray"];
- 在Swift侧直接监听
packetArray属性的变化,更新本地数组即可。
注意事项
- 后台线程新增包之后,所有更新SwiftUI视图的操作必须切换到主线程执行,否则会出现渲染异常甚至崩溃
- 如果数据包量非常大,建议做增量更新,不要每次都全量替换数组,避免UI卡顿
内容的提问来源于stack exchange,提问作者publicstaticmain
相关产品推荐
相关产品推荐

