Cannot Assign to Property: Function Call Returns Immutable Value

Cannot assign to property: function call returns immutable value

This is compiler's way of telling you that the modification of the struct is useless.

Here is what happens: when you call aStruct(), a copy of A is passed back to you. This copy is temporary. You can examine its fields, or assign it to a variable (in which case you would be able to access your modifications back). If the compiler would let you make modifications to this temporary structure, you would have no way of accessing them back. That is why the compiler is certain that this is a programming error.

Error - Cannot assign to value: function call returns immutable value

If you are setting value to the Label or textField then you need to simply set value (as String) to its property text, but you are try to convert the value to Int and then you assigning value of CatsROld to it, that is the reason you are getting this error. So simply write like AgeInCatYears.text = "\(CatsROld!)"

AgeInCatYears.text = "\(CatsROld!)"

Note: You are force wrapping CatsROld value with !, if you are 100% sure that it will not nil then its ok other wise you need to use if let or guard for optional wrapping.

Xcode error: 'Cannot assign to value: function call returns immutable value' in table views

It should be:

places[indexPath.row]["name"] as! String

As the type is Any and you need to specify it as String, since label expects Strings.

Cannot Assign to Value: Function call returns immutable value

The error is with the line:

cell.contentView.viewWithTag(1) = newData[indexPath.row]

Two problems. viewWithTag returns an optional UIView. You then attempt to assign a String to the UIView.

Assuming the view with tag 1 is a UILabel, you need something like this:

if let label = cell.contentView.viewWithTag(1) as? UILabel {
label.text = newData[indexPath.row]
}

This safely deals with accessing a possibly nil view (incase there is no actual view with a tag of 1) and attempting to cast that view to a UILabel (incase the view isn't actually a UILabel). If those conditions are met and you actually get a label, then you set the label's text property.

Unrelated to your issue (it will cause a new issue when you run your app), but it makes no sense to have your data array declared and setup in the cellForRowAt method and it makes no sense to hardcode a specific count in your numberOfRowsInSection method.

The proper thing to do would be to make newData a property of your view controller and set it up once instead of every time a cell is accessed. And then return its count in numberOfRowsInSection.

Is there any way to make the method return a mutable value?

The callAsFunction simply returns (a copy of the) Person, which is a value type. You cannot then mutate the property of it like that. It is equivalent to the following:

struct Person {
var name: String
}

Person(name: "Foo").name = "Bar"

That returns the same error:

Sample Image

If Person was a reference type, it would have worked, but not for a value type. And even if you took your value type, and first assigned it to a variable before mutating it, you would only be mutating your copy, not the original.

If you want the behavior you want, you would use a @dynamicMemberLookup as suggested by matt (+1) and outlined in SE-0195.


You said:

I can't use dynamicMemberLookup because I don't know what method or property there will be in Person. For example, there may be 100 methods and properties in Person (not only one name property as demonstrated), and it is impossible for me to write 100 subscript methods with dynamicMemberLookup.

You do not need “100 subscript methods.” It is the motivating idea behind @dynamicMemberLookup, namely that the properties will be determined dynamically. E.g., here is Person with two properties, but Group only has the one @dynamicMemberLookup.

struct Person {
var name: String
var city: String
}

@dynamicMemberLookup
struct Group {
var person: Person
subscript(dynamicMember keyPath: WritableKeyPath<Person, String>) -> String {
get { person[keyPath: keyPath] }
set { person[keyPath: keyPath] = newValue }
}
}

var group = Group(person: Person(name: "James", city: "New York"))
group.name = "Wong"
group.city = "Los Angeles"
print(group.person) // Person(name: "Wong", city: "Los Angeles")

If you want to handle different types, make it generic:

struct Person {
var name: String
var city: String
var age: Int
}

@dynamicMemberLookup
struct Group {
var person: Person
subscript<T>(dynamicMember keyPath: WritableKeyPath<Person, T>) -> T {
get { person[keyPath: keyPath] }
set { person[keyPath: keyPath] = newValue }
}
}

And

var group = Group(person: Person(name: "James", city: "New York", age: 41))
group.name = "Wong"
group.city = "Los Angeles"
group.age = 42
print(group.person) // Person(name: "Wong", city: "Los Angeles", age: 42)

Cannot modify my array - Cannot use mutating member on immutable value: function call returns immutable value

As the error tells you, your findPerson method is returning an immutable struct, so you can't edit it.

There are a few solutions to this -- two are included in the code sample below:

final class City {
var people = [Person]()

func addPetFor(id: UUID, newPets: [String]) {
guard let index = self.people.firstIndex(where: { $0.id == id }) else {
assertionFailure("Not found")
return
}
self.people[index].pets.append(contentsOf: newPets)
}

func addPetFor2(id: UUID, newPets: [String]) {
self.people = self.people.map {
if $0.id == id {
var personCopy = $0
personCopy.pets.append(contentsOf: newPets)
return personCopy
} else {
return $0
}
}
}
}

In both cases, the code has a reference to where the Person belongs in the people array, so it can modify it. Note that people also has to be var, not let, for the same reason -- it needs to be mutable.



Related Topics



Leave a reply



Submit