@BindableObject对didChange.send()的异步调用不会使它的视图无效(并且永远不会更新)

时间:2019-07-10 11:23:14

标签: swiftui

我发现我认为@ObjectBinding中的错误。对于@BindableObject异步调用其didChange.send()的情况,有时依赖于该更改的视图不会失效,因此不再请求它们的主体,并且不更新其外观。

List视图中的行应该每秒更新一次。起初它工作正常。但是,当使用“ +”按钮添加新行时,事情开始横摆。

我将行设置为 tappable ,因此,当点击它们时,@ State变量会更改以更改文本的颜色。因为已正确检测到此绑定,所以该视图将无效并且其外观也会更改。这表明计时器实际上正在运行,即使该视图在被点击之前也没有显示。

请注意,下面代码的唯一目的是演示这种奇怪的行为。我不是在寻找解决方法。出于这个问题,我的目的是确认这是否是错误,如果不是,那我在做什么错。

在其他情况下,用@EnvironmentObject替换@ObjectBinding可以解决此问题。不过,在这种情况下,它只会有所改善。

我在回答另一个问题时遇到了这个问题:SwiftUI and Combine not working smoothly when downloading image

更新:顺便说一句,如果将@ObjectBinding替换为@State,一切将会顺利进行。

import SwiftUI
import Combine

struct Row: Equatable {
    let id: Int
    let name: String
}

struct ContentView : View {
    @State private var rows: [Row] = [Row(id: 0, name: "Row #0"), Row(id: 1, name: "Row #1")]

    var body: some View {
        NavigationView {
            List(rows.identified(by: \.id)) { row in
                RowView(row: row, rowData: RowData())
            }
            .navigationBarItems(trailing:
                Button(action: {
                    self.addRow()
                }, label: {
                    Text("+").font(.system(size: 36.0))
                }))
        }
    }

    func addRow() {
        rows.append(Row(id: rows.count, name: "Row #\(rows.count)"))
    }

}

struct RowView: View {
    let row: Row
    @ObjectBinding var rowData: RowData
    @State private var showBlue = false

    var body: some View {
        Text("\(row.name) - Seconds \(rowData.value)").foregroundColor(showBlue ? Color.blue : Color.primary)
            .tapAction {
                self.showBlue.toggle()
        }
    }
}

class RowData: BindableObject {
    var didChange = PassthroughSubject<Void, Never>()

    var value: Int = 1 {
        didSet { didChange.send() }
    }

    init() {
        update()
    }

    func update() {
        DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {
            self.value += 1
            self.update()
        }
    }
}

1 个答案:

答案 0 :(得分:1)

您需要用let objectWillChange = ObservableObjectPublisher()替换didChange,因为ObservableObject已隐式实现了PassthroughtSubject。

此外,Apple文档现在建议使用@Published代替didSet:@Published var value: Int = 1

在您的更新函数中,将self.update()替换为self.objectWillChange.send()

我发现this link解释了如何触发视图无效。