Files
knowledge-kit/Chapter1 - iOS/1.2.md
2026-02-22 22:04:06 +01:00

165 lines
4.5 KiB
Markdown

# 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 <Foundation/Foundation.h>
@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 <Foundation/Foundation.h>
@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.