Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reference to property in closure requires explicit 'self.' to make capture semantics explicit

Tags:

swift

swift2

Trying to load HTML from a web service into a webview, I get this error:

Reference to property 'webviewHTML' in closure requires explicit 'self.' to make capture semantics explicit

What does it mean, and how can I load the HTML string into my web view?

func post(url: String, params: String) {

    let url = NSURL(string: url)
    let params = String(params);
    let request = NSMutableURLRequest(URL: url!);
    request.HTTPMethod = "POST"
    request.HTTPBody = params.dataUsingEncoding(NSUTF8StringEncoding)

    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
        data, response, error in

        if error != nil {
            print("error=\(error)")
            return
        }

        var responseString : NSString!;
        responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
        webviewHTML.loadHTMLString(String(responseString), baseURL: nil)
    }
    task.resume();
}
like image 972
ThisClark Avatar asked Sep 19 '15 07:09

ThisClark


2 Answers

Usage of self is an explicit acknowledgement of referencing (also known as capturing) a construct (class/struct/enum) in a closure, the implication being that self will not be deallocated until said closure is deallocated.

When you think about it, self could have very well been inferred, (as it is, when you use webviewHTML outside a closure), but it is an intentional design decision not to infer it, as Swift is a safety first language.

like image 169
Vatsal Manot Avatar answered Oct 19 '22 07:10

Vatsal Manot


Before answering this question you must know what a memory cycle is. See Resolving Strong Reference Cycles Between Class Instances From Apple's documenation


Now that you know what a Memory cycle is:

That error is Swift compiler telling you

"Hey the NSURLSession closure is trying to keep webviewHTML in the heap and therefor self ==> creating a memory cycle and I don't think Mr.Clark wants that here. Imagine if we make a request which takes forever and then the user navigates away from this page. It won't leave the heap.I'm only telling you this, yet you Mr.Clark must create a weak reference to the self and use that in the closure."

We create (ie capture) the weak reference using [weak self]. I highly recommend you see the attached link on what capturing means.

For more information see this moment of Stanford course.

Correct Code

func post(url: String, params: String) {

    let url = NSURL(string: url)
    let params = String(params);
    let request = NSMutableURLRequest(URL: url!);
    request.HTTPMethod = "POST"
    request.HTTPBody = params.dataUsingEncoding(NSUTF8StringEncoding)

    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
        [weak weakSelf self] data, response, error in

        if error != nil {
            print("error=\(error)")
            return
        }

        var responseString : NSString!;
        responseString = NSString(data: data!, encoding: NSUTF8StringEncoding) 

        weakSelf?.webviewHTML.loadHTMLString(String(responseString), baseURL: nil)
        // USED `weakSelf?` INSTEAD OF `self` 
    }
    task.resume();
}

For in depth details, see this Shall we always use [unowned self] inside closure in Swift

like image 33
mfaani Avatar answered Oct 19 '22 05:10

mfaani