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

如何在visionOS RealityView的API调用完成后添加新实体?

解决visionOS RealityView中定时添加新实体的问题

问题原因

RealityView的update块设计初衷是更新现有实体的状态(比如位置、材质变化),而非用于添加新实体。每次关联的@State变量(比如你代码里的location)变化时,update块会被频繁触发,直接在其中添加实体不仅会导致重复创建,还不符合RealityView的设计逻辑——这就是你代码中添加球体无效的核心原因。


方案一:状态驱动式添加(推荐)

利用SwiftUI的状态管理,用数组存储待添加的球体位置,在update块中统一处理添加操作,避免重复创建:

import SwiftUI
import RealityKit

struct ContentView: View {
    // 存储待添加的球体位置队列
    @State private var pendingSpherePositions: [SIMD3<Float>] = []
    // 跟踪当前X轴偏移量
    @State private var currentX: Float = 0

    var body: some View {
        VStack {
            RealityView { content in
                // 初始化添加一个蓝色球体
                let initialSphere = getSphere(location: SIMD3(0.2, 0.2, 0.2), color: .blue)
                content.add(initialSphere)
            } update: { content in
                // 遍历队列,添加所有待创建的球体
                for position in pendingSpherePositions {
                    let newSphere = getSphere(location: position, color: .orange)
                    content.add(newSphere)
                }
                // 清空队列,防止重复添加
                pendingSpherePositions.removeAll()
            }
            .onAppear {
                // 模拟API调用的定时器
                Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
                    currentX += 1.0
                    // 将新位置加入待处理队列
                    pendingSpherePositions.append(SIMD3(currentX, 0.7, 0.2))
                }
            }
        }
    }
}

func getSphere(location: SIMD3<Float>, color: SimpleMaterial.Color) -> ModelEntity {
    let sphere = ModelEntity(mesh: .generateSphere(radius: 0.03))
    let material = SimpleMaterial(color: color, isMetallic: false)
    sphere.model?.materials = [material]
    sphere.position = location
    return sphere
}

方案二:直接操作RealityViewContent引用

通过保存RealityView的内容引用,在定时器回调中直接添加实体,适合简单场景:

import SwiftUI
import RealityKit

struct ContentView: View {
    @State private var currentX: Float = 0
    // 保存RealityView的内容引用
    @State private var realityContent: RealityViewContent?

    var body: some View {
        VStack {
            RealityView { content in
                let initialSphere = getSphere(location: SIMD3(0.2, 0.2, 0.2), color: .blue)
                content.add(initialSphere)
                // 记录content引用
                realityContent = content
            }
            .onAppear {
                Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
                    currentX += 1.0
                    // 确保在主线程操作RealityKit(定时器回调可能在后台线程)
                    DispatchQueue.main.async {
                        let newSphere = getSphere(location: SIMD3(currentX, 0.7, 0.2), color: .orange)
                        realityContent?.add(newSphere)
                    }
                }
            }
            // 视图消失时清空引用,避免内存泄漏
            .onDisappear {
                realityContent = nil
            }
        }
    }
}

func getSphere(location: SIMD3<Float>, color: SimpleMaterial.Color) -> ModelEntity {
    let sphere = ModelEntity(mesh: .generateSphere(radius: 0.03))
    let material = SimpleMaterial(color: color, isMetallic: false)
    sphere.model?.materials = [material]
    sphere.position = location
    return sphere
}

方案对比

  • 方案一:完全遵循SwiftUI状态驱动的设计思想,自动处理线程安全,不会出现重复添加问题,适合大多数复杂场景。
  • 方案二:实现更直接,代码量更少,但需要手动管理RealityViewContent引用的生命周期,注意线程安全,适合简单的快速实现。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 12:35:18