Mutating self (struct/enum) inside escaping closure in Swift 3.0

In swift 2.2, We could mutate a struct or enum within a closure, when it was inside a mutating function. But in swift 3.0 its no longer possible. I get the following error

closure cannot implicitly captured a mutating self parameter

  • Programmatically place partial image over another in UIView using Swift 3
  • URLSession on Linux giving different result than on iOS
  • How to play a sound in Swift?
  • UITableView Pagination - Bottom Refresh to Load New Data in Swift
  • “hidden” vs #keyPath(UIView.isHidden)
  • What is the selector syntax for Core Data custom policies?
  • Here is a code snippet,

    struct Point {
        var x = 0.0, y = 0.0
    
        mutating func moveBy(x deltaX: Double, y deltaY: Double) {
            x += deltaX
            y += deltaY
    
            test { (a) -> Void in
                // Get the Error in the below line.
                self.x = Double(a)
            }
    
        }
    
        mutating func test(myClosure: @escaping (_ a: Double) -> Void) {
            myClosure(3)
        }
    }
    

    I get that value types are not supposed to be mutable. I have cases, where I do have to modify one variable in the struct within one of the functions, when I receive the API response. (In the completion closure)

    Is what I was doing in swift 2.2, impossible or is there way to accomplish this?

    3 Solutions Collect From Internet About “Mutating self (struct/enum) inside escaping closure in Swift 3.0”

    The problem is that @escaping closures can be stored for later execution:

    Escaping Closures

    A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns. …

    One way that a closure can escape is by being stored in a variable that is defined outside the function….

    Since the closure can be stored and live outside the scope of the function, the struct/enum inside the closure (self) will be copied (it is a value) as a parameter of the closure. And, if it was allowed to mutate, the closure could have an old copy of it, causing unwanted results.

    So, in answer to your question, you cannot; unless you are able to remove “@escaping” (not your case because it’s a 3rd party API)

    Yeah, you can do something like this.

    struct Point {
    
        var x = 0.0, y = 0.0
    
        mutating func moveBy(x deltaX: Double, y deltaY: Double) {
            x += deltaX
            y += deltaY
    
            test { (a) -> Void in
    
                self.x = Double(a)
            }
        }
    
        mutating func test(myClosure: (_ a: Double) -> Void) {
            myClosure(3)
        }
    }
    

    Struct is value type. So when use as Model or ModelView, you can make up a closure with new Value to VC.

    struct Point {
        var x = 0.0, y = 0.0
    
        mutating func moveBy(x deltaX: Double, y deltaY: Double) {
            x += deltaX
            y += deltaY
    
            test { [x, y](a) -> Point in
                // Get the Error in the below line.
                return Point(x: Double(a), y: y)
            }
    
        }
    
        mutating func test(myClosure: @escaping (_ a: Double) -> Point) {
            self = myClosure(3)
        }
    }