0

I am facing the issue of "Cannot assign to immutable expression of type 'Bool'" . Please look at the below code. I am getting error in viewForHeaderInSection. Actually where should i do modification to make it work?.

struct VenueDetail {
        var isVeg: Bool
}

struct VenueDetailDTOMapper {

    static func map(_ dto: DetailDataDTO) -> VenueDetail {
     return VenueDetail(isVeg: dto.isVeg)
    }
}

In API Manager I have get the data from api and use above struct as follow

let venueDetail = VenueDetailDTOMapper.map(getDetail)

ViewModel:

enum VenueDetailVMTypes {
    case veueInfoInfo
}

protocol VenueDetailVMItems {
 var type: VenueDetailVMTypes { get }
}

struct VenueInfoViewModel: VenueDetailVMItems {
        var type: VenueDetailVMTypes {
            return .veueInfoInfo
            }
        var headerSection: VenueDetail
}

func cretaDataSource() {

    if let getVenueDetails = self.venueDetails {
        let vmType = VenueInfoViewModel(headerSection: getVenueDetails)
        arrayDataSource.append(vmType)
    }
}

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

       let headerView = UIView()

       let venueDetailVMItems = viewModel.arrayDataSource[section]
       switch venueDetailVMItems.type {
       case .veueInfoInfo:
           let headerCell = tableView.dequeueReusableCell(withIdentifier: kCellIdentifierVenueHeader) as! VenueHeaderTVCell
           headerCell.updateCellData(detail: (venueDetailVMItems as! VenueInfoViewModel).headerSection)

           headerCell.foodTypeHandler = { [weak self] (isOn) in
               guard let strongSelf = self else {
                   return
               }                
            strongSelf.viewModel.showOnlyVegMenu(shouldShowVeg: isOn)
            (venueDetailVMItems as! VenueInfoViewModel).headerSection.isVeg = isOn.  //Cannot assign to immutable expression of type 'Bool'
            strongSelf.tableView.reloadData()
           }
           headerView.addSubview(headerCell)
           break
       }
       return headerView
}
Ketan Shinde
  • 1,847
  • 4
  • 18
  • 38

3 Answers3

1

A structure is an aggregation of fields; if a particular structure instance is mutable, its fields will be mutable; if an instance is immutable, its fields will be immutable. A structure type must thus be prepared for the possibility that the fields of any particular instance may be mutable or immutable.

Please check this

So try to change let to be var

Make sure the the arrayDataSource is mutable user var not let

var arrayDataSource = [VenueInfoViewModel]()
Same7Farouk
  • 837
  • 9
  • 19
  • 1
    i appreciated but still its giving issue. Actually all i want to change viewModel.arrayDataSource[section].headerSection.isVeg = true – Ketan Shinde Nov 23 '19 at 08:25
1

Structs are value types, so each time you assign a struct, it makes a copy. You're treating it as a reference type. Stripping away all the as! casting, what you've done is:

let value = array[index]
value.someBool = true
reloadData()

Even if value were mutable (which it could be), that wouldn't do anything. value is a copy of array[index], not a reference to it. If you want it to be a reference, then you need to make it a reference type (a class).

You've used a protocol and a "type" identifier, where what I think you really wanted was an enum with associated data:

enum VenueDetail {
    case veueInfoInfo(VenueInfoViewModel)
}

With this, you get rid of all of the dangerous and complicated as! casting.

But all of that doesn't really change the issue you're describing. Either way (with a protocol or with an enum), what you need to do is:

var value = array[index]
// change value the ways you want; set the bool, etc.
array[index] = value
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Yes, i am aware of assigning a struct to other is just creating other copy. Alright i think its better to convert struct to class. The reason being i defined a enum cause i have pasted only one case, there are multiple sections of different types i need, so casting will be there. Actually all i want to change viewModel.arrayDataSource[section].headerSection.isVeg = true – Ketan Shinde Nov 23 '19 at 08:36
  • Enums can have their own data (associated data), so you don't need to cast. That's the point of my `veueInfoInfo` case; it includes an associated VenueInfoViewModel. You can also have another case that has a completely different type of associated data. With that, you just `switch` on the type. There's no need to `as!`. – Rob Napier Nov 23 '19 at 19:07
-1

After struggling i just create a method in viewModel that removes objects in array of type .venueInfo and reload, i know its kind of hack but time being i have no option. In case if somebody found better way, really appreciated

 func changeHeaderSwitch(isVeg: Bool) {

    arrayDataSource.removeAll { (venueDetailVMItems) -> Bool in
        return venueDetailVMItems.type == .veueInfoInfo
    }

    if var getVenueDetails = self.venueDetails {
        getVenueDetails.isVeg = isVeg
        let vmType = VenueInfoViewModel(headerSection: getVenueDetails, arrayMenuInfo: [])
        arrayDataSource.append(vmType)
    }
}
Ketan Shinde
  • 1,847
  • 4
  • 18
  • 38