UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: Trying to Bind an ObservableObject but getting Cannot assign to property: 'XXXX' is a get-only property Error

Forums > SwiftUI

I am quite new in Swift and SwiftUI and I am getting a error that I cannot understand.

Here is my class that I load with JSON from a web service

class ResaListViewModel: ObservableObject {
    @Published var resasDeparts = [ResaViewModel]()

    init() {
        WSResa().getDeparts { resas in
            if let resas = resas as? [Resa] {
                self.resasDeparts = resas.map(ResaViewModel.init)
            }
        }
    }
}

class ResaViewModel: Identifiable, ObservableObject {
    @Published var resa: Resa

    init(resa: Resa) {
        self.resa = resa
    }

    var id: Int {
        return Int(self.resa.id)!
    }

 var nbveh: Int
    {
        return Int(self.resa.nbveh) ?? 0
    }
}

In a view I would like to Bind the nbveh property and to increment and decrement it with buttons.

the error is : "Cannot assign to property: 'nbveh' is a get-only property"

struct ResaDetail: View {
    @ObservedObject var resa:ResaViewModel

    var body: some View {
      vehiculeView(nbveh: $resa.nbveh)
}

This view is in a navigationLink with detailed view called like that.

struct ResaView: View { 
let resaListVM = ResaListViewModel() 

var body: some View { 
    List(self.resaListVM.resasDeparts, id: \.id) {resa in 
      NavigationLink(destination: ResaDetail(resa: resa)) {
        ResaList(resa: resa) 
      }
  } 
} 
.navigationBarTitle(Text("Réservations")) 
} 

How can I make this property editable and bindable ?

Thanks for any kind of help

-- Godefroy

3      

I think I see the problem.

var nbveh: Int {
        return Int(self.resa.nbveh) ?? 0
}

is like saying

var nbveh: Int{
        get {Int(self.resa.nbveh) ?? 0}
}

So you also need a set (I think this is right)

var nbveh: Int{
        get {return Int(self.resa.nbveh) ?? 0}
        set {self.resa.nbveh = newValue}
}

3      

godefroydlb

Can you provide Resa Struct, and also WSResa Class ?

3      

Thanks for your answers.

Here is Resa

class Resa:  Codable, Identifiable {
    var id: String
    var datep: String
    var datep2: String
    var nbveh: String
}

And WSResa

class WSResa {
    let url = Configuration().url

    func getDeparts(completion: @escaping([Resa]) -> ())
    {
        let session = URLSession.shared
        let request :String = "get_depart"
        let distantURL = URL(string: url + "resa_request.php?request=" + request)!

        let task = session.dataTask(with: distantURL) { data, response, error in

            if error != nil || data == nil {
                print("Client error!")
                return
            }
            guard let response = response as? HTTPURLResponse, (200...299).contains(response.statusCode) else {
                print("Server error!")
                return
            }
            guard let mime = response.mimeType, mime == "text/html" else {
                print("Wrong MIME type!")
                return
            }
            do {
                let resas = try! JSONDecoder().decode([Resa].self, from: data!)
                print("J'ai récupéré les départs")
                DispatchQueue.main.async{
                    completion(resas)
                }
            } catch {
                print("JSON error: \(error.localizedDescription)")
            }
        }

        task.resume()
}

At the moment I am working on loading data and update it throught the UI. Afterward I plan to update and save Resa objects through webservices

3      

Thanks for the feedbacks :-)

Much appreciated.

I have used the quick option. with get and set to bind two ways. Compilation succeded but there is still a problem, the view does not update. It is an observable object But I think I have to implement the didSet

I have tried to ad the property @Published but I am getting the error : Property wrapper cannot be applied to a computed property

The thing is didSet seems not compatible with the get and set declaration. When I try this

var didChange = PassthroughSubject<Void, Never>()

var nbveh: Int
    {
        get { return Int(resa.nbveh) ?? 0 }
        set { resa.nbveh = String(newValue)}
        didSet {
            didChange.send()
        }
    }

The error is "'didSet' cannot be provided together with a getter"

3      

Here the answer. Why a didSet when your are doing a setter where you can include the did/willChange message in the setter directly

 var nbveh: Int
    {
        get { return Int(resa.nbveh) ?? 0 }
        set { resa.nbveh = String(newValue)
            objectWillChange.send()
        }
    }

3      

I'm glad you solved your issue this way.

3      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.