简体   繁体   中英

Why cannot we use instance members in a closure definition?

Problem is the following compiler error:

"Instance member 'name' cannot be used on type 'Person'"

class Person {

    var name: String = "Amir"

    var myClosure = { (family: String) -> Void in
        print(name + " " + family)
    }

    func myFunc(family: String) -> Void {
        print(name + " " + family)
    }
}

The code inside myFunc and myClosure are the same, but I have compiler error on myClosure definition. As I know, basically closures and functions are the same. So what difference between them make the above limitation for closures?

The problem is that I'm trying to initialize a variable using an instance's variable while the instance itself has not been created yet. So the problem is not related to closure nature. The same problem does exist in the following code where I'm trying to initialize nickname with name instance property.

class Person {

    var name: String = "Amirreza"
    var nickname: String = name
}

As compiler says, "property initializers run before 'self' is available", so in the above code the self.name is not available to initialize nickname and this is the source of the problem.

Here the solution is to use "lazy" keyword before nickname definition. The lazy keywork defers the initialization of the nickname property to when it is accessed for the first time. Means when we are sure that the instance has been created and name property is available.

To read more about lazy refer to https://docs.swift.org/swift-book/LanguageGuide/Properties.html

So the correct form of above code is:

class Person {
    
    var name: String = "Amirreza"
    lazy var nickname: String = name
}

And the correct form of the my main question code would be:

class Person {

    var name: String = "Amirreza"

    lazy var myClosure = { [weak self] (family: String) -> Void in
        print(self!.name + " " + family)
    }

    func myFunc(family: String) -> Void {
        print(self.name + " " + family)
    }
}

Just note that we have to refer to properties inside closures with self explicitly like self.name. Meanwhile to avoid strong reference cycles we need to define a capture list in closure definition which in my example is [weak self]. By defining self as 'weak', self turns to an optional variable, so we have to unwrap it somehow which makes me to write self!.name in the closure.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM