1

正如标题所说:在分配和初始化对象之前检查对象是否为 nil 是否有必要或者是一种好习惯,就像这样?

if (!_menuFetcher) {
    _menuFetcher = [[MenuFetcher alloc] init];
    _menuFetcher.delegate = self;

}

我想这被称为延迟加载吧?

4

5 回答 5

2

延迟加载将对象的创建推迟到您需要它为止。UIViewController 用它的视图来做这件事——创建视图层次结构需要大量的时间和内存,所以在访问视图之前它不会完成。您可以使用您所展示的条件语句来实现延迟加载。理想情况下,您会将其放在属性的访问器中并在任何地方使用该属性,这样您就不会到处都有条件。

检查对象是否存在并不是一个坏习惯,但是使用属性可以限制需要这样做的地方的数量,从而简化其余代码。

在分配之前不必总是检查某些东西是否存在——大多数时候你应该已经知道了。例如,在您的-init方法中,您知道尚未分配任何内容,您可以创建新对象需要的任何对象。

于 2013-07-29T12:09:56.563 回答
1

通常你在 getter 方法中做这样的事情。

假设你有一个财产:

@property (nonatomic, strong) MenuFetcher *menuFetcher;

你在视图控制器中使用的说,那么你可以为属性实现一个getter,如下所示:

- (MenuFetcher *)menuFetcher 
{
    if (!_menuFetcher) {
        _menuFetcher = [[MenuFetcher alloc] init];
        _menuFetcher.delegate = self;
    }
    return _menuFetcher;
}

你是对的,这是一种延迟初始化(而不是加载)的形式 - 内存没有分配,也没有初始化实例,直到需要它。此外,您不需要集中初始化例程,也不需要担心正在设置的对象——如果它不存在,它会被创建——如果你通过将它设置回 nil 来吹走它,下一次需要该类型的实例时,它会再次创建。所以在这方面它有点优雅和高效。

因此,实际上,当您第一次尝试通过调用读取属性时self.menuFetcher,如果尚未设置,您的 getter 会注意到它为 nil 并为您创建和初始化它。一旦设置,该属性就不再是 nil,所以 getter 只是返回持有的对象。

如果适合您正在编写的内容,请使用延迟初始化。唯一需要真正注意的是除了惰性初始化之外还做其他事情的吸气剂——如果出现问题,具有“副作用”的吸气剂可能会很痛苦。让他们保持简单和专注。

于 2013-07-29T12:18:21.723 回答
1

这取决于。

如果您只需要实例化一个新对象,则无需检查 nil。

在分配对象之前无需检查 nil。一点也不。

但是,这是一种非常好的且广泛传播的模式,您可以在实际使用对象之前检查 nil。如果引用为 nil,那么您“即时”创建它。您必须在以下代码的上下文中看到它(在此处或在调用者中)。_menuFetcher 会以某种方式使用。(至少最可能。)或者这是一个可以多次调用的方法,就像viewWillAppear在视图控制器中一样。您可能有充分的理由不早点实例化和初始化对象,而只实例化一次。在下一次调用该方法时,您只需重用之前创建的对象。

(我的意思是先在评论中写这个,而不是答案。但它变得很渴望评论。)

于 2013-07-29T12:22:59.803 回答
1

是的,这基本上可以防止重新初始化已经初始化的东西。您应该始终这样做,除非您 100% 确定您没有重新初始化。然而,这不叫延迟加载——那是不同的东西。

例如,在表格视图中加载图像时会使用延迟加载。无需加载表格视图中的所有图像,您只需加载屏幕上可见的这些图像。这种方法更适合加载时间、性能和内存。

于 2013-07-29T12:10:23.330 回答
0

延迟加载意味着“按需加载”,只有在真正需要时才执行操作,例如:

- (MenuFetcher *)instance{
    if (_menuFetcher == nil){
        _menuFetcher = [[MenuFetcher alloc] init];
    }
    return _menuFetcher;
}
于 2013-07-29T12:22:33.093 回答