Immutable value of type [Card] only has mutating values of name append - swift

I have a Card class and a Player class.
In my Player class I have a function that takes a [Card] array and adds a Card to it.
However, when I call...
myCardArray.append(myCard)
...I get the error
Immutable value of type [Card] only has mutating values of name append
I can't figure out why this is? Why would this be immutable?

without more code, we can only guess what happened
sounds like you are doing something like
func addCard(_ myCardArray: [Card]) -> [Card] {
let myCard = Card()
myCardArray.append(myCard)
return myCardArray
}
the problem is that myCardArray is immutable, as error message said, you can't modify it
you can declare myCardArray mutable use var
func addCard(var _ myCardArray: [Card]) -> [Card] {
let myCard = Card()
myCardArray.append(myCard)
return myCardArray
}
or create a mutable copy of it
func addCard(_ myCardArray: [Card]) -> [Card] {
let myCard = Card()
var mutableMyCardArray = myCardArray
mutableMyCardArray.append(myCard)
return mutableMyCardArray
}

Values in a dictionary can be updated using this method only if the dictionary is defined with the var keyword (that is, if the dictionary is mutable)
https://developer.apple.com/library/prerelease/ios/documentation/General/Reference/SwiftStandardLibraryReference/Dictionary.html

Related

How to return a dictionary by reference in Swift?

In the following example, you can see that the dictionary in the myStruct instance is not returned by reference in the getDictionary() function. Therefore, any changes made to the returned dictionary is only made to the copy. How can you return the dictionary by reference?
struct myStruct {
func getDictionary() -> [Int:String] {
return dictionary
}
private var dictionary = [1:"one"]
}
let c = myStruct()
var sameDict = c.getDictionary()
sameDict[2] = "two"
print(c.getDictionary(), sameDict)
[1: "one"] [1: "one", 2: "two"]
Dictionary is a value type, it is not your choice to do some type of data structure to be reference or value, it is a Swift's choice. Only closure, class and functions can be used as reference
In Swift, Array, String, and Dictionary
https://developer.apple.com/swift/blog/?id=10
Because the Dictionary is a struct type, the only way to do this is by passing it in a function using inout keyword (indicates that the parameter will be changed) like this:
struct MyStruct {
func getDictionary() -> [Int: String] {
return dictionary
}
mutating func updateDictionary(block: (inout [Int: String]) -> Void) {
block(&dictionary)
}
private var dictionary = [1:"one"]
}
var c = MyStruct()
c.updateDictionary {
$0[2] = "two"
}
print(c.getDictionary())
Update: After modification of the copy inside the function, before the return, the modified copy WILL assign to the global variable. #AlexanderNikolaychuk and #matt pointed out that in the comments. The behavior can be seen if you run the following code in a Playground:
struct MyStruct {
var some = 1
}
var myStruct = MyStruct() {
didSet {
print("didSet")
}
}
func pass(something: inout MyStruct) {
something.some = 2
print("After change")
}
pass(something: &myStruct)
this will print:
After change
didSet
Just saying.
It seems that you did not quite understand the difference between struct and class.
When you initialise the struct and assign it to c you have your first copy of it. Then you initialise a new variable, calling it sameDict and copying the value of the c dictionary to it. Then you modify the copy called sameDict. The dictionary of c is still the same.
Check this doc:
https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html
Stuct's are passed around by copying them. classes get referenced.

Is it possible to write mutating function in swift class?

I am able to write mutating functions in structure but not in class.
struct Stack {
public private(set) var items = [Int]() // Empty items array
mutating func push(_ item: Int) {
items.append(item)
}
mutating func pop() -> Int? {
if !items.isEmpty {
return items.removeLast()
}
return nil
}
}
In swift, classes are reference type whereas structures and enumerations are value types. The properties of value types cannot be modified within its instance methods by default. In order to modify the properties of a value type, you have to use the mutating keyword in the instance method. With this keyword, your method can then have the ability to mutate the values of the properties and write it back to the original structure when the method implementation ends.
If you change the struct to a class, just delete the keyword mutating wherever it appears.
That's because classes are reference types, and structures are value types.
struct TestValue {
var a : Int = 42
mutating func change() { a = 1975 }
}
let val = TestValue()
val.a = 1710 // Forbidden because `val` is a `let` of a value type, so you can't mutate it
val.change() // Also forbidden for the same reason
class TestRef {
var a : Int = 42
func change() { a = 1975 }
}
let ref = TestRef()
ref.a = 1710 // Allowed because `ref` is a reference type, even if it's a `let`
ref.change() // Also allowed for the same reason
So on classes, you don't need to specify if a function is mutating or not, because, even when defined with let variables, you can modify instance...
That's why the mutating key word has no meaning on classes.

Swift for var list.enumerated()

I have an array of objects whose type is a struct with mutating functions. So I got this code:
for (index, object) in objects.enumerated() {
otherArray[index] = object.someMutatingFunction(...)
}
This leads me to this error Cannot use mutating member on immutable value of type 'Blabla' which I can fix by adding var:
for var (index, object) in objects.enumerated() {
otherArray[index] = object.someMutatingFunction(...)
}
But then I get another warning Variable 'index' was never mutated; consider changing to 'let' constant which I don't know how to fix elegantly. The only idea is too add a new var variable. Is there anything else I can do to prevent this warning?
Prefix the object variable with the var keyword:
struct S {
mutating func f() { }
}
let array = [S(), S()]
for (index, var object) in array.enumerated() {
object.f()
}
Note as Hamish points out in the comment to this answer that the elements of the array will not be modified. Only the local copy of object inside the scope of the for loop can be modified.
If you want to modify array you have to declare it var outside the scope of the for loop, then assign to array indices.

How to implement read-only var with mutating get

I have a var
var soketTasksList:Set<SocketTask> {
get { return socketManager.tasksList }
}
I don't need to set, only get,
but I need do something like this
soketTasksList.remove(task)
but compiler says
Cannot use mutating member on immutable value is a get-only property
I tried to add the keyword 'mutating' to the get, but this isn't working. I also
tried to add 'mutating' to the var, but this isn't working either.
UPD
i dont undestand why do I need set?
if i do
func getSoketTasksList() -> Set<CXSocketTask> {
return socketManager.tasksList
}
i can
getSoketTasksList().remove(task)
why not with var?
i don't need to set, only get
Yes, you do need to set.
i need do something like this soketTasksList.remove(task)
That is a mutation. Mutating a value type like Set requires the ability to set. But you have cut off that possibility by making this a read-only computed variable.
UPD i dont undestand why do I need set? if i do
func getSoketTasksList() -> Set<CXSocketTask> {
return socketManager.tasksList
}
i can
getSoketTasksList().remove(task)
No you can't. Try it. Here's a playground test:
class CXSocketTask:NSObject{}
class SocketManager {
var tasksList = Set<CXSocketTask>()
}
let task = CXSocketTask()
let socketManager = SocketManager()
socketManager.tasksList.insert(task)
func getSoketTasksList() -> Set<CXSocketTask> {
return socketManager.tasksList
}
getSoketTasksList().remove(task)
The last line generates an error: "cannot use mutating member on immutable value: 'getSoketTasksList' returns immutable value".
You can use temporary variable for this purpose:
var list = soketTasksList
list.remove(task)
Note that underlying list (socketManager.tasksList in this case) remains untouched.
The only situation in which you can do this is if the actual mutating is done through something which is settable.
For example:
struct Person {
var age: Int = 1
mutating func setAge(a: Int) -> Int {
age = a
return a
}
var computedAge: Int {
mutating get {
setAge(a: 4)
return age
}
}
}
var person = Person()
print(person.computedAge) //Prints 4
This is by design

Return an array of tuples as AnyObject?

Is it possible to return an array of tuples as AnyObject? or would I have to encapsulate the tuple variable within a class then return that class?
Current structure
public typealias Changes = (id:Int!, cors:Bool!)
struct ClientReturn{
var error: NSError?
var json: JSON?
var mutableReturn: AnyObject?
var pageResults: PageResults?
}
class func Changes(api_key: String!, startDate: String?, endDate:String?,
completion: (ClientReturn) -> ()) -> (){
//content
}
Client.Changes(api_key, startDate: nil, endDate: nil){
apiReturn in
var aReturn = apiReturn;
var changesArray = [Changes]()
for(var i = 0; i < apiReturn.json!["results"].count; i++ ){
let json = apiReturn.json!["results"]
changesArray.append((id: json[i]["id"].int, cors: json[i]["cors"].bool))
}
//aReturn.mutableReturn = changesArray as! Changes
aReturn.mutableReturn = changesArray //ERROR (Cannot assign value of type '[Changes]' to type 'AnyObject?')
completionHandler(aReturn)
}
The only thing that can be cast up to AnyObject is a class (or a Swift struct that is bridged to some class).
A tuple is not a class. Thus, it cannot be cast up to an AnyObject.
The same thing applies to an array, though by a more roundabout route. An Array is not a class, but it is bridged to NSArray. But an NSArray can contain only classes, i.e. AnyObject elements. Thus, only an array of AnyObject-castables can be cast to AnyObject. A tuple is not a class... You take it from here.
Another way of looking at it is this: AnyObject is all about interchange with Objective-C. But tuples are a Swift-only feature: Objective-C knows nothing of them. Thus, an array of tuples cannot be cast to an AnyObject, because it cannot be handed to Objective-C.