Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

forEach results in $0 is immutable error

protocols.forEach { $0.prop = nil } 

results in:

Cannot assign to property: '$0' is immutable 

I worked around this with:

protocols.forEach {     var protocol = $0      protocol.prop = nil } 

But why is the compiler okay with this? I would expect it could figure this out.

like image 775
meaning-matters Avatar asked Sep 05 '16 12:09

meaning-matters


1 Answers

You have an array of items that implement a protocol. If you don't tell Swift that this is a class protocol, 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 : class to your protocol definition.

For example:

protocol Xyzzy: class {     var prop: Int? { get set } }  class Fred: Xyzzy, CustomStringConvertible {     var description: String { return "\(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.

like image 153
vacawama Avatar answered Sep 28 '22 07:09

vacawama