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.