5

I have a ViewModel class with a method like this:

func getUserSettings() {
   UserSettingsManager.getInfo { (result, error) in
     if error == nil {
        self.userData = result
     }
   }
}

This class viewModel is instantiated and then viewModel.getUserSettings() is called. Such method is calling a static method UserSettings.getInfo which is passed an @escaping closure to be called as completion. That closure is capturing viewModel (it's using self within it's body).

  1. What consequences does calling a static method have in terms of memory? How would that UserSettings class that is not instantiated be "deallocated"?

  2. Could a strong reference cycle happen in this particular scenario? If so, how should self be captured: weak or strong?

rmaddy
  • 314,917
  • 42
  • 532
  • 579
AppsDev
  • 12,319
  • 23
  • 93
  • 186
  • For #1 - objects get allocated and deallocated, not classes. Classes live as long as their enclosing module lives. – Cristik Jul 08 '18 at 18:53

1 Answers1

2

What consequences does calling a static method have in terms of memory? How would that UserSettings class that is not instantiated be "deallocated"?

In the context of your question, the fact that the function is static doesn't have any special memory implications. Static methods have just as much potential to create reference cycles as non-static ones.

As you said, if there is no instance of UserSettingsManager, no instance will be deallocated. This fact alone does not eliminate the potential for reference cycles.

Could a strong reference cycle happen in this particular scenario? If so, how should self be captured: weak or strong?

Depending on what happens within getInfo, this could create a reference cycle. While, it seems unlikely, it's impossible to say for sure with the snippet you've posted.

For clarification, I should mention that you're currently capturing self strongly, which is default. This means the closure increments the strong reference count of the instance of self so that it can successfully interact with that instance when the closure is eventually invoked. To override this behavior and avoid a reference cycle, you'd use [weak self].

Finally, to visualize your current approach, you could think of it in the following manner:

UserSettingsManagerclosureself

That's a nice clean chain! A reference cycle would only occur if one of those links gained a reference back to another.

woodcutting
  • 271
  • 1
  • 9
  • 1
    Thanks for your answer. So, since `viewModel` is not holding a reference to `UserSettingsManager`, a strong reference cycle can't occur... but what would happen if the `viewController` has been deallocated when the closure is executed and `self` is called? Can the capture lists be also used in scenarios like that, even if it is not for preventing a strong reference cycle? – AppsDev Jul 09 '18 at 06:40
  • 1
    Because the closure holds a strong reference to the `viewModel`, the `viewModel` will not be deallocated until the closure is executed or otherwise released. This is another reason why you might use `{ [weak self]` at the start of the closure: to allow the `viewModel` to deallocate without waiting for this closure to decrement its retain count. – woodcutting Jul 09 '18 at 11:42