# Understanding Initializers ## Initializers * The internal implementation of the new method is to call alloc first, then call init. * alloc: Sends the alloc message to a class; alloc returns an instance of that class. * init: An instance method whose role is to initialize the object. * Steps to create an object: first use alloc to create an object, then use init to initialize it before using the object. * Using an uninitialized object is dangerous. * init method: Purpose — initialize the object and set initial values; this is called a constructor (initializer). ## Overriding init * If you want the created object's properties to have values other than the default initialization values, you need to override init. * Rules for overriding init: * You must first call the superclass's init method (because initialization of the current class proceeds through [super init]), and assign the returned value to self. * Calling init may fail; if it fails, return nil. * Check whether the superclass initialized successfully. If self != nil, initialization succeeded. * If initialization succeeded, initialize the current class's properties. * Finally return self. #### Clarifications: 1. Why call the superclass init method? 1. The current object has an isa pointer; the isa pointer is set through the superclass's init. 2. You need to ensure that the superclass's properties are also initialized. 2. Pattern for overriding init: ``` -(instancetype)init{ if (self = [super init]) { // todo: custom property initialization } return self; } ``` ```objc // Person #import @interface Person : NSObject @property NSString* name; @property int age; -(void)sayHi; @end #import "Person.h" @implementation Person -(void)sayHi{ NSLog(@"Hi"); } -(instancetype)init{ self = [super init]; if (self) { self.name = @"杭城小刘"; self.age = 22; } return self; } @end // Test Person *p1 = [[Person alloc] init]; // p1.name = "杭城小刘", p1.age = 22; Person *p2 = [Person new]; // p2.name = "杭城小刘", p2.age = 22; ``` If two classes have a composition relationship and one property is an object of another class, that property defaults to nil when the containing class is initialized. How to initialize it? ``` -(instancetype)init{ self = [super init]; if (self) { self.name = @"lbp"; self.age = 22; self.pig = [[Pig alloc] init]; } return self; } // Test Person *p1 = [[Person alloc] init]; // p1.pig != nil ``` ## Custom initializers * Current situation: Although each created object's properties are not the default values, every initialized object has the same values. * Requirement: Allow callers to decide the property values when instantiating. * Solution: Custom initializer. * Rules for custom initializers: * The return type should be instancetype. * The method name must begin with initWith. * The implementation is similar to init. * Note: You cannot use new to call a custom initializer. (new performs alloc then init; default init assigns the default property values.) ``` -(instancetype)initWithName:(NSString *)name andAge:(int)age{ if (self = [super init]) { self.name = name; self.age = age; } return self; } ``` ```objc // Person #import @interface Person : NSObject @property NSString* name; @property int age; -(instancetype)initWithName:(NSString *)name andAge:(int)age; @end #import "Person.h" @implementation Person -(instancetype)init{ self = [super init]; if (self) { self.name = @"lbp"; self.age = 22; } return self; } // You cannot assign to self outside of an initializer. // The compiler treats only methods starting with initWith as initializers. -(instancetype)initWithName:(NSString *)name andAge:(int)age{ if (self = [super init]) { self.name = name; self.age = age; } return self; } @end // Test Person *p1 = [[Person alloc] init]; Person *p2 = [Person new]; Person *p3 = [[Person alloc] initWithName:@"杭城小刘2号" andAge:23]; ``` ![init](../assets/2017-05-23-5-56-53.png) ![init](../assets/2017-05-23-5-57-08.png) An experiment about "custom initializers must start with initWith" ![initwith](../assets/2017-05-23-6-01-29.png) The error message is clear: you cannot assign to self outside of an initializer. Because the compiler considers only methods starting with initWith as initializers.