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

4.5 KiB

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;
}
// 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;
}
// 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 init

An experiment about "custom initializers must start with initWith"

initwith

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.