chudin26
chudin26

Reputation: 1172

How to make transformation of value for binding or state

I'm trying to understand how to transform value from model to view. For example, I have a model:

struct BloodPressure {  
    var systolic: Int = 0
    var diastolic: Int = 0
}

And I have a view:

struct MeasurementsTabView: View {
    @State private var bloodPressure = BloodPressure()

    var body: some View {
        VStack {
            TextField("Systolic", text: $bloodPressure.systolic)
            TextField("Diastolic", text: $bloodPressure.diastolic)
        }
    }
}

There is an error, because text parameter should be a string, but bloodPressure.systolic is Int.

I found a solution, but I think that isn't elegant:

var body: some View {
    let systolicBinding = Binding <String> (
        get: { String(self.bloodPressure.systolic) },
        set: {
            if let int = Int($0) {
                self.bloodPressure.systolic = int
            }
        })

    let diastolicBinding = Binding <String> (
        get: { String(self.bloodPressure.diastolic) },
        set: {
            if let int = Int($0) {
                self.bloodPressure.diastolic = int
            }
        })

    return VStack {
        TextField("Systolic", text: systolicBinding)
        TextField("Diastolic", text: diastolicBinding)
    }
}

How you solve similar issues?

Upvotes: 1

Views: 453

Answers (1)

Asperi
Asperi

Reputation: 257563

In this case I recommend to introduce ViewModel layer, so BloodPressure remains pure model.

Below is simplified demo of concept (eg. formatting/validation of text fields is out of scope, etc.)

import SwiftUI
import Combine

struct BloodPressure {
    var systolic: Int = 0
    var diastolic: Int = 0
}

class BloodPressureViewModel: ObservableObject {
    var model: BloodPressure

    init(_ model: BloodPressure) {
        self.systolic = String(model.systolic)
        self.diastolic = String(model.diastolic)

        self.model = model
    }
    @Published var systolic: String = "" {
        didSet {
            self.model.systolic = Int(self.systolic) ?? 0
        }
    }
    @Published var diastolic: String = "" {
        didSet {
            self.model.diastolic = Int(self.diastolic) ?? 0
        }
    }
}


struct MeasurementsTabView: View {
    @ObservedObject var viewModel: BloodPressureViewModel

    init(bloodPressure: BloodPressure) {
        viewModel = BloodPressureViewModel(bloodPressure)
    }
    var body: some View {
        VStack {
            TextField("Systolic", text: $viewModel.systolic)
            TextField("Diastolic", text: $viewModel.diastolic)
        }
    }
}

Upvotes: 2

Related Questions