在视图状态更新时重新加载Aync调用

时间:2020-07-09 20:44:11

标签: swift xcode swiftui

我有以下观点:

struct SpriteView: View {
    @Binding var name: String
    @State var sprite: Image = Image(systemName: "exclamationmark")
    
    var body: some View {
        VStack{
            sprite
        }
        .onAppear(perform: loadSprite)
    }
    
    func loadSprite() {
        // async function
        getSpriteFromNetwork(self.name){ result in
            switch result {
            // async callback
            case .success(newSprite):
                self.sprite = newSprite
            }
    }
}

我要发生的事情非常简单:用户在文本字段中(从父视图中)修改name,然后使用新的sprite重新加载SpriteView。但是上面的视图不起作用,因为当用新名称重新加载视图时,不会再次调用loadSpriteonAppear仅在首次加载视图时触发)。我也不能将loadSprite放在视图本身中(并返回一个图像),因为它会导致无限循环。

有一个Beta函数onChange正是我要寻找的功能,但仅在Xcode的Beta版本中。由于Combine是异步回调的全部,并且SwiftUI和Combine应该可以很好地结合使用,因此我认为这种行为很难实现,但是我遇到了很多麻烦。

1 个答案:

答案 0 :(得分:0)

我并不特别喜欢这种解决方案,因为它需要创建一个新的ObservableObject,但这是我最终要这样做的方式:

class SpriteLoader: ObservableObject {
    @Published var sprite: Image = Image(systemName: "exclamationmark")
    
    func loadSprite(name: String) {
        // async function
        self.sprite = Image(systemName: "arrow.right")
    }
}

struct ParentView: View {
    @State var name: String

    @State var spriteLoader = SpriteLoader()

    var body: some View {
        SpriteView(spriteLoader: spriteLoader)
        TextField(name, text: $name, onCommit: {
            spriteLoader.loadSprite(name: name)
        })
    }
}

struct SpriteView: View {
    @ObservedObject var spriteLoader: SpriteLoader
    
    var body: some View {
        VStack{
            spriteLoader.sprite
        }
    }
}

旧答案:

我认为做到这一点的最佳方法如下:

父视图:

struct ParentView: View {
    @State var name: String

    @State spriteView = SpriteView()

    var body: some View {
        spriteView
        TextField(value: $name, onCommit: {
            spriteView.loadSprite(name)
        })
    }

然后,sprite视图甚至不需要@Binding name成员。