iOS - Swift 5 - 标签文本未在循环内更新
iOS - Swift 5 - Label Text Not Updating within Loop
我正在使用 Scenekit,我正在尝试在点击屏幕时从循环内更新 UI 上的标签文本 属性。我已验证标签已连接到情节提要中,我可以从 ViewDidLoad 更新标签。我还验证了循环中的文本值是否存在,因为我可以在控制台中看到它在打印。手势识别器的完整代码如下,您可以在底部看到我已经尝试过 GCD 但没有成功。任何帮助表示赞赏。
@objc func sceneTapped(recognizer: UITapGestureRecognizer) {
let KTStoKMperSec = 0.0005144444444444
let aircraftSpeed = 480.0 * KTStoKMperSec
let quatSun = simd_quatf(angle: Float(-1.0 / aircraftSpeed * 2 * .pi / 86400.0),
axis: simd_float3(x: 0,
y: 1,
z: 0))
for i in 0...geodesic.count-1 {
SCNTransaction.begin()
let quatPitch = simd_quatf(angle: Float(-1.0/6371.0),
axis: simd_float3(x: 1,
y: 0,
z: 0))
aircraft.position = geodesic[i].unit * 1.05
aircraft.localRotate(by: SCNQuaternion(quatPitch.vector.x, quatPitch.vector.y, quatPitch.vector.z, quatPitch.vector.w))
let SCNQuat = SCNQuaternion(quatSun.vector.x, quatSun.vector.y, quatSun.vector.z, quatSun.vector.w)
termPathnode.rotate(by: SCNQuat, aroundTarget: SCNVector3(x:0, y:1, z:0))
lightNode.rotate(by: SCNQuat, aroundTarget: SCNVector3(x:0, y:1, z:0))
cameraNode.position = aircraft.position.unit*3
SCNTransaction.commit()
//print(String("\(aircraft.position.x)"))
DispatchQueue.main.async {
//self.dataLabel.setNeedsDisplay()
self.dataLabel.text = String("\(aircraft.position.x)")
}
}
}
你没有解释问题出在哪里,但我猜想什么也没发生,然后标签更新(最终)到最后一个值。
那是因为 sceneTapped
是一个手势识别器,这意味着它 运行 在主线程上运行。 (主线程上的所有 UI 代码和事件处理 运行。)
所以 sceneTapped
在主线程上循环旋转,在主线程上排队到 运行 的块。但是主线程正忙 运行ning sceneTapped
所以 none 这些块执行。
最后,sceneTapped
returns,所有那些排队的块突然一个接一个地执行。
如果这个 for
循环是一个很长的 运行ning 循环,它需要 运行ning 在它自己的线程中。通常,您从不 想让任何需要花费大量时间来执行的代码运行宁在主线程上。任何阻塞主线程的代码都会冻结您的 UI 和所有用户交互。
所以基本上你应该有这样的东西:
@objc func sceneTapped(recognizer: UITapGestureRecognizer) {
// ...
DispatchQueue.global().async {
// execute long running code in a background thread
for i in 0...geodesic.count-1 {
// ...
//print(String("\(aircraft.position.x)"))
DispatchQueue.main.async {
//self.dataLabel.setNeedsDisplay()
self.dataLabel.text = String("\(aircraft.position.x)")
}
}
}
}
您希望在后台线程中 运行 进行大部分操作,执行其操作、计算内容、阻塞、等待等等。
当它与UI有关系时,它可以在主线程上排队一个块到运行,它仍然(独立地)运行ning,处理事件、更新视图、重新计算布局,并通常保持您的应用响应。
最后,您必须确保该后台线程中的所有内容都是线程安全的。
我正在使用 Scenekit,我正在尝试在点击屏幕时从循环内更新 UI 上的标签文本 属性。我已验证标签已连接到情节提要中,我可以从 ViewDidLoad 更新标签。我还验证了循环中的文本值是否存在,因为我可以在控制台中看到它在打印。手势识别器的完整代码如下,您可以在底部看到我已经尝试过 GCD 但没有成功。任何帮助表示赞赏。
@objc func sceneTapped(recognizer: UITapGestureRecognizer) {
let KTStoKMperSec = 0.0005144444444444
let aircraftSpeed = 480.0 * KTStoKMperSec
let quatSun = simd_quatf(angle: Float(-1.0 / aircraftSpeed * 2 * .pi / 86400.0),
axis: simd_float3(x: 0,
y: 1,
z: 0))
for i in 0...geodesic.count-1 {
SCNTransaction.begin()
let quatPitch = simd_quatf(angle: Float(-1.0/6371.0),
axis: simd_float3(x: 1,
y: 0,
z: 0))
aircraft.position = geodesic[i].unit * 1.05
aircraft.localRotate(by: SCNQuaternion(quatPitch.vector.x, quatPitch.vector.y, quatPitch.vector.z, quatPitch.vector.w))
let SCNQuat = SCNQuaternion(quatSun.vector.x, quatSun.vector.y, quatSun.vector.z, quatSun.vector.w)
termPathnode.rotate(by: SCNQuat, aroundTarget: SCNVector3(x:0, y:1, z:0))
lightNode.rotate(by: SCNQuat, aroundTarget: SCNVector3(x:0, y:1, z:0))
cameraNode.position = aircraft.position.unit*3
SCNTransaction.commit()
//print(String("\(aircraft.position.x)"))
DispatchQueue.main.async {
//self.dataLabel.setNeedsDisplay()
self.dataLabel.text = String("\(aircraft.position.x)")
}
}
}
你没有解释问题出在哪里,但我猜想什么也没发生,然后标签更新(最终)到最后一个值。
那是因为 sceneTapped
是一个手势识别器,这意味着它 运行 在主线程上运行。 (主线程上的所有 UI 代码和事件处理 运行。)
所以 sceneTapped
在主线程上循环旋转,在主线程上排队到 运行 的块。但是主线程正忙 运行ning sceneTapped
所以 none 这些块执行。
最后,sceneTapped
returns,所有那些排队的块突然一个接一个地执行。
如果这个 for
循环是一个很长的 运行ning 循环,它需要 运行ning 在它自己的线程中。通常,您从不 想让任何需要花费大量时间来执行的代码运行宁在主线程上。任何阻塞主线程的代码都会冻结您的 UI 和所有用户交互。
所以基本上你应该有这样的东西:
@objc func sceneTapped(recognizer: UITapGestureRecognizer) {
// ...
DispatchQueue.global().async {
// execute long running code in a background thread
for i in 0...geodesic.count-1 {
// ...
//print(String("\(aircraft.position.x)"))
DispatchQueue.main.async {
//self.dataLabel.setNeedsDisplay()
self.dataLabel.text = String("\(aircraft.position.x)")
}
}
}
}
您希望在后台线程中 运行 进行大部分操作,执行其操作、计算内容、阻塞、等待等等。
当它与UI有关系时,它可以在主线程上排队一个块到运行,它仍然(独立地)运行ning,处理事件、更新视图、重新计算布局,并通常保持您的应用响应。
最后,您必须确保该后台线程中的所有内容都是线程安全的。