3

Since viewdidload() is only called once in the lifecycle of that instance of the UIViewController object, does that mean that this example below is a "bad practice" since setBackgroundColor(), a function that is only called once, is unnecesarrily loaded into the memory of the entire class when it really should just exist entirely (defined and called) inside viewdidload()? Or in terms of efficiency, does it not matter where setBackgroundColor() is defined and called?

class MasterViewController: UIViewController {

    func setBackgroundColor() {
        self.view.backgroundColor = UIColor.green
    }

    // Do any additional setup after loading the view, typically from a nib.
    override func viewDidLoad() {
        super.viewDidLoad()

        setBackgroundColor()

    }

    // Dispose of any resources that can be recreated.
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

}
youareawaitress
  • 387
  • 2
  • 17

4 Answers4

3

Making a function local to a method changes its scope, but not the lifetime of code compiled from it. Same goes for methods of the class: their binary codes are not managed individually, at least not at this time. This is not a big deal, though, because executable code of your function is relatively tiny.

What matters here is that the function name is not visible in its outer scope, letting other methods define their own setBackgroundColor() functions unrelated to the one defined within viewDidLoad:

override func viewDidLoad() {
    super.viewDidLoad()
    // Nested function definition
    func setBackgroundColor() {
        self.view.backgroundColor = UIColor.green
    }
    // Calling nested function
    setBackgroundColor()
}

This improves readability, because function definition is right there at the point where it is used. It also improves maintainability, because whoever is refactoring your code can be certain that there can be no other uses of setBackgroundColor outside of viewDidLoad.

Of course, this is just an example. The nested function is not necessary here - you can rewrite it without setBackgroundColor function, like this:

override func viewDidLoad() {
    super.viewDidLoad()
    self.view.backgroundColor = UIColor.green
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
2

I don't see anything in your code that warrants a memory concern. Micro-optimization is greatest time waster in software development. But since you asked, viewDidLoad is invoked only once. From Apple's Work with View Controllers:

viewDidLoad()—Called when the view controller’s content view (the top of its view hierarchy) is created and loaded from a storyboard. The view controller’s outlets are guaranteed to have valid values by the time this method is called. Use this method to perform any additional setup required by your view controller.

Typically, iOS calls viewDidLoad() only once, when its content view is first created; however, the content view is not necessarily created when the controller is first instantiated. Instead, it is lazily created the first time the system or any code accesses the controller’s view property.

Community
  • 1
  • 1
Code Different
  • 90,614
  • 16
  • 144
  • 163
  • The documentation says to "use this method to perform any additional setup required by your view controller", but is setting the background color really "additional setup"? Isn't it primary, foundational setup? The func doesn't load when it's not inside viewdidload() which leads me to believe the wording of "additional setup" is a bit misleading. Yes? – youareawaitress Aug 07 '17 at 15:32
  • It's important to realize that the viewController is different than the view. You are setting the color of the view which is part of the setup of the viewController. – toddg Aug 07 '17 at 15:43
2

It's not a case of memory usage, it's a matter of loading the view efficiently.

UIViewControllers control views. But the views isn't created at the same time as the view controller.

Setting the background colour, indeed, any kind of view configuration, in viewDidLoad is done because when that method is called, the view has been created (although not necessarily displayed) at a convenient point in the view controller's life cycle. If you created the view controller and then called your setBackgroundColor method, the self.view part of the call would cause the view to be created straight away if it hadn't already been created.

For certain methods, such as view controller presentations, this allows the creation methods to return as quickly as possible without the view being loaded straight away and keeps the UI responsive.

It's because of this lazy loading of views that UIViewController has the isViewLoaded parameter which returns a Bool for whether the view is loaded into memory or not, but without causing the view to load.

Abizern
  • 146,289
  • 39
  • 203
  • 257
2

My guess is that any loss in efficiency is worth the gain in having more readable code. In fact, a compiler optimization may even inline the function if you mark it as private. I don't know enough about the Swift compiler (LLVM) to know if this is definitely true but it may be.

Martin Fowler has a great article on function length in which he states that he has many functions that are one line long simply because they make the code easier to understand.

Some people are concerned about short functions because they are worried about the performance cost of a function call. When I was young, that was occasionally a factor, but that's very rare now. Optimizing compilers often work better with shorter functions which can be cached more easily. As ever, the general guidelines on performance optimization are what counts.

Not sure if his notes about function caching apply to Swift, but he also says:

If you have to spend effort into looking at a fragment of code to figure out what it's doing, then you should extract it into a function and name the function after that “what”. That way when you read it again, the purpose of the function leaps right out at you

In general, I wouldn't focus too much on optimization unless you notice that it's a problem. YAGNI

... And as Code Different noted, yes ViewDidLoad() is only called once.

toddg
  • 2,863
  • 2
  • 18
  • 33