Hi Guys,
I am just trying to get a value on my view to be a sum of stored values.
I have used the following code but get the error message “Value of type ‘Int’ has no member ‘reduce’”.
Any help here would be awesome.
I have also put the code in which references to IncomeDetails.
import SwiftUI
struct MainIncomeView: View {
@Binding var income: [IncomeDetails]
var body: some View {
VStack {
Text("Income")
.font(.title)
.padding()
ForEach($income) { $income in
Text("\(income.incomeAnnual.reduce(0, +))")
.font(.headline)
.padding(.bottom)
}
}
.padding()
}
}
struct MainIncomeView_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
MainIncomeView(income: .constant(IncomeDetails.sampledata))
.previewLayout(.fixed(width: 200, height: 100))
}
}
}
import Foundation
struct IncomeDetails: Identifiable {
let id: UUID
var incomeDetails: String
var incomeFrequency: Period
var incomeAmount: Int
var incomeAnnual: Int
init(id: UUID = UUID(), incomeDetails: String, incomeFrequency: Period, incomeAmount: Int, incomeAnnual: Int) {
self.id = id
self.incomeDetails = incomeDetails
self.incomeFrequency = incomeFrequency
self.incomeAmount = incomeAmount
self.incomeAnnual = incomeAnnual
}
}
extension IncomeDetails {
struct Data {
var incomeDetails: String = ""
var incomeFrequency: Period = .Weekly
var incomeAmount: Int = 0
var incomeAnnual: Int = 0
}
var data: Data {
Data(incomeDetails: incomeDetails, incomeFrequency: incomeFrequency, incomeAmount: incomeAmount, incomeAnnual: incomeAnnual)
}
mutating func update(from data: Data) {
incomeDetails = data.incomeDetails
incomeFrequency = data.incomeFrequency
incomeAmount = Int(data.incomeAmount)
incomeAnnual = Int(data.incomeAnnual)
}
init(data: Data) {
id = UUID()
incomeDetails = data.incomeDetails
incomeFrequency = data.incomeFrequency
incomeAmount = Int(data.incomeAmount)
incomeAnnual = Int(data.incomeAnnual)
}
}
extension IncomeDetails {
static let sampledata: [IncomeDetails] =
[
IncomeDetails(incomeDetails: "Wages", incomeFrequency: .Weekly, incomeAmount: 1000, incomeAnnual: 52000),
IncomeDetails(incomeDetails: "Dividends", incomeFrequency: .Quarterly, incomeAmount: 500, incomeAnnual: 2000)
]
}
Perfect formatted question 

Reduce is a function of an array, not an integer, that’s what the issue is.
So you want a sum of the incomeAnnual
property for every element in the income
array?
Hi Mikaela,
ah ok makes sense. And yes thats exactly what I want to do.
Do you know what I need to do to achieve this?
Thanks
First easiest way I can think of is:
- Create a lazy variable in your MainIncomeView and have it be a normal computer property
- iterate through the
income
array (now you could use the reduce function)
- and return that value as the value for the computed property
- in the view use your computed property
Thanks Mikaela,
This is the code which I wrote (not sure if its correct) but I am still getting the same error. Can you please help work out where I am going wrong?
private lazy var incomeAnnualSum = ForEach($income) { $income in
income.incomeAnnual.reduce(0, +)
}
You can’t use ForEach
outside of a View
's body
property (or another property that returns some View
or similar). You want incomeAnnualSum
to return an Int
, so ForEach
is incorrect here. Your use of reduce
is a good idea, but you’ve got the form wrong. You can’t just pass +
as the function to use in the reduce, since you have to drill down into a property to get the value you want and can’t do a straight addition.
It should be:
private var incomeAnnualSum: Int {
income.reduce(into: 0) { r, c in
r += c.incomeAnnual
}
}
But your logic doesn’t make any sense. By using:
ForEach($income) { $income in
...
}
You are calculating incomeAnnualSum
for each member of your income
array. But it will always be the same amount because incomeAnnualSum
is calculated using every member of the income
array!
Take out the ForEach
and just have the Text
there and that will be correct.
Thanks for this, I have updated the code accordingly (see below) but now I am getting an error on the Text(incomeAnnualSum) line saying “No exact matches in call to initializer”.
Any thoughts here?
import SwiftUI
struct MainIncomeView: View {
@Binding var income: [IncomeDetails]
private var incomeAnnualSum: Int {
income.reduce(into: 0) { r, c in
r += c.incomeAnnual
}
}
var body: some View {
VStack {
Text("Income")
.font(.title)
.padding()
Text(incomeAnnualSum)
.font(.headline)
.padding(.bottom)
}
.padding()
}
}
struct MainIncomeView_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
MainIncomeView(income: .constant(IncomeDetails.sampledata))
.previewLayout(.fixed(width: 200, height: 100))
}
}
}
Actually looks like I got it working sorry, just had to wrap it in a Int.
Thank you again for your help!
import SwiftUI
struct MainIncomeView: View {
@Binding var income: [IncomeDetails]
private var incomeAnnualSum: Int {
income.reduce(into: 0) { r, c in
r += c.incomeAnnual
}
}
var body: some View {
VStack {
Text("Income")
.font(.title)
.padding()
Text("\(Int(incomeAnnualSum))")
.font(.headline)
.padding(.bottom)
}
.padding()
}
}
struct MainIncomeView_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
MainIncomeView(income: .constant(IncomeDetails.sampledata))
.previewLayout(.fixed(width: 200, height: 100))
}
}
}
You don’t need to wrap it in an Int
if you add a format
parameter, as I mentioned in the other thread:
Text(computedIncomeAmount, format: .number)