Expression of type is unused

Hi Team,

The below code is where I have a form to input but I want the “Annual Amount” to have a calculated value. So I have disabled the edit function for this section and tried to have .onAppear be my calculated value. But I am having issues with the .onAppear which is giving me the error “Expression of type ‘Binding’ is unused.”.

Any help on how to resolve this would be awesome.

Thanks

import SwiftUI

struct IncomeEditView: View {
    @Binding var data: IncomeDetails.Data
    
    private var computedIncomeAmount: Binding<Int> {
        Binding(
          get: {
            switch data.incomeFrequency {
            case .Daily:
                return data.incomeAmount * 365
            case .Weekly:
              return data.incomeAmount * 52
            case .Fortnightly:
              return data.incomeAmount * 26
            case .Monthly:
              return data.incomeAmount * 12
            case .Quarterly:
              return data.incomeAmount * 4
            case .Annually:
              return data.incomeAmount
            }
          },
          set: { _ in }
          )
      }
    

    var body: some View {
        Form {
            Section(header: Text("Details")) {
                TextField("Details", text: $data.incomeDetails)
            }
            Section(header: Text("Frequency")) {
                PeriodPicker(selection: $data.incomeFrequency)
            }
            Section(header: Text("Amount")) {
                TextField("Amount", value: $data.incomeAmount, format: .number)
                    .keyboardType(.numberPad)
            }
            Section(header: Text("Annual Amount")) {
                TextField("Amount", value:  $data.incomeAnnual, format: .number)
                    .onAppear(perform: {computedIncomeAmount})
                    .keyboardType(.numberPad)
                    .disabled(true)
            }
        }
    }
}

struct IncomeEditView_Previews: PreviewProvider {
    static var previews: some View {
        NavigationView {
            IncomeEditView(data: .constant(IncomeDetails.sampledata[0].data))
    }
}
}

Why is it a binding property?

try to just make it just a normal computed property

private lazy var computedIncomeAmount: Int {
switch data.incomeFrequency {
            case .Daily:
                return data.incomeAmount * 365
            case .Weekly:
              return data.incomeAmount * 52
            case .Fortnightly:
              return data.incomeAmount * 26
            case .Monthly:
              return data.incomeAmount * 12
            case .Quarterly:
              return data.incomeAmount * 4
            case .Annually:
              return data.incomeAmount
            }
          }

Thanks Mikaela,

The binding but was recommended by another user.

I have updated my code with your recommendation but it is now showing that ‘lazy’ cannot be used on a computed property and its also not in the initializer.

Then when I remove Lazy I still have the same warning or the expression type not being used.

Any other ideas?

Thanks

If you think about it, lazy doesn’t make sense for a computed property. lazy means the value is only calculated the first time it is needed; computed properties get calculated only when they are used. Same idea. So lazy is only good for stored properties, not computed properties. So get rid of the lazy annotation.

Expression not used means that the result of your closure is not being assigned to anything. That’s here:

.onAppear(perform: {computedIncomeAmount})

If you change it to this you will silence that error:

.onAppear(perform: {_ = computedIncomeAmount})

But there are a couple other issues:

  1. You are using computedIncomeAmount to compute something but then not using that something anywhere.
  2. If you don’t want the user to be able to edit the Annual Amount field, don’t put it in a TextField with .disabled(true), just put it in a Text. With TextField, as you’ve seen, you need to supply a Binding but a Binding only makes sense if you will be changing the amount displayed in the field, which you can’t with .disabled(true) attached.

So, you can replace that TextField with:

Text(computedIncomeAmount, format: .number)

This way you are using computedIncomeAmount and editing is disabled and you no longer need to supply a Binding or supply a keyboard type or use onAppear to do the calculation. And your computed property becomes this:

private var computedIncomeAmount: Int {
    switch data.incomeFrequency {
    case .Daily:
        return data.incomeAmount * 365
    case .Weekly:
        return data.incomeAmount * 52
    case .Fortnightly:
        return data.incomeAmount * 26
    case .Monthly:
        return data.incomeAmount * 12
    case .Quarterly:
        return data.incomeAmount * 4
    case .Annually:
        return data.incomeAmount
    }
}

And, a friendly suggestion:

If you are going to be making that same calculation in a number of different places, it would probably be useful to do something like this:

enum Period: Int {
    case Daily = 365
    case Weekly = 52
    case Fortnightly = 26
    case Monthly = 12
    case Quarterly = 4
    case Annually = 1
}

(Note, you didn’t include it in your post, so I had to guess at what Period looked like.)

Make Period be backed by an Int and assign each case a value, which automatically conforms it to the RawRepresentable protocol, which means you can change your computed property to this:

private var computedIncomeAmount: Int {
    data.incomeAmount * data.incomeFrequency.rawValue
    //rawValue refers to the value you assigned each case
}

Much easier to use if you find yourself doing the same switch statement in multiple Views.

1 Like

Thanks for this, below is my code now but it doesn’t appear to be calculating at all.

I have also been using the annual amount as a disabled text field because I need it to be persisting data to pull through other areas of the app. Do you know if this will be possible though Text?

if you need any more details please let me know.

Thanks

import SwiftUI

struct IncomeEditView: View {
    @Binding var data: IncomeDetails.Data
    
    private var computedIncomeAmount: Int {
        switch data.incomeFrequency {
        case .Daily:
            return data.incomeAmount * 365
        case .Weekly:
            return data.incomeAmount * 52
        case .Fortnightly:
            return data.incomeAmount * 26
        case .Monthly:
            return data.incomeAmount * 12
        case .Quarterly:
            return data.incomeAmount * 4
        case .Annually:
            return data.incomeAmount
        }
    }

    var body: some View {
        Form {
            Section(header: Text("Details")) {
                TextField("Details", text: $data.incomeDetails)
            }
            Section(header: Text("Frequency")) {
                PeriodPicker(selection: $data.incomeFrequency)
            }
            Section(header: Text("Amount")) {
                TextField("Amount", value: $data.incomeAmount, format: .number)
                    .keyboardType(.numberPad)
            }
            Section(header: Text("Annual Amount")) {
                TextField("Amount", value:  $data.incomeAnnual, format: .number)
                    .onAppear(perform: {_ = computedIncomeAmount})
                    .keyboardType(.numberPad)
                    .disabled(true)
            }
        }
    }
}

struct IncomeEditView_Previews: PreviewProvider {
    static var previews: some View {
        NavigationView {
            IncomeEditView(data: .constant(IncomeDetails.sampledata[0].data))
    }
}
}

As I said, you are using computedIncomeAmount to compute something but then not using that something anywhere.

TextField("Amount", value:  $data.incomeAnnual, format: .number)
    .onAppear(perform: {_ = computedIncomeAmount})

You use onAppear to calculate computedIncomeAmount but then you are displaying data.incomeAnnual in the TextField. Those are two different values.

I have also been using the annual amount as a disabled text field because I need it to be persisting data to pull through other areas of the app. Do you know if this will be possible though Text?

I don’t really understand what you mean by this. What you have isn’t going to persist anything. data.incomeAnnual is being pulled from your data variable but since you’ve disabled editing on the TextField, it will never change. So any persisting of that field being done isn’t being done here.

I might be getting confused but my other values in the form are writeable for example where I have $data.incomeDetails there is no data until I write something there then its stored for use somewhere else in the app.

I am trying to achieve the same thing for my incomeAnnual value expected I want it to be a calculated value.

Is there a better way to do this?

Thanks

Hi Again,

just thinking about this more I have rewritten my code to try and show the calculated value but I still need to update my incomeAnnual figure. While I have no errors in my code it does not update my value. Do you have any ideas how I can achieve this?

Thanks

import SwiftUI

struct IncomeEditView: View {
    @Binding var data: IncomeDetails.Data
    
    private var computedIncomeAmount: Int {
        switch data.incomeFrequency {
        case .Daily:
            return data.incomeAmount * 365
        case .Weekly:
            return data.incomeAmount * 52
        case .Fortnightly:
            return data.incomeAmount * 26
        case .Monthly:
            return data.incomeAmount * 12
        case .Quarterly:
            return data.incomeAmount * 4
        case .Annually:
            return data.incomeAmount
        }
    }

    var body: some View {
        Form {
            Section(header: Text("Details")) {
                TextField("Details", text: $data.incomeDetails)
            }
            Section(header: Text("Frequency")) {
                PeriodPicker(selection: $data.incomeFrequency)
            }
            Section(header: Text("Amount")) {
                TextField("Amount", value: $data.incomeAmount, format: .number)
                    .keyboardType(.numberPad)
            }
            Section(header: Text("Annual Amount")) {
                Text(computedIncomeAmount, format: .number)
            }
        }
        .onSubmit {
            data.incomeAnnual =  computedIncomeAmount
        }
    }
}

struct IncomeEditView_Previews: PreviewProvider {
    static var previews: some View {
        NavigationView {
            IncomeEditView(data: .constant(IncomeDetails.sampledata[0].data))
    }
}
}