'Trying to change a variable set as var, but can't change it within the structure it exists

Working on the upload section of my app, after uploading a file from the iPhone, the server puts the file through multiple processing stages.

I use a struct that keeps the uploaded file info, scripts to call, etc.

struct XFile {
    let key: String
    let filename: String
    let data: Data
    var mimeType: String?
    let url: URL
    var toUrl : URL?
    var upStatus : UpStatus?
    var fileStage : Int32?
    
    init(fileUrl: URL, key: String) {
        //setting multiplle variables here
        //set the initial fileStage to 0
        self.fileStage = 0
    }
}

I declare and create my XFile structure from within my UIViewControler with:

class UploadFile : UIViewController, URLSessionDelegate {
    var xFile : XFile?

    //buttonAction
    xFile = XFile(fileUrl: url, key: "filename")
}

When I attempt to change xFile.fileStage from within XFile itself, or within the UIViewControler that created that instance of XFile, I have no problems.

However, if I pass xFile as a parameter into a different class's function, I cannot change the variable xfile.fileStage without getting the following compiler editor:

Cannot assign to property: 'xFile' is a 'let' constant

However, I do not get the error if I send xFile as a reference to xFile to that 3rd class.

getService.start(upFile: &xFile!, upLoadInvoiceClass: self)

Is this normal behavior?
Is it that passing xFile in a function sends a copy?
I just want to make sure I am understanding AND using it properly.



Solution 1:[1]

This is because you are using struct not class. Struct makes a copy of itself when you pass it through the functions.

There are two solutions:

  1. Either change the struct to class.

  2. Make a mutating method in struct which can change the fileStage

    struct XFile { let key: String let filename: String let data: Data var mimeType: String? let url: URL var toUrl : URL? var upStatus : UpStatus? var fileStage : Int32?

    init(fileUrl: URL, key: String) {
        //setting multiplle variables here
        //set the initial fileStage to 0
        self.fileStage = 0
    }
    
    mutating func updateFileStage(_ stage: Int32) {
        self.fileStage = stage
    }
    

    }

Solution 2:[2]

Is this normal behavior?

Yes, because all parameters passed into a swift function are constants. You can't change them. If you want then pass the parameter as inout. Here is an example.

func doubleInPlace(number: inout Int) {
    number *= 2
}

var myNum = 10 
doubleInPlace(number: &myNum)
print(myNum) // value is 20

Is it that passing xFile in a function sends a copy?

Yes, because struct instances are value types. It will send a copy when passed as a parameter in a function. You can check this.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Ghulam Mustafa
Solution 2 MBT