在 viewdidload() 内部定义函数是否比在外部定义它们节省更多内存?

Does defining functions inside viewdidload() save more memory versus defining them outside?

由于 viewdidload() 在 UIViewController 对象的那个实例的生命周期中只被调用一次,这是否意味着下面的这个例子是 "bad practice" 自 setBackgroundColor() 以来,一个只被调用一次的函数, 被不必要地加载到整个 class 的内存中,而它实际上应该完全存在(定义和调用)在 viewdidload() 中?或者在效率方面,setBackgroundColor()在哪里定义和调用不重要吗?

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()
    }

}

我在您的代码中没有看到任何值得考虑内存问题的内容。微优化是软件开发中最大的时间浪费。但是既然你问了, viewDidLoad 只被调用一次。来自 Apple 的 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.

使函数成为方法的局部函数会改变它的范围,但不会改变从它编译的代码的生命周期。 class 的方法也是如此:它们的二进制代码不是单独管理的,至少目前不是。不过,这没什么大不了的,因为您的函数的可执行代码相对较小。

这里重要的是函数名称在其外部范围内不可见,让其他方法定义自己的 setBackgroundColor()viewDidLoad:

中定义的函数无关的函数
override func viewDidLoad() {
    super.viewDidLoad()
    // Nested function definition
    func setBackgroundColor() {
        self.view.backgroundColor = UIColor.green
    }
    // Calling nested function
    setBackgroundColor()
}

这提高了可读性,因为函数定义就在使用它的地方。它还提高了可维护性,因为重构您的代码的任何人都可以确定 setBackgroundColor 除了 viewDidLoad.

之外没有其他用途

当然,这只是一个例子。嵌套函数在这里不是必需的——你可以在没有 setBackgroundColor 函数的情况下重写它,像这样:

override func viewDidLoad() {
    super.viewDidLoad()
    self.view.backgroundColor = UIColor.green
}

这不是内存使用问题,而是有效加载视图的问题。

UIViewControllers 控制视图。但是视图不是与视图控制器同时创建的。

设置背景颜色,事实上,任何类型的视图配置,在 viewDidLoad 中完成,因为当调用该方法时,视图已在方便的位置创建(尽管不一定显示)查看控制器的生命周期。如果您创建了视图控制器,然后调用了您的 setBackgroundColor 方法,那么调用的 self.view 部分将导致立即创建视图(如果尚未创建的话)。

对于某些方法,例如视图控制器演示,这允许创建方法尽快 return 而无需立即加载视图并保持 UI 响应。

由于视图的这种延迟加载,UIViewController 具有 isViewLoaded 参数,该参数 return 是一个布尔值,表示视图是否加载到内存中,但不会导致加载视图。

我的猜测是,任何效率损失都值得获得更具可读性的代码。事实上,如果将函数标记为 private,编译器优化甚至可能会内联该函数。我对 Swift 编译器 (LLVM) 的了解还不够,无法确定这是否确实如此,但它可能是。

Martin Fowler 有一个 great article on function length,他在其中声明他有许多函数,它们只有一行,只是因为它们使代码更容易理解。

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.

不确定他关于函数缓存的注释是否适用于 Swift,但他还说:

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

一般来说,除非您注意到这是一个问题,否则我不会过多地关注优化。 YAGNI

...正如代码不同指出的那样,是的 ViewDidLoad() 只被调用一次。