rx-swiftrx-cocoa

Best way to update nested property in BehaviourRelay


I have the following Model

final class Vehicle {
var cars:[SportsCar] = []
}

final class SportsCar {
var isCheap:Bool = false
}

Assumming that Vehicle & SportsCar are both Equatable (I Have ommited Equatable conformance for simplicity).

Goal: Update isCheap property of one of the cars embedded in cars array nested inside Vehicles BehaviorRelay relay.

Attempts:

final class ViewModel {
    let vehicles:BehaviorRelay<[Vehicle]> = BehaviorRelay(value: [])
    // Attempt 1: Access vehicles direct without making a copy.
    
    // Toggling `isCheap` property when user tap a button on a collectionView cell.
    func updateCarProperty(checkedVehicle:Vehicle,checkedIndexPath:IndexPath){
        for car in vehicles.value[checkedIndexPath.section].cars {
            let checkedCar = checkedVehicle.cars[checkedIndexPath.item]
            if car == checkedCar {
                if car.isCheap {
                    vehicles.value[checkedIndexPath.section].cars[checkedIndexPath.item].isCheap = false
                }else {
                    vehicles.value[checkedIndexPath.section].districts[checkedIndexPath.item].isCheap = true
                }
                break
            }
        }
    }
    
}


// Attempt 2: Make a copy of vehicles then use it to change the property then on completion update the whole vehicles array by calling
//vehicles.accept(vehiclesCopy)
// As described on this answer: https://stackoverflow.com/a/58295908/7551807
// This approach didn't work too.

Expectation: Car isCheap property to change when the function call finished.

Result: The property doesn't change as expected 😢. It just remain as the default value (false) no matter what!!

Question: Is there any other better way to deal with this issue?


Solution

  • You have to create an entirely new copy of your object and send it to the relay. You can't emit a "subset" or the type of the relay, since it emits values of the type [Vehicle], so you must always send a new array of vehicles to it.

    You'll have to create a copy of your vehicles array, mutate the needed items and then send the entire array back using .accept(updatedVehicles).