Carl Hung
Carl Hung

Reputation: 555

When should i use capture list in closure, and when to use weak vs. unowned?

i am reading a book, a method in viewcontroller:

func addNewWord() {
    // create our alert controller
    let ac = UIAlertController(title: "Add new word", message: nil, preferredStyle: .alert)
    // add two text fields, one for English and one for French
    ac.addTextField { textField in
        textField.placeholder = "English"
    }
    // ac.addTextField { (textField) in // also works.
    ac.addTextField { (textField: UITextField) in
        textField.placeholder = "French"
    }
    // create an "Add Word" button that submits the user's input
    let submitAction = UIAlertAction(title: "Add Word", style: .default) {
        [unowned self, ac] (action: UIAlertAction!) in
        // pull out the English and French words, or an empty string if there was a problem
        let firstWord = ac.textFields?[0].text ?? ""
        let secondWord = ac.textFields?[1].text ?? ""
        // submit the English and French word to the insertFlashcard() method
        self.insertFlashcard(first: firstWord, second: secondWord)
    }
    // add the submit action, plus a cancel button
    ac.addAction(submitAction)
    ac.addAction(UIAlertAction(title: "Cancel", style: .cancel))
    // present the alert controller to the user
    present(ac, animated: true)
}

I don't understand why ac doesn't need to mark unowned?

when is the best time to mark unowned or weak?

thanks.

Upvotes: 0

Views: 726

Answers (2)

BaseZen
BaseZen

Reputation: 8718

In most cases, self is a View Controller or some other semi-persistent object. View Controllers are fairly expensive memory-wise, given how much state they govern, including the view hierarchy. When a View Controller is dismissed from the App's navigation flow, its resources really need to be freed. So the design pattern is to always pay attention to self, so avoid excess references to the VC. For example if the closure lives on for a long time, but the VC is dismissed from navigation, the VC and its associated resources chew up memory uselessly: a memory leak.

In contrast, local variables to a function only have a longer life with respect to the contained closure -- their initial reference count is guaranteed to decrement as soon as the containing function exits. So the closure alone can manage references to it and not be concerned with its App-wide lifecycle.

owned vs. weak is really a different question. It depends on your App design -- there's no formulaic answer. unowned, like weak, does not increment the retain count of captured objects in the closure. However that leaves the possibility that the captured object ends up with a retain count of 0, and will be deallocated before the closure runs, risking a crash. So you need to be sure, if you say unowned, that something else is always taking ownership responsibility. In contrast, declaring self as weak acknowledges the object as volatile, and forces you to check (if let...) if the object was deallocated.

Also, I didn't check the related links thoroughly, but I'm sure I'm repeating a lot of what has been said before. Read the highly upvoted posts first.

Shall we always use [unowned self] inside closure in Swift

optional closure property in Swift

EDIT, PERHAPS THE REAL ISSUE

Your book's code makes no sense, because the manual specifically says:

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html

This distinction [leaving a variable out of the capture list entirely, versus including it, but with no weak/unowned designation] is not visible when the captured variable’s type has reference semantics. For example, there are two things named x in the code below, a variable in the outer scope and a constant in the inner scope, but they both refer to the same object because of reference semantics.

In other words, because ac is a reference type object, including it "bare" in the capture list does nothing.

I believe the book is in error, and it should say [unowned self, unowned ac].

My reasoning is: UIAlertController ac -> strong reference to submitAction (via addAction) -> strong reference to anonymous closure -> strong reference to ac. Unless one of those is internally declared as weak just for this purpose, unowned ac is necessary. Too bad some of that is closed source and we cannot check for sure. The documentation is not specific so we have to assume those are all stored strongly in the library code.

Upvotes: 2

Patrick Tescher
Patrick Tescher

Reputation: 3447

Your text field blocks are called immediately and don't reference self or your UIAlertController.

The action blocks are called later (when the user clicks a button) and thus need to store references to self or ac. By storing this reference you can introduce Circular References which can lead to memory leaks. Essentially if you use a strong reference to ac in the action block then the block points to the UIAlertController and the UIAlertController points to the block and nothing ever gets released.

Upvotes: 1

Related Questions