I have a question about ARC in Swift, please take a look at the following code.
When SecondViewController is presented, the alert will pop up, and once you click "OK" button,
SecondViewController will dismiss. Here is my question, in my opinion, SecondViewController retain UIAlertController, UIAlertController retain UIAlertAction, and UIAlertAction calls
the function back() in SecondViewController. So it may cause retain cycle in this case, and it does cause retain cycle according the video here(around 8:30). However, when SecondViewController dismiss, the deinit function is called, and it does print SecondViewController is being deinitializing. So I'm confused which one is correct.
class SecondViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .orange
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let alert = UIAlertController(title: "Hi", message: "everyone", preferredStyle: .alert)
let ok = UIAlertAction(title: "OK", style: .default) { _ in
self.back()
}
alert.addAction(ok)
self.present(alert, animated: true)
}
private func back() {
dismiss(animated: true)
}
deinit {
print("SecondViewController is being deinitializing")
}
}
And here is another example. I run the following code in playground, and the deinit function is still called when I set test equals to nil. I don't understand why it would be called without adding [weak self] before the value in hehe() function.
class Test {
var int: Int = 0
func hehe() {
fetchAPI(input: 3) { value in
self.int = value
}
}
func fetchAPI(input: Int, completion: @escaping (Int) -> Void) {
completion(input)
}
deinit {
print("Test in being deinitializing")
}
}
var test: Test? = Test()
test?.hehe()
test = nil
I have taken a look at the Swift documentation, but couldn't find the similar example.
I expect the deinit function will not be called until I add [weak self]. I know ARC does not work on value type, but still not sure about it. Does anyone could explain more about this? Thanks.
[Update]
Here's the third example, and it will cause retain cycle. I guess the reason is because UIAlertController and UIAlertAction retains each other, and UIAlertAction also retains SecondViewController. So when UIAlertController dismiss, the closure in UIAlertAction is still exist, which cause retain cycle. Am I correct?
class SecondViewController: UIViewController {
var array: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .orange
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let alertController = UIAlertController.init(title: "Test", message: nil, preferredStyle: .alert)
alertController.addTextField(configurationHandler: nil)
let alertAction = UIAlertAction.init(title: "OK", style: .default) { (action) in
let text = alertController.textFields![0].text
self.array.append(text!)
}
alertController.addAction(alertAction)
self.present(alertController, animated: true, completion: nil)
}
deinit {
print("SecondViewController is being deinitializing")
}
}