4

In Swift Collections are pass by value by default and we can user inout to make it pass by reference in function arguments but how can we do it in closure capture variables?

var list = [1, 2, 3]
func edit(inout list: [Int]) {
    list.append(4)
    dispatch_async(dispatch_get_main_queue()) {
        list.append(5)
    }
}
edit(&list)
...// after dispatch_async was executed 
NSLog("\(list)")

Result will be [1, 2, 3, 4]

How can I modify the original variable () inside closure?

UPDATE:

Actually I have a workaround to handle this case by putting the array into an object so I can pass this object to the function by reference and we can modify the same array instance inside the function. but I want see any clever way to archive that

1 Answer 1

2

For getting a variable escape from a closure you need @escaping, check this out. A workaround is to put a completion function as an argument rather than an inout variable.

class MyClass {
    static func edit(_ list: [Int], _ completion: @escaping ([Int]) -> ()) {
        var list = list
        list.append(4)
        DispatchQueue.main.async() {
            list.append(5)
            completion(list)
        }
    }
}

var myList = [1, 2, 3]
MyClass.edit(myList) { (list) in
    myList = list
    print("My list after editing: \(myList)")
}
print("My list without editing: \(myList)")

Note: The above example is for Swift 3 where inout parameters are not allowed to be captured in closures. Based on your post, you may be using a lower version of Swift where you might be able to use inout rather than setting a mutable copy of the list: var list = list. However, the logic is very similar.

For more information, check the Limiting inout capture to @noescape contexts in Swift evolution:

Swift's behavior when closures capture inout parameters and escape their enclosing context is a common source of confusion. We should disallow implicit capture of inout parameters except in @noescape closures.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for your response but any chance that to implement it without access any instance variables inside the function? you can treat it like a static function
Thanks, Your answer is a way to get back the new copy of array and we can update the instance array variable in the completion closure. but I want to know any chance that "directly" modify the original array after passing into a function . sorry for my bad explanation in the question. I have tried your code and the result for the global list variable is still [1, 2, 3]
I updated my answer again to use myList rather than list to make it less confusing. To get the edited myList you need to wait until the edit gets completed. If you want to edit the myList directly, just make it as a class-level variable in your class and use something like self.myList in the closure. As you don't want to go for that approach at the first place, you cannot modify the myList directly. For the reason, check out the link I provided in my answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.