Reference to property in closure requires explicit 'self.' to make capture semantics explicit
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();
}
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.
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