swift - 如何在 View 中使用 Swift 参数包

标签 swift parameter-pack wwdc

我想轻松地为 SwiftUI 预览 View 提供可变绑定(bind)(以便预览是交互式的,与传递 .constant(...) 绑定(bind)不同)。我关注了BindingProvider一次允许一个值的方法,如下所示:

#Preview {
    BindingProvider(true) { binding in
        SomeToggleView(toggleBinding: binding)
    }
}

最好传入多个要绑定(bind)的值,就像这样

#Preview {
    BindingProvider(true, "text") { toggleBinding, textFieldBinding in
        SomeToggleAndTextFieldView(toggleBinding: toggleBinding, textFieldBinding: textFieldBinding)
    }
}

到目前为止,我已经得到了这段代码,但它没有编译,只是说“Command SwiftCompile failed with a nonzero exit code

struct BindingProvider<each T, Content: View>: View {
    
    @State private var state: (repeat State<each T>)
    
    private var content: ((repeat Binding<each T>)) -> Content
    
    init(_ initialState: repeat each T, 
         @ViewBuilder content: @escaping ((repeat Binding< each T>)) -> Content)
    {
        self.content = content
        self._state = State(initialValue: (repeat State(initialValue: each initialState)))
    }
    
    var body: Content {
        content((repeat (each state).projectedValue))
    }
}

也许我做错了什么或者这只是编译器问题?任何帮助将不胜感激!

最佳答案

编译器似乎还无法将某些协议(protocol)结构与参数包一起管理。指定具体 View 类型有帮助,因此只需替换

var body: some View {

var body: Content {

没有类型删除的解决方案不能提供平滑的绑定(bind)展开...并且如果不以某种方式枚举元组的元素,您就无法展开它。我认为在 @dynamicMemberLookup 学会如何处理参数包之前这是不可能的。

struct BindingProvider<each T, Content: View>: View {
    
    @State private var state: (repeat each T)
    private var content: (_ binding: Binding<(repeat each T)>) -> Content
    
    init(_ initialState: repeat each T, @ViewBuilder content: @escaping (Binding<(repeat each T)>) -> Content) {
        self.content = content
        self._state = State(initialValue: (repeat each initialState))
    }
    
    var body: Content {
        self.content($state)
    }
}

#Preview {
    BindingProvider(0, true) { bind in
        let (count, isOn) = (bind.0, bind.1)
        Stepper("", value: count)
        Toggle("", isOn: isOn)
    }
}

这是类型删除和枚举元组值的解决方案:

struct BindingProvider<each T, Content: View>: View {
    
    @State private var states: [Any]
    private var content: ((repeat Binding<each T>)) -> Content
    
    init(_ initialState: repeat each T, @ViewBuilder content: @escaping (repeat Binding<each T>) -> Content) {
        self.content = { (args: (repeat Binding<each T>)) in
            content(repeat each args)
        }
        
        // convert arguments to an array
        var states = [Any]()
        repeat states.append(each initialState as Any)
        _states = State(initialValue: states)
    }
    
    // Specify body type as Content. Compile time error otherwise
    var body: Content {
        content((repeat each makeBindings()))
    }
    
    private func makeBindings() -> (repeat Binding<each T>) {
        var index = 0
        func makeBinding<Result>(_ index: inout Int) -> Binding<Result> {
            let currentIndex = index
            index += 1
            return Binding<Result> {
                states[currentIndex] as! Result
            } set: { newValue in
                states[currentIndex] = newValue
            }
        }
        
        return (repeat makeBinding(&index) as Binding<each T>)
    }
}

#Preview {
    BindingProvider(18, "Hello") { $temperature, $greeting in
        VStack(alignment: .leading) {
            Text("\(greeting), the temperature is \(temperature)º")
            TextField("Greeting", text: $greeting)
            Stepper("\(temperature)", value: $temperature)
        }
        .padding()
    }
}

即使类型删除发生在幕后,该解决方案也是强类型的。此外,索引也是安全的,因为它受限于内部“A”的数量(重复每个 A),并且在任何实例的生命周期中都是相同的。

关于swift - 如何在 View 中使用 Swift 参数包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77101028/

相关文章:

swift - AVAssetReader输出内存问题

swift - UITextField 可复制但不可编辑 Swift

ios - Swift - 存储和检索数据

c++ - 为什么参数包没有扩展为正确的类型?

swift - xcode Playground 中的 UITableView 不显示文本/字幕

ios - 在 Xcode 模拟器中将 View 堆栈压缩到一个 block 中

c++ - 从可变参数继承并使用参数包: default constructor构造

c++ - 如何在 std 函数 lambda c++ 11 中正确捕获参数包

swift - 如何获取 ECG 电压测量 HKElectrocardiogram.VoltageMeasurement iOS 14

swift - 强制 Swift Playgrounds (xcode) 在不模拟 iOS 的情况下使用 MacOS SpriteKit