1

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.

Shabnam Siddiqui
  • 579
  • 4
  • 13
Bartender1382
  • 195
  • 1
  • 10
  • `struct` is pass by value. So when you pass a `struct` as an parameter, you will only get a read-only copy of the original `struct`, which in this case, a `let` constant. – koropok May 06 '22 at 05:12

2 Answers2

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.

MBT
  • 1,381
  • 1
  • 6
  • 10
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
    }
    

    }

Ghulam Mustafa
  • 196
  • 1
  • 7
  • Both are great answers. Would there be a reason for doing one over the other? Passing the pointer vs. muting function? – Bartender1382 May 06 '22 at 17:37
  • 1
    @Bartender1382 It depends on requirements. Classes are references type, if you assign one object to another variable it does not make new object it just create a new reference to same object so if you change the object from anywhere it will reflect all over the places where you are using it. On the other hand struct assures that whenever you assign an object to new variable it makes it's copy therefore struct is not mutable and cannot change it's state, in order to change something in struct you need to specify mutating keyword. – Ghulam Mustafa May 18 '22 at 08:07