为什么将nil分配给单例的静态变量?

5
使用此方法的优势是什么?
+ (CardPainter*) sharedPainter {
    static CardPainter* sp = nil;

    if (nil == sp) {
        sp = [[CardPainter alloc] init];
    }

    return sp;
}

改为以下方式:

+ (CardPainter*) sharedPainter {
    static CardPainter* sp = [[CardPainter alloc] init];

    return sp;
}

静态变量的初始化只会执行一次,所以我认为前者没有任何优势。

3
https://dev59.com/l2ct5IYBdhLWcg3wKqQd#12304815 - melanye
5
前者的优点在于它能够工作,而后者甚至无法编译。 - rmaddy
2个回答

0

在编译器层面上,有几个重叠的原因……最简单的想法是静态变量存储在已编译应用程序的专用数据部分中,该部分只是按原样映射到内存中。因此,编译器必须在编译时精确地知道它是什么。任何 Objective-C 方法调用的结果在定义和实践上都是不可预测的 - 你永远不知道某些“有趣”的事情是否会在运行时改变该方法调用的行为,因此你不确定会返回什么。

这与 C++ 有所不同,原因有很多(其中一个关键原因是 C++ 有构造函数,而 Objective-C 没有)。但即使在 C++ 中,出于几个原因,这仍然是不被赞成的:

  1. 构造函数的顺序是不可预测的,但很容易且常见的是构造函数彼此依赖,这意味着你的程序可能在运行时具有未定义的行为(包括数据损坏或崩溃)。
  2. 初始化许多非平凡对象可能是昂贵的。在启动时一起完成可能是有效的,但会使你的应用程序启动缓慢,这是更糟糕的。

后一点同样适用于 Objective-C。你能够避免在启动时执行的操作越多,而是在需要时进行即时、按需处理,用户体验就会越好。

[请注意,“不允许静态对象实例”的规则有一个值得注意的例外,那就是字符串,以 @"foo" 形式表示。这些实际上被编码为您应用程序的数据部分中的真实实例(特殊的 NSString 子类),只需在启动时映射即可神奇地正常工作。但这是非常谨慎的架构,并且编译器和运行时在这个方面紧密耦合,以确保一切顺利运行。它并不适用于一般情况。]


-2
因为如果你不询问,每次调用“sharedPainter”都会初始化“*sp”,导致任何数据丢失。
所以,如果你询问sp是否为空,答案是FALSE意味着“sp”已经初始化并返回实例。如果答案是true,那就意味着sp没有初始化,在这种情况下才调用init函数。

这不是关于你是否检查指针是否为空,而是为什么不在初始化行上直接调用 alloc init - Dan F
实际上,静态变量的声明不能在sharedPainter函数中,必须在实现之前。 - Vertig0
@PatricioIgnacioFariaValdivi:嗯...什么?当然可以在函数内部有静态变量。 - user102008
我不记得说“你不能”。是的,你可以。但在这种情况下,你不应该这样做。你每次都在“重新实例化”sp。 - Vertig0
2
除了第二个示例由于我在答案中解释的原因无法编译之外,即使它能够编译,它也不会像你描述的那样运行。静态变量仅在启动时(基本上)初始化为其分配的值。如果它们没有被初始化,它们将与非静态局部变量没有区别,第一个示例的形式也就没有任何意义了。 - Wade Tregaskis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接