Overriding initialize on an AppDelegate - Protecti

2019-09-18 18:43发布

问题:

Overriding initialize() is common for executing code before a class is sent its first message (setting UserDefaults, etc). The documentation states that a superclass' implementation may be called multiple times subclasses do not override initialize(), and give an example of a way to protect a class from executing code more than once if initialize() is called several times:

The superclass implementation may be called multiple times if subclasses do not implement initialize()—the runtime will call the inherited implementation—or if subclasses explicitly call [super initialize]. If you want to protect yourself from being run multiple times, you can structure your implementation along these lines:

+ (void)initialize {
  if (self == [ClassName self]) {
    // ... do the initialization ...
  }
}

I am overriding initialize() in my AppDelegate and trying to avoid having code run more than once. The class check doesn't make sense to me, as checking if self is AppDelegate.Type will always evaluate to true (and gives me a warning in Xcode).

Does the class check not apply, since we're not in a superclass (the superclass of AppDelegate is UIResponder)? Will the contents of my overridden initialize() method only run once without calling super or performing a class check?

回答1:

The reason for the class check is because you usually want to run code on initialize only once (as per the docs). Writing that condition protects you from subclasses that don't implement initialize or call [super initialize]. Here's an example class hierarchy:

class Animal: NSObject {
    class func initialize() {
        //Some code I only want to run once
    }
}


class Dog: Animal {}

When I instantiate a new Dog, the Objective-C runtime will send the initialize method to every class in Dog's hierarchy (superclasses first), so Dog will receive the message, but so will Animal. Because Dog doesn't implement initialize, its superclass will receive the message, so if you don't add the check that makes sure that the message was intended for that class, your code will end up executing twice.

This doesn't really make sense in Swift, and probably even less so in an AppDelegate so if you want to have code only run once in Swift, you should probably use lazily initialized globals or static properties, as defined in the migration docs.