Swift Quick Initializer

In Swift, a super initializer must be called after all the properties of the current class have been initialized. This, however, does not work for Objective-C init, where super init is called first before the properties in the current class are initialized.

What problems is Swift trying to prevent by observing this? Why can Objective-C avoid the problems that Swift is trying to prevent?

+5
source share
2 answers

What problems is Swift trying to prevent by observing this?

This is a great question, and Objective-C did not avoid it.

The problem is that, being inside the initialization method, the object is technically in a partially constructed state. The Bryan post is a great (albeit far-fetched) example of why. A common problem is that if the super class initializer calls the method, the subclass can override this method. This in itself is not bad. The problem arises if the overridden method assumes that the object is completely constructed.

However, since the object is still in the middle of the initializer call, this is not the case. The whole object is not built until a call [super init] is returned and the class of the object executes some of its initialization code.

There is a related problem with dealloc methods: if you call methods inside your -dealloc method, these methods may assume that the object is completely built, but in fact it can be partially deconstructed. This is not much for a deal in ARC, but it can still lead to some very subtle errors.

With Swift, it was decided to avoid this class of problems by observing this rule:

By the time you decide to call super , the calling class must complete any initialization of the class.

A variation of this rule:

You cannot call methods until you call the super initializer.

With this rule, you will never encounter the problem described above.

+10
source

ObjC avoids nothing.

For this ObjC code, it crashed because the parent class is trying to access ivar from the child class. It can be detected / avoided if the Swift rule is used. those. initialize all elements before [super init]

 @interface Parent : NSObject @property (readonly) int value; @end @implementation Parent - (id)init { self = [super init]; if (self) { NSLog(@"%d", self.value); // call a method, which can be overrided by child class } return self; } - (int)value { return 42; } @end @interface Child : Parent @end @implementation Child { int *_valuePtr; } - (id)init { self = [super init]; // call self.value if (self) { // to avoid crash, move this line before [super init], but it may have other undesired effect. eg when [super init] return another instance _valuePtr = calloc(sizeof(int), 1); } return self; } - (void)dealloc { free(_valuePtr); } - (int)value { return *_valuePtr; } - (void)setValue:(int)value { *_valuePtr = value; } @end 
+5
source

Source: https://habr.com/ru/post/1201527/


All Articles