Reputation: 555
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
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:
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
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