【问题标题】:Should +initialize/+load always start with an: if (self == [MyClass class]) guard?+initialize/+load 是否应该始终以 if (self == [MyClass class]) 守卫开头?
【发布时间】:2010-09-24 09:23:24
【问题描述】:

在您的一个 Objective-C 类中实现 +initialize 或 +load 方法时,您是否应该总是从这种保护开始?:

@implementation MyClass

+ (void)initialize {
    if (self == [MyClass class]) {
        ...
    }
}

...
@end

似乎 +load 和 +initialize 中的代码通常只想执行一次。因此,这将有助于避免在子类加载/初始化时重复执行。

我想我只是想从一些 ObjC 向导那里得到一些强化,这是必要的/常见的做法......

对此有什么普遍看法?你会建议总是这样做吗?

您对 +load 和 +initialize 的建议是否相同,或者它们的处理方式是否有所不同?

谢谢。

【问题讨论】:

    标签: iphone objective-c cocoa macos


    【解决方案1】:

    快速回答是:不。

    in-depth discussion of this matter 可以在 Apple 开发者邮件列表中找到。

    它的要点是:

    1. 运行时实际上会在超类上调用+initialize上调用子类。
    2. 如果您确实包含守卫,则具有自己的+initialize 方法的类的子类将不会触发相关的KVO 通知。

    对于第 2 点的示例,请务必阅读上述线程中的this post

    【讨论】:

    • 如果你的目标是 Leopard,你不应该使用 +setKeys: triggerChangeNotificationsForDependentKey: 而是应该实现 +(NSSet *)keyPathsForValuesAffecting,这就涉及到第二点了。
    • +initialize 中所做的绝大多数事情都应该只为实现它的类而不是子类执行一次。旧的 KVO 依赖键机制是一个需要注意的重要例外,它应该在这样的保护之外完成,但在大多数其他情况下应该使用保护。引用的电子邮件线程主要是关于+initialize 是否应该调用super,它不应该。
    【解决方案2】:

    是的,如果您正在初始化应该只初始化一次的全局变量,您应该在您的 intialize 和 load 方法中执行此操作。

    也就是说,在很多情况下你可以避免它......

    如果需要对每个类的每个继承者执行工作,则不应使用此条件进行包装:

    • 例如,将每个类的所有继承类名添加到集合中。
    • 编辑添加:或者您正在建立 KVO 依赖项(如 eJames 所述)

    还有一些情况是你不必费心的:

    • 如果您执行的操作是幂等的(重复时不要更改值)
    • 该类是“密封的”(设计上没有后代)

    “幂等”部分是相关的。初始化程序应该只是设置初始状态(每次都应该相同)。在一个好的初始化器中,重复应该无关紧要。虽然我想如果你忘记在条件中包装方法确实很重要,这可能会很烦人。

    编辑添加:另一种方法可以正确反映任何仅初始化一次的要求,即测试您要初始化的属性是否已经初始化。即

    id myGlobalObject = nil;
    
    +(void)initialize
    {
        if (myGlobalObject == nil)
        {
            myGlobalObject = [[MyGlobalClass alloc] init];
        }
    }
    

    【讨论】:

    • 我更喜欢这个答案,因为它清楚地表明(在示例中)警卫通常必要的,但测试的类型可能很重要。 (虽然我认为如果你依赖 initialize() 未被覆盖,以便在子类加载时执行某些操作,那可能不属于 initialize()。)
    【解决方案3】:

    是的!!!!

    因为一个类的initialize方法可能会被多次调用。例如当你在父类中实现了initialize,而在子类中没有实现,那么你先调用子类,父类的initialize会被调用两次。

    @implementation BaseClass
    
    + (void)initialize
    {
        NSLog(@"BaseClass initialize self=%@, class=%@", self, [BaseClass class]);
    }
    
    @end
    
    @interface SubClass : BaseClass
    @end
    
    @implementation SubClass
    
    // don't implement the initialize method
    
    @end
    

    ===================

    现在当你首先调用 SubClass 时,就像

    [SNSBaseSubLogic alloc]
    

    查看调试控制台,输出:

    BaseClass initialize self=BaseClass, class=BaseClass
    BaseClass initialize self=SubClass, class=BaseClass
    

    所以,你必须使用

    + (void)initialize
    {
       if (self == [BaseClass class]) {
          NSLog(@"BaseClass initialize self=%@, class=%@", self, [BaseClass class]);
       }
    }
    

    确保方法体执行一次。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-04
      • 1970-01-01
      • 2016-11-11
      • 1970-01-01
      • 1970-01-01
      • 2016-02-16
      • 2022-06-23
      相关资源
      最近更新 更多