简体   繁体   中英

Why would I ever use unowned self?

The following pattern happens a lot in iOS apps:

class MyViewController: UIViewController {
    let myModel = MyModel()

    override func viewDidLoad() {
        super.viewDidLoad()
        myModel.foo() { [***] in
            // use self here
        }
    }
}

class MyModel {
    public func foo(complete: () -> Void) {
        // do something
        complete()
    }
}

The consensus is to use either [unowned self] or [weak self] in place of the [***] , unowned when you can guarantee that self will not be nil at the time of completion and weak when you're not sure the reference will still be valid.
What I don't understand is why I would ever risk using unowned, maybe I'm sure that right now the reference will never be nil, but that can change in the future. I could also have overlooked an edge-case, mistakes happen. I could just as easily always use weak, and put a guard at the top of the closure to be able to use self without a ! or ?.
What is the use of unowned? Is it faster than weak+guard? Is it syntactic sugar? It seems to go against Swift's philosophy of protecting the developer against common mistakes that can cause crashes.

unowned has a marginal performance advantage over weak because the runtime doesn't have to keep track of the reference to turn it into nil when the object goes away.

In respect of retain cycles (well, strong reference cycles), neither weak nor unowned creates a strong reference (in pre ARC terms, neither increments the retain count) so there is no danger of a reference cycle, in fact, that is why you need to specify weak or unowned for self in closures.

Also, with unowned you can use the reference as a non optional, so you don't have to put any code in the closure to unwrap it.

I always use weak unless there is a really good performance reason not to.

NB in your code, I do not think either is necessary because the closure is not escaping ie The reference to it taken in the function call foo does not persist after the end of foo 's scope.

I believe that using unowned adds to the risk than using weak self. Mistakes do happen and one example of it would be starting an API call in a view controller, let it wait for the response to arrive and suddenly popping that view controller may cause it to get deallocated (If there are no strong references to it). By the time when the response arrives, our view controller object would be gone, and our app will crash on our face. It is up to us to decide which one to use in which place.

As Jeremy pointed out, unowned does not have the responsibility to keep track of the reference count, so it has ever so slight performance advantage over strong and weak.

As per Swit Programming Guide: Automatic Reference Counting

An unowned reference is expected to always have a value. As a result, ARC never sets an unowned reference's value to nil, which means that unowned references are defined using nonoptional types.

In short, weak are optionals, where unowned are not.

An simple example of using unowned reference in navigation controller:

class RegisterViewController: UIViewController {
    lazy var navigatinRightBarItemsCount: Int = { [unowned self] in
        guard let navigationController = self.navigationController else { return 0 }
        guard let topItem = navigationController.navigationBar.topItem else { return 0 }
        guard let rightBarButtonItems = topItem.rightBarButtonItems else { return 0 }
        return rightBarButtonItems.count
        }()

    override func viewWillAppear(_ animated: Bool) {
        print("Navigation bar right side items count: ", navigationRightBarItemsCount)
    }
}

This means that RegisterViewController must be initialized than we can safely get self. navigationController and from here to get items count. If you try to make it as [weak self], XCode will complain because self(viewcontroller) can be nil, so we must use unowned.

Another example with UIBarButtonItem

lazy final private var filterNavigationBarItem: UIBarButtonItem = { [unowned self] in
    return UIBarButtonItem(image: #imageLiteral(resourceName: "filter_icon"),
                           style: .plain,
                           target: self,
                           action: #selector(segueToFilterJobs))
    }()

What we see here? See the target which stands for " The object that receives the action message. " which means that object that receives the action message can not be nil and must be initialized.

A very nice explanation from drewag in this article.

The only time where you really want to use [unowned self] or [weak self] is when you would create a strong reference cycle. A strong reference cycle is when there is a loop of ownership where objects end up owning each other (maybe through a third party) and therefore they will never be deallocated because they are both ensuring that each other stick around.

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