Swift - Инициализация
Классы, структуры и перечисления, однажды объявленные в Swift 4, инициализируются для подготовки экземпляра класса. Начальное значение инициализируется для сохраненного свойства, а также для новых экземпляров значения инициализируются для продолжения. Ключевое слово для создания функции инициализации выполняется методом init (). Инициализатор Swift 4 отличается от Objective-C тем, что не возвращает никаких значений. Его функция - проверять инициализацию вновь созданных экземпляров перед их обработкой. Swift 4 также предоставляет процесс «деинициализации» для выполнения операций управления памятью после освобождения экземпляров.
Роль инициализатора для сохраненных свойств
Сохраненное свойство должно инициализировать экземпляры для своих классов и структур перед обработкой экземпляров. Сохраненные свойства используют инициализатор для присвоения и инициализации значений, тем самым устраняя необходимость вызова наблюдателей за свойствами. Инициализатор используется в сохраненном свойстве
Для создания начального значения.
Чтобы присвоить значение свойства по умолчанию в определении свойства.
Для инициализации экземпляра для определенного типа данных используется init (). Внутри функции init () аргументы не передаются.
Синтаксис
init() {
//New Instance initialization goes here
}
пример
struct rectangle {
var length: Double
var breadth: Double
init() {
length = 6
breadth = 12
}
}
var area = rectangle()
print("area of rectangle is \(area.length*area.breadth)")
Когда мы запускаем вышеуказанную программу с помощью игровой площадки, мы получаем следующий результат:
area of rectangle is 72.0
Здесь структура «прямоугольник» инициализируется с элементами длины и ширины как типы данных «Double». Метод Init () используется для инициализации значений вновь созданных членов length и double. Площадь прямоугольника вычисляется и возвращается путем вызова функции прямоугольника.
Установка значений свойств по умолчанию
Язык Swift 4 предоставляет функцию Init () для инициализации сохраненных значений свойств. Кроме того, пользователь может инициализировать значения свойств по умолчанию при объявлении членов класса или структуры. Когда свойство принимает одно и то же значение во всей программе, мы можем объявить его только в разделе объявления, а не инициализировать его в init (). Установка значений свойств по умолчанию позволяет пользователю, если для классов или структур определено наследование.
struct rectangle {
var length = 6
var breadth = 12
}
var area = rectangle()
print("area of rectangle is \(area.length*area.breadth)")
Когда мы запускаем вышеуказанную программу с помощью игровой площадки, мы получаем следующий результат:
area of rectangle is 72
Здесь вместо объявления длины и ширины в init () значения инициализируются в самом объявлении.
Инициализация параметров
В языке Swift 4 пользователь может инициализировать параметры как часть определения инициализатора с помощью init ().
struct Rectangle {
var length: Double
var breadth: Double
var area: Double
init(fromLength length: Double, fromBreadth breadth: Double) {
self.length = length
self.breadth = breadth
area = length * breadth
}
init(fromLeng leng: Double, fromBread bread: Double) {
self.length = leng
self.breadth = bread
area = leng * bread
}
}
let ar = Rectangle(fromLength: 6, fromBreadth: 12)
print("area is: \(ar.area)")
let are = Rectangle(fromLeng: 36, fromBread: 12)
print("area is: \(are.area)")
Когда мы запускаем вышеуказанную программу с помощью игровой площадки, мы получаем следующий результат:
area is: 72.0
area is: 432.0
Локальные и внешние параметры
Параметры инициализации имеют как локальные, так и глобальные имена параметров, аналогичные именам параметров функции и метода. Объявление локального параметра используется для доступа в теле инициализации, а объявление внешнего параметра используется для вызова инициализатора. Инициализаторы Swift 4 отличаются от инициализатора функций и методов тем, что они не определяют, какой инициализатор используется для вызова каких функций.
Чтобы преодолеть это, Swift 4 вводит автоматическое внешнее имя для каждого параметра в init (). Это автоматическое внешнее имя эквивалентно локальному имени, записанному перед каждым параметром инициализации.
struct Days {
let sunday, monday, tuesday: Int
init(sunday: Int, monday: Int, tuesday: Int) {
self.sunday = sunday
self.monday = monday
self.tuesday = tuesday
}
init(daysofaweek: Int) {
sunday = daysofaweek
monday = daysofaweek
tuesday = daysofaweek
}
}
let week = Days(sunday: 1, monday: 2, tuesday: 3)
print("Days of a Week is: \(week.sunday)")
print("Days of a Week is: \(week.monday)")
print("Days of a Week is: \(week.tuesday)")
let weekdays = Days(daysofaweek: 4)
print("Days of a Week is: \(weekdays.sunday)")
print("Days of a Week is: \(weekdays.monday)")
print("Days of a Week is: \(weekdays.tuesday)")
Когда мы запускаем вышеуказанную программу с помощью игровой площадки, мы получаем следующий результат:
Days of a Week is: 1
Days of a Week is: 2
Days of a Week is: 3
Days of a Week is: 4
Days of a Week is: 4
Days of a Week is: 4
Параметры без внешних имен
Когда внешнее имя не требуется для инициализации, подчеркивание используется для отмены поведения по умолчанию.
struct Rectangle {
var length: Double
init(frombreadth breadth: Double) {
length = breadth * 10
}
init(frombre bre: Double) {
length = bre * 30
}
init(_ area: Double) {
length = area
}
}
let rectarea = Rectangle(180.0)
print("area is: \(rectarea.length)")
let rearea = Rectangle(370.0)
print("area is: \(rearea.length)")
let recarea = Rectangle(110.0)
print("area is: \(recarea.length)")
Когда мы запускаем вышеуказанную программу с помощью игровой площадки, мы получаем следующий результат:
area is: 180.0
area is: 370.0
area is: 110.0
Дополнительные типы свойств
Когда сохраненное свойство в некотором экземпляре не возвращает никакого значения, это свойство объявляется с «необязательным» типом, указывающим, что для этого конкретного типа не возвращается «никакого значения». Когда сохраненное свойство объявлено как «необязательное», оно автоматически инициализирует значение «nil» во время самой инициализации.
struct Rectangle {
var length: Double?
init(frombreadth breadth: Double) {
length = breadth * 10
}
init(frombre bre: Double) {
length = bre * 30
}
init(_ area: Double) {
length = area
}
}
let rectarea = Rectangle(180.0)
print("area is: \(rectarea.length)")
let rearea = Rectangle(370.0)
print("area is: \(rearea.length)")
let recarea = Rectangle(110.0)
print("area is: \(recarea.length)")
Когда мы запускаем вышеуказанную программу с помощью игровой площадки, мы получаем следующий результат:
area is: Optional(180.0)
area is: Optional(370.0)
area is: Optional(110.0)
Изменение постоянных свойств во время инициализации
Инициализация также позволяет пользователю изменять значение постоянного свойства. Во время инициализации свойство класса позволяет изменять его экземпляры класса суперклассом, а не подклассом. Рассмотрим, например, в предыдущей программе «длина» объявлена как «переменная» в основном классе. Приведенная ниже программная переменная "длина" изменена как "постоянная" переменная.
struct Rectangle {
let length: Double?
init(frombreadth breadth: Double) {
length = breadth * 10
}
init(frombre bre: Double) {
length = bre * 30
}
init(_ area: Double) {
length = area
}
}
let rectarea = Rectangle(180.0)
print("area is: \(rectarea.length)")
let rearea = Rectangle(370.0)
print("area is: \(rearea.length)")
let recarea = Rectangle(110.0)
print("area is: \(recarea.length)")
Когда мы запускаем вышеуказанную программу с помощью игровой площадки, мы получаем следующий результат:
area is: Optional(180.0)
area is: Optional(370.0)
area is: Optional(110.0)
Инициализаторы по умолчанию
Инициализаторы по умолчанию предоставляют новый экземпляр для всех объявленных свойств базового класса или структуры со значениями по умолчанию.
class defaultexample {
var studname: String?
var stmark = 98
var pass = true
}
var result = defaultexample()
print("result is: \(result.studname)")
print("result is: \(result.stmark)")
print("result is: \(result.pass)")
Когда мы запускаем вышеуказанную программу с помощью игровой площадки, мы получаем следующий результат. -
result is: nil
result is: 98
result is: true
Вышеупомянутая программа определена с именем класса как defaultexample. Три функции-члена инициализируются по умолчанию как «имя группы?» для хранения значений 'nil', 'stmark' как 98 и 'pass' как логическое значение 'true'. Аналогичным образом значения членов в классе могут быть инициализированы по умолчанию перед обработкой типов членов класса.
Поэлементные инициализаторы для типов структур
Когда пользовательские инициализаторы не предоставляются пользователем, типы структур в Swift 4 автоматически получат «поэлементный инициализатор». Его основная функция - инициализировать новые экземпляры структуры с помощью поэлементной инициализации по умолчанию, а затем новые свойства экземпляра передаются элементарной инициализации по имени.
struct Rectangle {
var length = 100.0, breadth = 200.0
}
let area = Rectangle(length: 24.0, breadth: 32.0)
print("Area of rectangle is: \(area.length)")
print("Area of rectangle is: \(area.breadth)")
Когда мы запускаем вышеуказанную программу с помощью игровой площадки, мы получаем следующий результат:
Area of rectangle is: 24.0
Area of rectangle is: 32.0
Структуры инициализируются по умолчанию для своих функций принадлежности во время инициализации для «длины» как «100,0» и «ширины» как «200,0». Но значения переопределяются во время обработки переменных length и width как 24.0 и 32.0.
Делегирование инициализатора для типов значений
Делегирование инициализатора определяется как вызов инициализаторов из других инициализаторов. Его основная функция заключается в возможности повторного использования, чтобы избежать дублирования кода в нескольких инициализаторах.
struct Stmark {
var mark1 = 0.0, mark2 = 0.0
}
struct stdb {
var m1 = 0.0, m2 = 0.0
}
struct block {
var average = stdb()
var result = Stmark()
init() {}
init(average: stdb, result: Stmark) {
self.average = average
self.result = result
}
init(avg: stdb, result: Stmark) {
let tot = avg.m1 - (result.mark1 / 2)
let tot1 = avg.m2 - (result.mark2 / 2)
self.init(average: stdb(m1: tot, m2: tot1), result: result)
}
}
let set1 = block()
print("student result is: \(set1.average.m1, set1.average.m2)
\(set1.result.mark1, set1.result.mark2)")
let set2 = block(average: stdb(m1: 2.0, m2: 2.0),
result: Stmark(mark1: 5.0, mark2: 5.0))
print("student result is: \(set2.average.m1, set2.average.m2)
\(set2.result.mark1, set2.result.mark2)")
let set3 = block(avg: stdb(m1: 4.0, m2: 4.0),
result: Stmark(mark1: 3.0, mark2: 3.0))
print("student result is: \(set3.average.m1, set3.average.m2)
\(set3.result.mark1, set3.result.mark2)")
Когда мы запускаем вышеуказанную программу с помощью игровой площадки, мы получаем следующий результат:
(0.0,0.0) (0.0,0.0)
(2.0,2.0) 5.0,5.0)
(2.5,2.5) (3.0,3.0)
Правила делегирования инициализатора
Типы значений | Типы классов |
---|---|
Наследование не поддерживается для типов значений, таких как структуры и перечисления. Обращение к другим инициализаторам осуществляется через self.init | Наследование поддерживается. Проверяет, что все сохраненные значения свойств инициализированы |
Наследование и инициализация классов
Типы классов имеют два вида инициализаторов, чтобы проверить, получают ли определенные сохраненные свойства начальное значение, а именно назначенные инициализаторы и удобные инициализаторы.
Назначенные инициализаторы и удобные инициализаторы
Назначенный инициализатор | Инициализатор удобства |
---|---|
Считается первичной инициализацией класса | Считается поддержкой инициализации для класса |
Все свойства класса инициализируются, и для дальнейшей инициализации вызывается соответствующий инициализатор суперкласса. | Назначенный инициализатор вызывается с удобным инициализатором для создания экземпляра класса для определенного варианта использования или типа входного значения. |
По крайней мере, один назначенный инициализатор определен для каждого класса | Нет необходимости в обязательном определении удобных инициализаторов, если класс не требует инициализаторов. |
Init (параметры) {операторы} | удобство init (параметры) {операторы} |
Программа для назначенных инициализаторов
class mainClass {
var no1 : Int // local storage
init(no1 : Int) {
self.no1 = no1 // initialization
}
}
class subClass : mainClass {
var no2 : Int // new subclass storage
init(no1 : Int, no2 : Int) {
self.no2 = no2 // initialization
super.init(no1:no1) // redirect to superclass
}
}
let res = mainClass(no1: 10)
let print = subClass(no1: 10, no2: 20)
print("res is: \(res.no1)")
print("res is: \(print.no1)")
print("res is: \(print.no2)")
Когда мы запускаем вышеуказанную программу с помощью игровой площадки, мы получаем следующий результат:
res is: 10
res is: 10
res is: 20
Программа для удобных инициализаторов
class mainClass {
var no1 : Int // local storage
init(no1 : Int) {
self.no1 = no1 // initialization
}
}
class subClass : mainClass {
var no2 : Int
init(no1 : Int, no2 : Int) {
self.no2 = no2
super.init(no1:no1)
}
// Requires only one parameter for convenient method
override convenience init(no1: Int) {
self.init(no1:no1, no2:0)
}
}
let res = mainClass(no1: 20)
let print = subClass(no1: 30, no2: 50)
print("res is: \(res.no1)")
print("res is: \(print.no1)")
print("res is: \(print.no2)")
Когда мы запускаем вышеуказанную программу с помощью игровой площадки, мы получаем следующий результат:
res is: 20
res is: 30
res is: 50
Наследование и переопределение инициализатора
Swift 4 не позволяет своим подклассам наследовать инициализаторы суперкласса для своих типов членов по умолчанию. Наследование применимо к инициализаторам суперкласса только в некоторой степени, что будет обсуждаться в разделе «Автоматическое наследование инициализатора».
Когда пользователю необходимо определить инициализаторы в суперклассе, подкласс с инициализаторами должен быть определен пользователем как пользовательская реализация. Когда должно быть выполнено переопределение подклассом, необходимо объявить ключевое слово суперкласса override.
class sides {
var corners = 4
var description: String {
return "\(corners) sides"
}
}
let rectangle = sides()
print("Rectangle: \(rectangle.description)")
class pentagon: sides {
override init() {
super.init()
corners = 5
}
}
let bicycle = pentagon()
print("Pentagon: \(bicycle.description)")
Когда мы запускаем вышеуказанную программу с помощью игровой площадки, мы получаем следующий результат:
Rectangle: 4 sides
Pentagon: 5 sides
Назначенные и удобные инициализаторы в действии
class Planet {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[No Planets]")
}
}
let plName = Planet(name: "Mercury")
print("Planet name is: \(plName.name)")
let noplName = Planet()
print("No Planets like that: \(noplName.name)")
class planets: Planet {
var count: Int
init(name: String, count: Int) {
self.count = count
super.init(name: name)
}
override convenience init(name: String) {
self.init(name: name, count: 1)
}
}
Когда мы запускаем вышеуказанную программу с помощью игровой площадки, мы получаем следующий результат:
Planet name is: Mercury
No Planets like that: [No Planets]
Неудачный инициализатор
Пользователь должен быть уведомлен о сбоях инициализатора при определении класса, структуры или значений перечисления. Инициализация переменных иногда становится неудачной из-за:
- Неверные значения параметров.
- Отсутствие необходимого внешнего источника.
- Условие, препятствующее успешной инициализации.
Чтобы перехватить исключения, вызванные методом инициализации, Swift 4 создает гибкую инициализацию, называемую «сбойный инициализатор», чтобы уведомить пользователя о том, что что-то осталось незамеченным при инициализации элементов структуры, класса или перечисления. Ключевое слово для обнаружения сбойного инициализатора - «init?». Кроме того, отказоустойчивые и исправные инициализаторы не могут быть определены с одинаковыми типами параметров и именами.
struct studrecord {
let stname: String
init?(stname: String) {
if stname.isEmpty {return nil }
self.stname = stname
}
}
let stmark = studrecord(stname: "Swing")
if let name = stmark {
print("Student name is specified")
}
let blankname = studrecord(stname: "")
if blankname == nil {
print("Student name is left blank")
}
Когда мы запускаем вышеуказанную программу с помощью игровой площадки, мы получаем следующий результат:
Student name is specified
Student name is left blank
Неудачные инициализаторы для перечислений
Язык Swift 4 обеспечивает гибкость использования инициализаторов Failable для перечислений, чтобы уведомлять пользователя, когда члены перечисления не инициализируют значения.
enum functions {
case a, b, c, d
init?(funct: String) {
switch funct {
case "one":
self = .a
case "two":
self = .b
case "three":
self = .c
case "four":
self = .d
default:
return nil
}
}
}
let result = functions(funct: "two")
if result != nil {
print("With In Block Two")
}
let badresult = functions(funct: "five")
if badresult == nil {
print("Block Does Not Exist")
}
Когда мы запускаем вышеуказанную программу с помощью игровой площадки, мы получаем следующий результат:
With In Block Two
Block Does Not Exist
Неудачные инициализаторы для классов
Неудачный инициализатор, объявленный с перечислениями и структурами, предупреждает об ошибке инициализации при любых обстоятельствах в рамках своей реализации. Однако неудачный инициализатор в классах будет предупреждать об ошибке только после того, как для сохраненных свойств будет установлено начальное значение.
class studrecord {
let studname: String!
init?(studname: String) {
self.studname = studname
if studname.isEmpty { return nil }
}
}
if let stname = studrecord(studname: "Failable Initializers") {
print("Module is \(stname.studname)")
}
Когда мы запускаем вышеуказанную программу с помощью игровой площадки, мы получаем следующий результат:
Module is Optional("Failable Initializers")
Отмена неудачного инициализатора
Как и при инициализации, у пользователя также есть возможность переопределить отказоустойчивый инициализатор суперкласса внутри подкласса. Отказоустойчивая инициализация суперкласса также может быть переопределена в неотказном инициализаторе подкласса.
Инициализатор подкласса не может делегировать полномочия инициализатору суперкласса при замене отказавшего инициализатора суперкласса с помощью инициализатора подкласса без сбоя.
Неисправный инициализатор никогда не может делегировать отказавшему инициализатору.
В приведенной ниже программе описаны отказоустойчивые и исправные инициализаторы.
class Planet {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[No Planets]")
}
}
let plName = Planet(name: "Mercury")
print("Planet name is: \(plName.name)")
let noplName = Planet()
print("No Planets like that: \(noplName.name)")
class planets: Planet {
var count: Int
init(name: String, count: Int) {
self.count = count
super.init(name: name)
}
override convenience init(name: String) {
self.init(name: name, count: 1)
}
}
Когда мы запускаем вышеуказанную программу с помощью игровой площадки, мы получаем следующий результат:
Planet name is: Mercury
No Planets like that: [No Planets]
Файл init! Неудачный инициализатор
Swift 4 предоставляет init? для определения необязательного сбойного инициализатора экземпляра. Для определения неявно развернутого необязательного экземпляра определенного типа 'init!' указан.
struct studrecord {
let stname: String
init!(stname: String) {
if stname.isEmpty {return nil }
self.stname = stname
}
}
let stmark = studrecord(stname: "Swing")
if let name = stmark {
print("Student name is specified")
}
let blankname = studrecord(stname: "")
if blankname == nil {
print("Student name is left blank")
}
Когда мы запускаем вышеуказанную программу с помощью игровой площадки, мы получаем следующий результат:
Student name is specified
Student name is left blank
Необходимые инициализаторы
Чтобы объявить каждый подкласс ключевого слова initialize 'required', необходимо определить до функции init ().
class classA {
required init() {
var a = 10
print(a)
}
}
class classB: classA {
required init() {
var b = 30
print(b)
}
}
let res = classA()
let print = classB()
Когда мы запускаем вышеуказанную программу с помощью игровой площадки, мы получаем следующий результат:
10
30
10