IOS面试题——Swift初始化器(8)

一 面试题汇总

  1. 指定初始化器和便捷初始化器有什么区别?required
  2. 重写父类指定初始化器和便捷初始化器有何区别?
  3. 初始化器自动继承的规则?
  4. 初始化器中赋值会触发属性观察器么?
  5. 初始化器中赋值会触发属性观察器么?

二 面试题解答(仅供参考)

2.1 指定初始化器和便捷初始化器有什么区别?required

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
在 Swift 中,指定初始化器(Designated Initializer)
和便捷初始化器(Convenience Initializer)是两种不同类型的初始化器,
它们在类中的作用和使用场景有所不同。

1-指定初始化器(Designated Initializer):
1.1-指定初始化器是类中的主要初始化器,它负责初始化类的所有存储属性,
并且它至少需要调用直接父类的指定初始化器(如果有父类的话)。
1.2-一个类至少要有一个指定初始化器。如果没有手动定义指定初始化器,
编译器会自动生成一个不带参数的默认指定初始化器。
1.3-通过 init 关键字声明,不带 convenience 关键字。

2-便捷初始化器(Convenience Initializer):
2.1-便捷初始化器是类中的辅助初始化器,它可以调用同一个类中的其他初始化器
(包括指定初始化器和其他便捷初始化器),但不能直接初始化类的存储属性。
2.2-便捷初始化器通常用于提供更便捷的初始化方式,避免代码重复和增加灵活性。
2.3-通过 convenience init 关键字声明。

3-required 关键字:
3.1-在 Swift 中,如果子类重写了父类的指定初始化器,
那么必须在子类的初始化器前面添加 required 关键字,以确保所有子类都实现了这个初始化器。
3.2-用 required 修饰的初始化器要求其所有子类都必须实现该初始化器。

2.2 重写父类指定初始化器和便捷初始化器有何区别?

1
2
3
4
5
6
7
8
9
10
11
12
13
在 Swift 中,子类可以重写父类的指定初始化器(Designated Initializer)
和便捷初始化器(Convenience Initializer),它们之间存在一些区别:

1-指定初始化器的重写:

1.1子类可以重写父类的指定初始化器。
重写的指定初始化器在参数列表和返回类型上必须与父类的指定初始化器相匹配。
1.2-子类重写父类的指定初始化器时,不需要添加 override 关键字,因为它们属于构造函数,不是方法。

2-便捷初始化器的重写:

2.1-子类也可以重写父类的便捷初始化器,但是在重写时需要添加 override 关键字。
2.2-子类重写父类的便捷初始化器时,参数列表和返回类型必须与父类的便捷初始化器相匹配。

2.3 初始化器自动继承的规则?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
在 Swift 中,子类默认会继承父类的初始化器,但是有一些限制和规则:

1.如果子类没有定义任何指定初始化器(designated initializer):
子类会自动继承父类所有的指定初始化器和便捷初始化器。

2-如果子类提供了父类所有指定初始化器的实现:
子类会自动继承父类的所有便捷初始化器。

3-如果子类提供了父类某些指定初始化器的实现:
子类不会继承父类相同参数列表的指定初始化器。
这是因为父类的指定初始化器可能对子类的属性进行初始化,而子类可能拥有父类没有的属性,
所以编译器无法保证父类的指定初始化器可以正确初始化子类的所有属性。

如果子类希望继承父类的某个指定初始化器,需要使用 override 关键字显式地重写该初始化器。

4-如果子类重写了所有父类的指定初始化器:
子类会自动继承父类的所有便捷初始化器。

2.4 初始化器中赋值会触发属性观察器么?

1
2
3
在 Swift 中,初始化器中对属性的赋值不会触发属性观察器。
属性观察器(willSet 和 didSet)仅在属性的值在初始化器外部被设置时才会被调用,
而不是在初始化器内部赋值的时候

2.5 初始化器中赋值会触发属性观察器么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
在 Swift 中,属性的初始化器赋值会触发属性观察器的调用,包括在初始化器内部对属性的赋值。
属性观察器(willSet 和 didSet)会在属性的值被设置时被调用,
无论是在初始化器内部还是在其他地方进行属性赋值。

示例:

class MyClass {
var value: Int {
didSet {
print("Value changed to \(value)")
}
}

init() {
value = 0 // 在初始化器内部对属性进行赋值,会触发属性观察器
}
}

let myObject = MyClass() // 输出: "Value changed to 0"

在这个示例中,当 MyClass 的实例被初始化时,初始化器内部对 value 属性进行了赋值,
这个赋值操作触发了 didSet 属性观察器的调用,打印出了属性值变化的信息。

三 参考

  • 简书—Swift初始化器