forEach results in $0 is immutable error

You have an array of items that implement a protocol. If you don’t tell Swift that this is an AnyObject protocol (or class protocol in earlier versions of Swift), it will assume that it can be implemented by a struct.

In a forEach loop, you will essentially have a let variable (called $0 by default) assigned to each value in the array in turn. If you have an array of objects (instances of a class), then you can modify properties of that item. If you have an array of struct items, then those will be immutable. If you have an array of items that implement a protocol, then Swift will treat them as the more restrictive struct unless you add : AnyObject (or : class in earlier versions of Swift) to your protocol definition.

For example:

protocol Xyzzy: AnyObject {
    var prop: Int? { get set }
}

class Fred: Xyzzy, CustomStringConvertible {
    var description: String { String(describing: prop) }
    var prop: Int? = 17
}

let objects: [Xyzzy] = [Fred(), Fred(), Fred()]

print(objects)  //  [Optional(17), Optional(17), Optional(17)]

objects.forEach { $0.prop = nil }

print(objects)  // [nil, nil, nil]

Your workaround:

protocols.forEach
{
    var protocol = $0

    protocol.prop = nil
}

works for class objects because it creates a new var pointer to the object, and then that allows you to modify the object. Note, this workaround only works for instances of classes. If your protocol is implemented by a struct, then the new var will be a new copy of the struct item, and the original ones in the array will not be changed.

Leave a Comment

tech