Swift6 RealityKit动画中@Sendable闭包捕获非Sendable类型的警告消除方法咨询
Swift6 RealityKit动画中@Sendable闭包捕获非Sendable类型的警告消除方法咨询
嘿,这个警告我之前在Swift 6写RealityKit动画时也碰到过,给你捋一捋问题根源和解决办法!
首先,这个警告的原因很明确——Timer.scheduledTimer的闭包在Swift 6里默认是@Sendable的,而SimpleMaterial并没有遵循Sendable协议。当你在这个@Sendable闭包里直接捕获外部的simpleMaterial变量时,Swift的并发安全检查就会跳出来警告你,因为它没法保证这个非Sendable类型在并发环境下的安全性。而且你的原有代码还有个小问题:每次Timer触发都创建一个新的Task,虽然能跑,但其实有点冗余,还可能带来不必要的开销。
话不多说,直接上修改后的代码,完美解决警告还优化了逻辑:
func fadeInText(entity: ModelEntity, duration: TimeInterval = 1) { let steps = 60 let interval = duration / Double(steps) let startTime = CACurrentMediaTime() Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { [weak entity] t in guard let entity = entity else { t.invalidate() return } let elapsed = CACurrentMediaTime() - startTime let progress = min(elapsed / duration, 1.0) let alpha = progress Task { @MainActor in guard var simpleMaterial = entity.model?.materials.first as? SimpleMaterial else { t.invalidate() return } simpleMaterial.color.tint = simpleMaterial.color.tint.withAlphaComponent(CGFloat(alpha)) entity.model?.materials = [simpleMaterial] } if progress >= 1.0 { t.invalidate() } } }
我来给你拆解下关键修改:
- 去掉了在@Sendable闭包外部捕获
simpleMaterial的操作,转而在@MainActor的Task内部重新获取最新的material。这样就完全避免了在Sendable闭包里持有非Sendable类型的变量,从根源上消除了警告。 - 给Timer闭包加上了
[weak entity]捕获列表,既避免了循环引用,也符合并发安全的最佳实践。 - 把原来在外部的
guard let simpleMaterial移到了MainActor的上下文中,确保所有对RealityKit实体和材质的修改都在正确的主线程环境里执行——毕竟RealityKit的所有操作都要求在MainActor上完成。
如果你更倾向于提前获取材质,还有一种思路是把simpleMaterial的访问完全隔离在MainActor中,比如用@MainActor修饰一个变量来持有它,但上面的方案更简洁直接,没必要多此一举。
这样修改后,不仅警告会消失,代码的并发安全性也更高,还顺带优化了Task创建的冗余问题,一举三得!
内容来源于stack exchange
相关产品推荐
相关产品推荐

