obsidian/笔记文件/2.笔记/objectc什么时候alloc的时候,需要init.md
2025-03-26 00:02:56 +08:00

4.3 KiB
Raw Permalink Blame History

#ios

栗子:

!Pasted image 20241024101001.png

在 Objective-C 中,调用 alloc 时通常需要紧接着调用 init(或它的变种 initWith...),因为 alloc 只是为对象分配内存,而 init 负责进行初始化设置和状态的配置。这两个方法通常是配套使用的。

为什么 allocinit 需要一起使用

  • alloc:仅分配内存给对象,并设置对象的基本结构(如引用计数)。在这个阶段,尚未初始化对象的状态。

  • init:初始化对象的状态,设置对象的内部数据。对象在调用 init 后,才能进入一个可用的状态。

因此,调用 alloc 之后,必须调用 init 或其他具体的初始化方法才能得到一个完全可用的对象。

常见的使用方式

通常,我们会这样使用:

MyClass *object = [[MyClass alloc] init];

alloc 分配内存,init 对对象进行初始化,这种组合通常会确保创建的对象是有效的。

什么时候需要调用 init

每当你通过 alloc 创建一个新对象时,通常都需要调用 init 或者某个特定的初始化方法,例如 initWithName:initWithFrame: 等等。

1. 基础初始化:alloc + init

最常见的场景是调用无参的 init 方法进行初始化。许多类的 init 方法负责设置对象的默认状态:

MyClass *object = [[MyClass alloc] init];

2. 指定初始化方法:alloc + initWith...

有时类提供了自定义的初始化方法,如 initWith...,它们需要特定的参数来进行对象的初始化。比如:

MyClass *object = [[MyClass alloc] initWithName:@"Example"];

在这种情况下,initWithName: 方法会初始化对象的内部状态,比如名称属性。

3. init 方法的继承和重写

如果你创建了一个自定义类并希望定义自己的初始化逻辑,可以通过重写 init 方法来完成:

- (instancetype)init {
    self = [super init]; // 调用父类的初始化方法
    if (self) {
        // 自定义初始化逻辑
        _name = @"DefaultName";
    }
    return self;
}

在这里,[super init] 调用父类的 init 方法来确保父类部分被正确初始化。之后,你可以添加自定义逻辑来设置当前类的属性或状态。

什么时候不需要调用 init

1. 类工厂方法

一些类提供了工厂方法来创建对象,它们通常隐藏了 allocinit 的细节。在这种情况下,你不需要手动调用 allocinit

例如,NSString 类的 stringWithString: 方法:

NSString *string = [NSString stringWithString:@"Hello"];

这个工厂方法内部会完成对象的创建和初始化,因此你不需要显式地调用 allocinit

同理,其他常用的类也提供类似的方法,比如:

NSArray *array = [NSArray arrayWithObjects:@"A", @"B", @"C", nil];

2. 已初始化的对象

当你接收到一个已经初始化的对象时,你不需要再次调用 init。例如,如果你通过其他方法或函数获得了对象,它已经是完全可用的了。

特别情况

1. init 方法返回 nil

如果对象初始化失败(例如资源分配不成功),init 方法可能会返回 nil。因此,初始化对象时,最好检查返回值:

MyClass *object = [[MyClass alloc] init];
if (object) {
    // 成功初始化
} else {
    // 初始化失败,处理错误
}

2. alloc 但不 init 的错误示例

如果你只调用 alloc 而不调用 init,对象没有被正确初始化,可能导致不可预见的错误。比如:

MyClass *object = [MyClass alloc]; // 忘记了调用 init

总结

  • alloc 分配内存,init 初始化对象。调用 alloc 后,通常必须调用 init 或其他初始化方法。
  • 自定义类时,如果需要自定义初始化逻辑,可以重写 init 方法。
  • 使用类工厂方法(如 stringWithString:)时不需要显式调用 allocinit,这些方法已经处理了对象的初始化。
  • 避免只 alloc 而不 init 的情况,否则对象可能未初始化,无法安全使用。