如何在 SwiftUI 中计算和发布数组
How to Calculate and Publish Arrays in SwiftUI
在 SwiftUI 中,如果我使用 属性 包装器 @Published
声明一个数组变量,然后在 for()
循环中计算该数组的每个元素,该变量是否会被发布每次我计算一个新元素?如果是这样,有没有办法告诉编译器在计算完每个元素之前不要发布变量?
我有一个应用程序可以为每个连续的音频数据帧计算频谱。然后,该应用程序将 spectrum[]
发布到呈现精美图形的多个视图。我希望每个视图只为每个连续的音频数据帧重新绘制一次 - 而不是为 spectrum[]
数组的每个计算元素重新绘制一次。
这里有一些简化的代码来说明这个问题:
class ArrayGenerator: ObservableObject {
@Published var spectrum = [Float](repeating: 0.0, count: 1000)
DispatchQueue.main.async { [self] in
for bin in 0 ..< 1000 {
spectrum[bin] = (userGain + userSlope * Float(bin)) * amplitudes[bin]
}
}
}
由于这段代码更改变量 1,000 次,我相信它发布了 1,000 次。但我希望它只发布一次 - 当 for()
循环完成时。我怎样才能做到这一点?
您假设它将发布 1000 changes/renders 是不正确的。 for
循环的所有这些迭代将在主 运行 循环的 一次 迭代中完成。以这个简单的例子为例:
class ArrayGenerator: ObservableObject {
@Published var spectrum = [Float](repeating: 0.0, count: 1000)
func run() {
DispatchQueue.main.async { [self] in
for bin in 0 ..< 1000 {
spectrum[bin] = Float(bin)
}
}
}
}
struct ContentView: View {
@StateObject private var generator = ArrayGenerator()
var body: some View {
let _ = print("Rendering...")
Text(generator.spectrum.map { String([=10=]) }.joined())
.onAppear {
generator.run()
}
}
}
打印:
Rendering...
Rendering...
第一次出现时渲染一次,然后 onAppear
运行 次,循环完成后再渲染一次。
那么,您的代码已经达到了您的预期。
您假设它将发布 1000 个更改是正确的。 objectWillChange 是在 willSet 中发送的,尽管 SwiftUI 将这些通知合并到一个渲染器中,但这仍然是您想要避免的事情。解决这个问题的方法是简单地在数组的副本上进行工作,然后将已发布的 属性 设置为新版本的数组一次。
在 SwiftUI 中,如果我使用 属性 包装器 @Published
声明一个数组变量,然后在 for()
循环中计算该数组的每个元素,该变量是否会被发布每次我计算一个新元素?如果是这样,有没有办法告诉编译器在计算完每个元素之前不要发布变量?
我有一个应用程序可以为每个连续的音频数据帧计算频谱。然后,该应用程序将 spectrum[]
发布到呈现精美图形的多个视图。我希望每个视图只为每个连续的音频数据帧重新绘制一次 - 而不是为 spectrum[]
数组的每个计算元素重新绘制一次。
这里有一些简化的代码来说明这个问题:
class ArrayGenerator: ObservableObject {
@Published var spectrum = [Float](repeating: 0.0, count: 1000)
DispatchQueue.main.async { [self] in
for bin in 0 ..< 1000 {
spectrum[bin] = (userGain + userSlope * Float(bin)) * amplitudes[bin]
}
}
}
由于这段代码更改变量 1,000 次,我相信它发布了 1,000 次。但我希望它只发布一次 - 当 for()
循环完成时。我怎样才能做到这一点?
您假设它将发布 1000 changes/renders 是不正确的。 for
循环的所有这些迭代将在主 运行 循环的 一次 迭代中完成。以这个简单的例子为例:
class ArrayGenerator: ObservableObject {
@Published var spectrum = [Float](repeating: 0.0, count: 1000)
func run() {
DispatchQueue.main.async { [self] in
for bin in 0 ..< 1000 {
spectrum[bin] = Float(bin)
}
}
}
}
struct ContentView: View {
@StateObject private var generator = ArrayGenerator()
var body: some View {
let _ = print("Rendering...")
Text(generator.spectrum.map { String([=10=]) }.joined())
.onAppear {
generator.run()
}
}
}
打印:
Rendering...
Rendering...
第一次出现时渲染一次,然后 onAppear
运行 次,循环完成后再渲染一次。
那么,您的代码已经达到了您的预期。
您假设它将发布 1000 个更改是正确的。 objectWillChange 是在 willSet 中发送的,尽管 SwiftUI 将这些通知合并到一个渲染器中,但这仍然是您想要避免的事情。解决这个问题的方法是简单地在数组的副本上进行工作,然后将已发布的 属性 设置为新版本的数组一次。