首页 > 解决方案 > 我需要刷新 SwiftUI 视图,当 @propertyWrapper 被传递到

问题描述

我有一个示例结构:

public struct Axis: Hashable, CustomStringConvertible {
    public var name: String
    public var description: String {
        return "Axis: \"\(name)\""
    }
}

和属性包装器对[Axis]结构进行一些操作。

@propertyWrapper
struct WrappedAxes {
    var wrappedValue: [Axis] {
        // This is just example, in real world it's much more complicated.    
        didSet {
            for index in wrappedValue.indices {
                var elems = Array(wrappedValue[index].name.split(separator: " "))
                if elems.count>1 {
                    elems.removeLast()
                }
                let new = elems.reduce(into:"", {$0 += "\($1) "})
                wrappedValue[index].name = new+("\(Date())")
}   }   }   }

       

我尝试Axes在 SwiftUI 视图中添加、插入和删除:

public struct ContentView: View {
    @Binding var axes: [Axis]
    public var body: some View {
        VStack {
            ForEach(axes.indices, id:\.self) {index in
                HStack {
                    TextField("", text: $axes[index].name)
                    Button("Delete", action: {deleteAxis(index)})
                    Button("Insert", action: {insertAxis(index)})
                }
            }
            Button("Add", action: addAxis)
        }
    }
    
    var addAxis: () -> Void {
        return {
            axes.append(Axis(name: "New"))
            print (axes)
        }
    }
    
    var deleteAxis: (_:Int)->Void {
        return {
            if  $0 < axes.count {
                axes.remove(at: $0)
            }
            print (axes)
        }
    }
    
    var insertAxis: (_:Int)->Void {
        return {
            if  $0 < axes.count {
                axes.insert(Axis(name: "Inserted"), at: $0)
            }
            print (axes)
        }
    }
    
    public init (axes: Binding<[Axis]>) {
        self._axes = axes
    }
}

print (axes)显示所做的更改而言,视图永远不会更新。我制作了非常小的应用程序进行测试,我在其中调用ContentView

class AppDelegate: NSObject, NSApplicationDelegate {

    var window: NSWindow!
    @WrappedAxes var axes = [Axis(name: "FirstOne")]

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        let contentView = ContentView(
            axes: Binding (
                get: {self.axes},
                set: { [self] in axes = $0}))
    .... // No fancy stuff

我对代码本身的所有批评持开放态度,并提供帮助:如何在更改时推动此视图(以及所有可能的未来子视图)进行更新axes

标签: swiftswiftui

解决方案


问题是@Binding 用于嵌套视图。当您想在 SwiftUI 视图中进行更改时,您必须在操作开始的地方使用 @State。另外,您不需要以这种方式设置初始化程序。您可以像这样在 ObservableObject 中设置您的值来处理您的逻辑:

struct Axis {

  var name: String
  var description: String {
    return "Axis: \"\(name)\""
  }
}

final class AxisViewModel: ObservableObject {

  @Published var axes: [Axis] = [Axis(name: "First")]

  init() { handleAxes() }

  func addAxis() {
    axes.append(Axis(name: "New"))
    handleAxes()
  }

  func insertAxis(at index: Int) {
    axes.insert(Axis(name: "Inserted"), at: index)
    handleAxes()
  }

  func handleAxes() {
    for index in axes.indices {
      var elems = Array(axes[index].name.split(separator: " "))
      if elems.count > 1 {
        elems.removeLast()
      }
      let new = elems.reduce(into:"", { $0 += "\($1) " })
      axes[index].name = new + ("\(Date())")
    }
  }
}

struct ContentView: View {

  @ObservedObject var viewModel = AxisViewModel()

  var body: some View {
    VStack {
      ForEach(viewModel.axes.indices, id:\.self) { index in

        HStack {
          TextField("", text: $viewModel.axes[index].name)
          Button("Insert", action: { viewModel.insertAxis(at: index) })
        }
      }

      Button("Add", action: viewModel.addAxis)
    }
  }
}

推荐阅读