WWDC21 SALE: Save 50% on all my Swift books and bundles! >>

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

   

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}
}

   

godefroydlb

Can you provide Resa Struct, and also WSResa Class ?

   

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

   

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"

   

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()
        }
    }

   

I'm glad you solved your issue this way.

   

Save money with our WWDC sale!

SAVE 50% To celebrate WWDC21, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Reply to this topic…

You need to create an account or log in to reply.

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.