What are the disadvantages of using self in initialization methods?

What are the disadvantages of using self in initialization methods?

What are the disadvantages of using self in initialization methods?
thinking about the gills

Scene description

IOS initialization methods include system defaults and customizations. Common system initialization methods include init, initWithFrame:, initWithNibName:bundle:, and so on. In our everyday iOS project development, we often initialize some of the necessary data or interfaces needed by the next class in the initialization method of the class. There are roughly two scenarios for using self in the initialization method, one is the self calling method, such as: [self doSomething], and two is property initialization, such as: self.property = xxx. The style is as follows:

@interface HHAnimal: NSObject @property (nonatomic, strong) NSString *name; @end @implementation HHAnimal (instancetype init) {self = [super init]; if (self) {self.name = @ "HH"; [self doSomething];} return self;} - {@end} doSomething (void)

So, why not suggest that in the initialization method, self.property = XXX, or, [self, doSomething], code like that?

problem analysis

When using self.property = XXX, the system will help us do these two things:

  1. Method call. [self setProperty:xxx]
  2. KVO. Send a change to the listener for this property

Then, to merge [self doSomething], the initial call to self is roughly divided into method calls and KVO. These two things will not be a problem in general, but in class initialization, the class is in a partially initialized state, and there is a good chance that an error will occur. Because the object of the execution of the method body or property value changes that will monitor the current execution process is stable when fully initialized, executive body using the uninitialized data, the data may occur disorder, abnormal program or crash.

Let’s give an example

Example support

In order to better illustrate, the following code, suppose we have a HHAnimal class, there are three properties, age age, name animal name (which is readable), attrDescription is used to display with the color of the name (read-only), it is a calculation of variables, according to the change of age, color name the same.

@interface HHAnimal: NSObject @property (nonatomic, assign) NSUInteger age @property (nonatomic, readonly); NSString *name; @property (nonatomic, readonly) NSAttributedString *attrDescription; @end @implementation HHAnimal (instancetype init) {self = [super init]; if (self) {self.age = 12; _name = @ "HH";} return self - (void);} updateAttrDescription {NSDictionary *attrs = nil; if (self.age < 18) {attrs = @{NSForegroundColorAttributeName: [UIColor greenColor]};} else {attrs = @{NSForegroundColorAttributeName: [UIColor yellowColor]} _attrDescription [[NSAttributedString alloc] initWithString:self.name;} = attributes:attrs];} @end

We increase from the probability of error, the first level upward. Now we want the attrDescription variable to be initialized after initialization. The first method of adding (call [self updateAttrDescription] directly after the default age is set):

- (instancetype) init {self = [super init]; if (self) {self.age = 12; [self updateAttrDescription]; _name = @ HH ';} return, self;}

Someone will say, “this method is weak, look at me.”:

- - (void) setAge: (NSUInteger) age {_age = age; [self updateAttrDescription];}
What are the disadvantages of using self in initialization methods?
yeah!

This method is more advanced and associates attrDescription with age. Well, that’s good. But still crash, because in the implementation of [self updateAttrDescription], name is nil, and [NSAttributedString initWithString:attributes:] method calls, if string is nil, apple dad directly to collapse.

Then why do you write like that? One reason may be because you don’t know not the system uses nil as the parameter, another important point is you clearly see name has been assigned in the initialization method, it does not exist the problem of nil.

This obvious scenario in our daily development process, we will soon find. Suppose, however, that a subclass HHHuman inherits HHAnimal, which can only see the.H file of the parent class (and declare that name is the initial value). If the HHHuman implementation overrides the age method of setter and uses name as an initialized variable, problems such as crashes can be introduced.

[UIViewController view]

In addition to some of the examples outlined above, a more complex and common example of everyday development is the property–view of UIViewController. Suppose that the self.view is written during initialization, as follows:

@implementation ViewController - (instancetype) initWithOrderId: (NSString * orderId) {self = [super init]; if (self) {NSLog ("% @ @", self.view); _orderId = orderId;} return self;} - (void) viewDidLoad [HHNetUtil requestWithOrderId:_orderId completionBlock: {[super viewDidLoad];}];...

What strange things will happen when you write this? Normal UIViewController initialization -> interface display process is:

Init -> loadView -> viewDidLoad -> viewWillApear:

After calling self.view, the process is:

Init (loadView, -&gt, viewDidLoad) -> viewWillAppear:

After invoking self.view in initialization, the system automatically triggers the loadView and viewDidLoad processes. In turn calls the loadView -&gt in init viewDidLoad, this time period method; initialized data has not been completed, the viewDidLoad method is likely to get empty data (such as the init initialization code according to orderId after the request to order data), the program will abnormal. In addition, we may create UIViewController, and do not want to show it immediately, but I hope to show in the lazy loading, and then create the interface, data processing or request resources in the process of viewDidLoad.

What are the disadvantages of using self in initialization methods?

Many examples have shown that it is not appropriate to use self in initialization, so is there any way we should pay attention to it?

Dealloc is best not to use self.property = XXX

Like initialization, the dealloc method is also a procedural, “unstable” approach. The instability here refers to the fact that the current process is an incomplete state, incomplete initialization, incomplete release.

In addition to meeting the problems introduced in initialization, dealloc often generates exceptions that are caused by the KVO mechanism. When an object A listens for the property C of the object B, if the call B.C = nil is called in the B dealloc, the listener method in the A is triggered. At this time if the use of B in some property or method, B is half the release condition, will cause some abnormal strange questions. So, it’s safer to use _C = nil at this point.

epilogue

This paper first analyzes the reasons for not using self in initialization, and proves it by several examples, and finally derives the inference that dealloc is best not to use. Most of the time, though, there is no error in the use of self (the way you have been able to ensure that the method and property of the call does not affect other code cases), but the risk is there, and self is there.

Here, you probably think of the Objective-C successor, —Swift class two section of the construction process, it is more secure, standardized. Swift ensures that all initialization attributes are initialized through the two construction processes, avoiding the unpredictable use of the process after the property has no initial value. Students who are not quite sure and want to understand the two – paragraph construction process of the Swift class can poke the official Chinese tutorial.

Finally, thank you for your reading. Please correct me when you have any questions

Reference article

Initializing a property, dot notation
Should I refer to self.property in the init method with ARC
Objective-C init: Why? It s Helpful to Avoid Messages “to self
Practical Memory Management