Why self is deallocated when calling [unowned self]

Just to be clear about all the answers here–how you should fix this error depends on your needs.

The problem with the code in the original question is that self, which is a UIViewController, is being accessed from an asynchronously executed NSOperation block, and this is being done inside the completion handler of an asynchronous NSURLSessionTask.

By the time the runtime reaches self.textArea!.text, self has become nil. Under what circumstances will a UIViewController be deallocated? When you pop it out of the navigation stack, when it is dismissed, etc. I’m guessing that the code for btnSendRequestTapped(:) above isn’t complete and has a popViewController() somewhere.

The solutions are:

1: To use weak instead of unowned. The difference between the two is that weak means the captured object (self) may be nil and turns it into an optional, while unowned means that you are certain self will never be nil and you can access self as is. Using weak means unwrapping self before using it. If it’s nil, do nothing in the code.

{[weak self] in
    if let strongSelf = self {
        // ...
        strongSelf.textArea!.text = "123"
    }
}

2: The other solution is to cancel the NSURLSessionTask and its completion handler (which is dispatched into an NSOperationQueue property of NSURLSession called delegateQueue) if the UIViewController is being popped out of the navigation stack.

func btnSendRequestTapped() {
    // pop the view controller here...
    sessionTask.cancel()
    sessionTask.delegateQueue.cancelAllOperations()
}

3: Keep using [unowned self], but don’t pop the view controller until the operation block is done. I personally prefer this approach.

In short, keep self from being deallocated until you’re actually done with it.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)