Jordi Daiku Serra Jordi Daiku Serra - 1 year ago 80
iOS Question

Swift Mutation inside switch with associated values

I have these structs I want to mutate:

public struct CheckoutViewModel {
var sections: [Section]
var total: String

public struct Section {
var title: String
var description: String
var kind: Kind
var expandState: ExpandState

enum Kind {
case products([ProductOrderViewModel])
case shippingMode(SelectableArray<ShippingMode>)
case shippingTarget(SelectableArray<ShippingKind>)
case billingAddress(SelectableArray<Address>)
case payment(SelectableArray<PaymentProvider>)
case promoCode(String?)
case legalAdvice(userAccepted: Bool)

struct SelectableArray<T> {
var selectedIndex: Int?
let options: [T]

init(options: [T]) {
self.options = options
self.selectedIndex = nil

mutating func select(atIndex: Int) throws -> T {
guard atIndex < options.count else {
throw SelectableArrayError.outOfBoundsIndex
selectedIndex = atIndex
return options[atIndex]

var selectedElement: T? {
guard let selectedIndex = selectedIndex else { return nil }
return options[selectedIndex]

I want to use this mutating func select() method inside SelectableArray, I am calling it from a chain of mutating functions (because Sections is nested inside a struct)

extension CheckoutViewModel {
mutating func select(atIndexPath indexPath: IndexPath) {
sections[indexPath.section].select(atIndex: indexPath.row)

extension CheckoutViewModel.Section {
mutating func select(atIndex idx: Int) {
switch kind {
case .shippingMode(var modes):
do { _ = try idx) } catch { return }
return nil
dump(self) // Here self hasn't changed

The problem is that the CheckoutViewModel struct is never mutated. I am guessing that switch is not a mutating function, so
var modes
inside that switch is non mutable and then it does not matter if the following functions mutate anything. The workaround I managed to do is this:

mutating func select(atIndex idx: Int) {
switch kind {
case .shippingMode(var modes):
do {
_ = try idx)
self.kind = .shippingMode(modes)
} catch { return }

Do you have any oher solution to this problem? Is there any sort of
mutating switch
function that I can use?

Answer Source

According to The Swift Programming Language:

A switch case can bind the value or values it matches to temporary constants or variables, for use in the body of the case. This behavior is known as value binding, because the values are bound to temporary constants or variables within the case’s body.

Changes to such a temporary variable (e.g. the modes variable) do not affect the contents of the enum that is being switched on (e.g. kind).

For your first approach to work you would indeed need a different sort of switch statement that creates a reference to the enum's associated value, allowing you to modify that value in place. Such a statement doesn't exist in Swift 3.0.1.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download