Why does initializing subclasses require calling a superclass of the same init function?

I heard that when you have a subclass, you must initialize the superclass with the same init function from the init subclass. I mean, the init subclass should call [super init], and the initWithFrame subclass should call [super initWithFrame]. Why is this? Why does calling super-init from a subclass of initWithFrame lead to an infinite loop?

If necessary, does this mean that I cannot create a new init function inside a subclass, such as initWithPoint, and have this call super init or initWithFrame simply because the superclass does not have initWithPoint? I suppose the gist of the question is why is it not suitable for calling another superclass, which scares me, possibly due to my C ++ background?

+2
source share
5 answers

When you create a subclass, if you implement an initializer, you must definitely call the initializer of the superclass, and you must specify at least one assigned initializer, although this may just be your override of the superclass.

As part of the initialization of your subclass, you must call one of the initializers assigned to the superclasses.

Class documentation should designate designated initializers. If not, the designated initializer is usually considered the most specific initializer (which takes most arguments) provided by the superclass.

See "Objective-C Programming Language: Object Selection and Initialization" for details . [Note: As of December 2013, this content is no longer available through the Apple doc. Which language link has been replaced by more task-oriented textbooks and conceptual documentation.]

Regarding your specific questions:

Why is this? For the superclass to be able to initialize its state. You can continue and initialize the state that you add above and above what the superclass provides.

Why does calling super-init from a subclass of initWithFrame lead to an infinite loop? Since for NSView , -init not a designated initializer, although it is NSObject 's, therefore NSView overrides it to call the designated initializer -initWithFrame: If you called -init from your -initWithFrame: you now have -initWithFrame: call to -init calling -initWithFrame: call to -init: calling ...

Does it mean...? No, because it is not required. You should understand the actual documentation, not firsthand.

+3
source

Why is this? Why does calling super-init from a subclass of initWithFrame lead to an infinite loop?

If -init in super is implemented as

 -(id)init { return [self initWithFrame:CGRectZero]; } 

then the call schedule will be cyclical:

 [subclass initWithFrame:] | ^ v | [super init] 

as self always uses the current class ("subclass").


If necessary, does this mean that I cannot create a new init function inside a subclass, such as initWithPoint, and have this call super init or initWithFrame simply because the superclass does not have initWithPoint?

No, this is not required. It is preferable to call super most specialized initializer, so there is no way for super -initXXX redirect the -initYYY subclass.

+3
source

Why does calling super-init from a subclass of initWithFrame lead to an infinite loop?

Based on the background of C ++, as you say, the main problem is probably that you are using the C ++ method, which causes a paradigm shift. In Objective-C, you do not call function objects. It’s not even technically quite right to say that you are calling methods. In Objective-C, you send messages to objects, and the object decides what to do with them. What he usually does is find the method in his class and call it. The consequence of this is that you cannot control which version of the method in the class hierarchy is invoked by the message. This is always a method that belongs to the class of the object to which you are sending a message (with the exception of one case). It is as if C ++ had no virtual functions, not even constructors.

The only exception is when you send a super message. In this case, the method of your class bypasses. This can lead to endless cycles, as you know. The reason is that we do not call functions, we send messages. Therefore, if method A in the SubKlass class sends [super methodB] , the implementation of method B in Klass will be called. If it sends [self methodA] , then I am still an instance of SubKlass, it does not magically turn into an instance of the Klass class, so the MethodA method in SubKlass will be called.

This is why the rules for initializers seem so confusing. Only the designated initializer is guaranteed not to send one of the other initializers, so you can only safely send the assigned initializer to super in your initializer.

+3
source

from a C ++ point of view:

I heard that when you have a subclass, you must initialize the superclass with the same init function from the init subclass. I mean, the init subclass should call [super init], and the initWithFrame subclass should call [super initWithFrame].

which is not true. it's just a common thing. you can invoke any superclass initializer that is documented as a valid initializer.

it can help to look at it like this: look at the activators of the superclass and determine which of them are supported.

  • sometimes there is a designated initializer
  • sometimes new initializers appear (for example, one that can add an argument to a super superclass)
  • sometimes there are intializers inherited from the super-superclass

for designated initializers: consider it secure

for a new initializer: consider it protected

for inherited initializers: usually consider private when the superclass declares new initializers, otherwise protected

Why does calling super-init from a subclass of initWithFrame lead to an infinite loop?

this is the effect (undefined behavior) of calling an intializer, which you should not call.

If necessary, does this mean that I cannot create a new init function inside a subclass, such as initWithPoint, and have this call super init or initWithFrame simply because the superclass does not have initWithPoint?

this is normal if you call one of the supported superclass initializers.

I think the gist of the question is why is it not suitable for calling another superclass, which scares me because of my C ++ background?

objc does not support hiding / visibility for initializers. as soon as it is in the interface of the superclass, it is there (and you can make bad options when the compiler cannot help you) - you must define the visibility schedule for the initializers and write down your subclass accordingly. objc lacks the language features that you are used to having in C ++.

+1
source

I don’t know where you heard this from, but AFAIK is not required. You can select the subtitle that you want, provided that you call the init method for the superclass. Any init method will work.

However, if you also have the same init function in your superclass, I think it is best to name this function and then add your own customization. This is not required, it is just good practice because this init function can provide some initializations and settings that you might forget to add.

0
source

All Articles