SwiftUI 无法将变量传递给高阶函数映射
SwiftUI Can't Pass Variable to Higher Order Function Map
我有一个应用程序,其中包含一系列包含数字字段的模型。我想成为
能够对任何给定的数据字段求和。我可以通过使用数据字段来使用地图
名称(例如 $0.cups)。但是我想以编程方式发送一个
“杯子”的变量,但我没有尝试过。
这是一些示例代码。我想将要合计的字段名传入
函数 sumOnAttribute
struct ContentView: View {
@State private var answer: String = ""
@State private var startingModels = [
StartingModel(name: "abe", age: 1, bags: 2, cups: 3),
StartingModel(name: "abe", age: 11, bags: 12, cups: 13),
StartingModel(name: "abe", age: 21, bags: 22, cups: 23),
StartingModel(name: "donna", age: 31, bags: 32, cups: 33),
StartingModel(name: "elsie", age: 41, bags: 42, cups: 43),
StartingModel(name: "farah", age: 51, bags: 52, cups: 53)
]//some data
var body: some View {
VStack(spacing: 10) {
Text("Do Some Math")
.font(.title)
Text(answer)
.font(.headline)
Button {
answer = String(sumOnAttribute(filterField: "abe", sumField: "cups"))
} label: {
Text("Make it So")
}
.font(.system(size: 20))
}//v
}//body
func sumOnAttribute(filterField: String, sumField: String) -> Double {
let filteredAttribute = startingModels.filter({ [=10=].name == filterField })
//[=10=].sumField does not work, [=10=].value(sumField) does not work
let nums = filteredAttribute.map({ [=10=].cups })
let total = nums.reduce(0, +)
return total
}
}//struct
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct StartingModel: Identifiable {
let id = UUID()
let name: String
let age: Double
let bags: Double
let cups: Double
}//model
看起来应该很简单,但是我搜索了很多都没有找到任何答案。
任何指导将不胜感激。 Xcode13.3,iOS15.4
一个选项是 KeyPath
-- 它不是您正在使用的 String
,而是您正在查找的 属性 的 compile-time-safe 路径为了。实现可能如下所示:
struct ContentView: View {
@State private var answer: String = ""
@State private var startingModels = [
StartingModel(name: "abe", age: 1, bags: 2, cups: 3),
StartingModel(name: "abe", age: 11, bags: 12, cups: 13),
StartingModel(name: "abe", age: 21, bags: 22, cups: 23),
StartingModel(name: "donna", age: 31, bags: 32, cups: 33),
StartingModel(name: "elsie", age: 41, bags: 42, cups: 43),
StartingModel(name: "farah", age: 51, bags: 52, cups: 53)
]//some data
var body: some View {
VStack(spacing: 10) {
Text("Do Some Math")
.font(.title)
Text(answer)
.font(.headline)
Button {
answer = String(sumOnAttribute(filterField: "abe", sumField: \.cups))
} label: {
Text("Make it So")
}
.font(.system(size: 20))
}//v
}//body
func sumOnAttribute(filterField: String, sumField: KeyPath<StartingModel,Double>) -> Double {
let filteredAttribute = startingModels.filter({ [=10=].name == filterField })
return filteredAttribute.map({ [=10=][keyPath:sumField] }).reduce(0, +)
}
}//struct
如果你真的想使用String
,你可以考虑使用@dynamicMemberLookup
:https://www.hackingwithswift.com/articles/55/how-to-use-dynamic-member-lookup-in-swift
不清楚你想要什么,也许你可以尝试这样的事情,“...将我想要汇总的字段名称传递给函数 sumOnAttribute...”:
struct ContentView: View {
@State private var namefield: String = "" // <-- here
@State private var sumfield: String = "" // <-- here
@State private var answer: String = ""
@State private var startingModels = [
StartingModel(name: "abe", age: 1, bags: 2, cups: 3),
StartingModel(name: "abe", age: 11, bags: 12, cups: 13),
StartingModel(name: "abe", age: 21, bags: 22, cups: 23),
StartingModel(name: "donna", age: 31, bags: 32, cups: 33),
StartingModel(name: "elsie", age: 41, bags: 42, cups: 43),
StartingModel(name: "farah", age: 51, bags: 52, cups: 53)
]
var body: some View {
VStack(spacing: 10) {
TextField("name field", text: $namefield).border(.red) // <-- here
TextField("sum field", text: $sumfield).border(.red) // <-- here
Text("Do Some Math")
.font(.title)
Text(answer)
.font(.headline)
Button {
answer = String(sumOnAttribute(filterField: namefield, sumField: sumfield)) // <-- here
} label: {
Text("Make it So")
}
.font(.system(size: 20))
}
}
func sumOnAttribute(filterField: String, sumField: String) -> Double {
let filteredAttribute = startingModels.filter{ [=10=].name == filterField }
// -- here
var nums: [Double] = []
switch sumField {
case "cups": nums = filteredAttribute.map{ [=10=].cups }
case "bags": nums = filteredAttribute.map{ [=10=].bags }
case "age": nums = filteredAttribute.map{ [=10=].age }
default: break
}
return nums.reduce(0, +)
}
}
我有一个应用程序,其中包含一系列包含数字字段的模型。我想成为 能够对任何给定的数据字段求和。我可以通过使用数据字段来使用地图 名称(例如 $0.cups)。但是我想以编程方式发送一个 “杯子”的变量,但我没有尝试过。
这是一些示例代码。我想将要合计的字段名传入 函数 sumOnAttribute
struct ContentView: View {
@State private var answer: String = ""
@State private var startingModels = [
StartingModel(name: "abe", age: 1, bags: 2, cups: 3),
StartingModel(name: "abe", age: 11, bags: 12, cups: 13),
StartingModel(name: "abe", age: 21, bags: 22, cups: 23),
StartingModel(name: "donna", age: 31, bags: 32, cups: 33),
StartingModel(name: "elsie", age: 41, bags: 42, cups: 43),
StartingModel(name: "farah", age: 51, bags: 52, cups: 53)
]//some data
var body: some View {
VStack(spacing: 10) {
Text("Do Some Math")
.font(.title)
Text(answer)
.font(.headline)
Button {
answer = String(sumOnAttribute(filterField: "abe", sumField: "cups"))
} label: {
Text("Make it So")
}
.font(.system(size: 20))
}//v
}//body
func sumOnAttribute(filterField: String, sumField: String) -> Double {
let filteredAttribute = startingModels.filter({ [=10=].name == filterField })
//[=10=].sumField does not work, [=10=].value(sumField) does not work
let nums = filteredAttribute.map({ [=10=].cups })
let total = nums.reduce(0, +)
return total
}
}//struct
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct StartingModel: Identifiable {
let id = UUID()
let name: String
let age: Double
let bags: Double
let cups: Double
}//model
看起来应该很简单,但是我搜索了很多都没有找到任何答案。 任何指导将不胜感激。 Xcode13.3,iOS15.4
一个选项是 KeyPath
-- 它不是您正在使用的 String
,而是您正在查找的 属性 的 compile-time-safe 路径为了。实现可能如下所示:
struct ContentView: View {
@State private var answer: String = ""
@State private var startingModels = [
StartingModel(name: "abe", age: 1, bags: 2, cups: 3),
StartingModel(name: "abe", age: 11, bags: 12, cups: 13),
StartingModel(name: "abe", age: 21, bags: 22, cups: 23),
StartingModel(name: "donna", age: 31, bags: 32, cups: 33),
StartingModel(name: "elsie", age: 41, bags: 42, cups: 43),
StartingModel(name: "farah", age: 51, bags: 52, cups: 53)
]//some data
var body: some View {
VStack(spacing: 10) {
Text("Do Some Math")
.font(.title)
Text(answer)
.font(.headline)
Button {
answer = String(sumOnAttribute(filterField: "abe", sumField: \.cups))
} label: {
Text("Make it So")
}
.font(.system(size: 20))
}//v
}//body
func sumOnAttribute(filterField: String, sumField: KeyPath<StartingModel,Double>) -> Double {
let filteredAttribute = startingModels.filter({ [=10=].name == filterField })
return filteredAttribute.map({ [=10=][keyPath:sumField] }).reduce(0, +)
}
}//struct
如果你真的想使用String
,你可以考虑使用@dynamicMemberLookup
:https://www.hackingwithswift.com/articles/55/how-to-use-dynamic-member-lookup-in-swift
不清楚你想要什么,也许你可以尝试这样的事情,“...将我想要汇总的字段名称传递给函数 sumOnAttribute...”:
struct ContentView: View {
@State private var namefield: String = "" // <-- here
@State private var sumfield: String = "" // <-- here
@State private var answer: String = ""
@State private var startingModels = [
StartingModel(name: "abe", age: 1, bags: 2, cups: 3),
StartingModel(name: "abe", age: 11, bags: 12, cups: 13),
StartingModel(name: "abe", age: 21, bags: 22, cups: 23),
StartingModel(name: "donna", age: 31, bags: 32, cups: 33),
StartingModel(name: "elsie", age: 41, bags: 42, cups: 43),
StartingModel(name: "farah", age: 51, bags: 52, cups: 53)
]
var body: some View {
VStack(spacing: 10) {
TextField("name field", text: $namefield).border(.red) // <-- here
TextField("sum field", text: $sumfield).border(.red) // <-- here
Text("Do Some Math")
.font(.title)
Text(answer)
.font(.headline)
Button {
answer = String(sumOnAttribute(filterField: namefield, sumField: sumfield)) // <-- here
} label: {
Text("Make it So")
}
.font(.system(size: 20))
}
}
func sumOnAttribute(filterField: String, sumField: String) -> Double {
let filteredAttribute = startingModels.filter{ [=10=].name == filterField }
// -- here
var nums: [Double] = []
switch sumField {
case "cups": nums = filteredAttribute.map{ [=10=].cups }
case "bags": nums = filteredAttribute.map{ [=10=].bags }
case "age": nums = filteredAttribute.map{ [=10=].age }
default: break
}
return nums.reduce(0, +)
}
}