Minon Weerasinghe
Minon Weerasinghe

Reputation: 342

Making immutable function parameter mutable

I have a method that takes in an array and inside that method I want to append some objects to that array. Since Swifts parameters to functions are immutable I'm unable to do so. It is vital that I maintain the same reference to that array since that array is going to be used in a table view to display data. My code is as follows:

class func loadData(tableView: UITableView, results: [LocationInfo]){
    print("\n Data fetch started \n")
    let root = FIRDatabase.database().reference()
    let locationSummary = root.child("LocSummary")

    locationSummary.observeSingleEvent(of: .value,with: { (snapshot) in
        for item in snapshot.children{
            let locationInfo = LocationInfo(snapshot: item as! FIRDataSnapshot)
            results.append(locationInfo) // ERROR IS WITH THIS

        }
        DispatchQueue.main.async {
            print("\n data fetch completed \n ")
            tableView.reloadData()
            print("After on completion method \(results.count)")

        }
    })
}

How can I append data to this array while maintaining the same reference.

Upvotes: 2

Views: 629

Answers (3)

Marcel Voss
Marcel Voss

Reputation: 380

You could either make that array available to all functions by declaring it as a property (and removing the class modifier of your function) or you could define your function's parameter as an in-out parameter. By adding the inout keyword right before the parameter's type, you can make the parameter mutable by keeping the reference to the passed array.

Nevertheless, I would recommend you to make your array into a property – simply because it's easier and, in my opinion, better maintainable.

Upvotes: 2

matt
matt

Reputation: 534925

It is vital that I maintain the same reference to that array

That desire is incoherent. Consider: locationSummary.observingSingleEvent takes a function that will be executed asynchronously, that is, at some unknown future time. But that is where you want to change this array through the "same reference". It is madness to say that you will come back at some unknown future time with a maintained reference to some persistent variable and, poof, out of the blue, change it.

Therefore, this [Location] cannot be a parameter to loadData.

I would also suggest asking yourself why this needs to be a class function. That means there is no instance, so there is no meaningful place to store a persistent variable anyway!

If this is were a normal instance method (i.e. delete class), then the problem would be easily solved: make your [Location] an instance property, and now you can refer to it from your asynchronous function. Be careful (1) to get and set it only on the main thread, and (2) not to get yourself into a retain cycle by accidentally retaining self (you will want to say [weak self] in).

Upvotes: 1

Daniel T.
Daniel T.

Reputation: 33967

First point: You can't "maintain the same reference to that array" because that isn't a reference to an array. It is a temporary value that exists only until the end of the method.

I see you have a table view. In order to keep the LocationInfo objects for display in the table view, you will need to assign (i.e. copy) results into a parameter that you can then use to populate the table view. Something as simple as this might work... It depends on what the rest of your code looks like.

var tableViewData: [LocationInfo] = []

// note, this isn't a class func anymore.
func loadData(results: [LocationInfo]){
    print("\n Data fetch started \n")
    tableViewData = results
    let root = FIRDatabase.database().reference()
    let locationSummary = root.child("LocSummary")

    locationSummary.observeSingleEvent(of: .value,with: { (snapshot) in
        for item in snapshot.children{
            let locationInfo = LocationInfo(snapshot: item as! FIRDataSnapshot)
            tableViewData.append(locationInfo)

        }
        DispatchQueue.main.async {
            print("\n data fetch completed \n ")
            self.tableView.reloadData()
            print("After on completion method \(results.count)")

        }
    })
}

Upvotes: 0

Related Questions