Від док
Перевірка безпеки 1
Призначений ініціалізатор повинен забезпечити ініціалізацію всіх властивостей, введених його класом, до того, як він делегує ініціалізатор надкласового класу.
Навіщо нам потрібна така перевірка безпеки?
Щоб відповісти на це, ми можемо пройти процес швидкої ініціалізації.
Двофазна ініціалізація
Ініціалізація класів у Swift - це двофазний процес. На першій фазі кожному збереженому властивості присвоюється початкове значення класом, який його ввів. Після того, як визначено початковий стан для кожного збереженого властивості, починається другий етап, і кожному класу надається можливість додатково налаштувати свої збережені властивості до того, як новий екземпляр вважатиметься готовим до використання.
Використання двофазного процесу ініціалізації робить ініціалізацію безпечною, одночасно надаючи повну гнучкість кожному класу в ієрархії класів. Двофазна ініціалізація перешкоджає доступу до значень властивостей до їх ініціалізації , а також запобігає несподіваному встановленню іншого значення на інше значення іншим ініціалізатором.
Отже, щоб переконатися, що процес ініціалізації в два етапи виконується, як визначено вище, є чотири перевірки безпеки, одна з них:
Перевірка безпеки 1
Призначений ініціалізатор повинен забезпечити ініціалізацію всіх властивостей, введених його класом, до того, як він делегує ініціалізатор надкласового класу.
Тепер двофазова ініціалізація ніколи не говорить про порядок, але ця перевірка безпеки вводить super.init
впорядковано після ініціалізації всіх властивостей.
Перевірка безпеки 1 може здатися неактуальною, оскільки
двофазна ініціалізація запобігає доступу до значень властивостей до того, як їх ініціалізувати можна буде виконати, без цієї перевірки безпеки 1.
Як і в цьому зразку
class Shape {
var name: String
var sides : Int
init(sides:Int, named: String) {
self.sides = sides
self.name = named
}
}
class Triangle: Shape {
var hypotenuse: Int
init(hypotenuse:Int) {
super.init(sides: 3, named: "Triangle")
self.hypotenuse = hypotenuse
}
}
Triangle.init
ініціалізується, кожне властивість перед використанням. Тому перевірка безпеки 1 видається нерелевантною,
Але тоді може бути інший сценарій, трохи складний,
class Shape {
var name: String
var sides : Int
init(sides:Int, named: String) {
self.sides = sides
self.name = named
printShapeDescription()
}
func printShapeDescription() {
print("Shape Name :\(self.name)")
print("Sides :\(self.sides)")
}
}
class Triangle: Shape {
var hypotenuse: Int
init(hypotenuse:Int) {
self.hypotenuse = hypotenuse
super.init(sides: 3, named: "Triangle")
}
override func printShapeDescription() {
super.printShapeDescription()
print("Hypotenuse :\(self.hypotenuse)")
}
}
let triangle = Triangle(hypotenuse: 12)
Вихід:
Shape Name :Triangle
Sides :3
Hypotenuse :12
Тут, якби ми зателефонували super.init
до встановлення цього hypotenuse
, super.init
виклик тоді закликав би те, printShapeDescription()
і оскільки це було відмінено, він би вперше відступив до реалізації класу Triangle printShapeDescription()
. Клас printShapeDescription()
Triangle має доступ до hypotenuse
необов'язкового властивості, яке ще не було ініціалізовано. І це не дозволено як двофазна ініціалізація перешкоджає доступу до значень властивостей перед їх ініціалізацією
Тому переконайтеся, що двофазова ініціалізація виконана так, як визначено, має бути певний порядок виклику super.init
, тобто після ініціалізації всіх властивостей, введених self
класом, таким чином нам потрібна перевірка безпеки 1