Escaping Closure and Mutating Self Explained in Swift
Image via Author

Escaping Closure and Mutating Self Explained in Swift


Let’s begin by analysing the following code to learn why it throws an error.


struct User {
    
    var name: String
    
    init(_ userName: String) {
        self.name = userName
    }
    
    mutating func changeUserName(_ newName: String) {
        self.name = newName
    }
    
    func escapingFunction(_ x: @escaping () -> ()) {
        x()
    }
    
    mutating func callEscapingFunction() {
        escapingFunction {
            self.changeUserName("Ijeoma") // Escaping closure captures mutating 'self' parameter
        }
    }
}
        

Here, the User struct has a name property of type String, an initializer and three methods.

The first method is a mutating method named changeUserName, it accepts a single parameter of type string. In the body of the method, the name property is assigned to the value passed to the method.

The second method, escapingFunction, accepts a single parameter and the parameter type is an escaping function that returns void.

The third method, callEscapingFunction, is another mutating method and it accepts no parameters. Inside the method, escapingFunction is called and changeUserName is passed as an argument with the value “Ijeoma.

This code causes the following error:


// error: Escaping closure captures mutating 'self' parameter        

The error happens because we’re passing a mutating instance property of a struct as an argument for an escaping function (closure).

As User is a struct, when we mutate its instance properties Swift secretly replaces the instance with a different instance that holds the updated property value.

The error is thrown because the closure will later attempt to execute on an instance that no longer exists — hence the cryptic message, “captures mutating self.

This error will not occur if User was a class.


class User {
    
    var name: String
    
    init(_ userName: String) {
        self.name = userName
    }
    
    func changeUserName(_ newName: String) {
        self.name = newName
    }
    
    func escapingFunction(_ x: @escaping () -> ()) {
        x()
    }
    
    func callEscapingFunction() {
        escapingFunction {
            self.changeUserName("Ijeoma")
        }
    }
}

let myUser = User("Emily")
print(myUser.name) // Emily
myUser.callEscapingFunction()
print(myUser.name) // Ijeoma
        

Now, the error is gone because Swift classes can be mutated in place.

要查看或添加评论,请登录

Ijeoma Nelson的更多文章

社区洞察

其他会员也浏览了