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