Swift - Inicialización

Las clases, estructuras y enumeraciones una vez declaradas en Swift 4 se inicializan para preparar la instancia de una clase. El valor inicial se inicializa para la propiedad almacenada y también para las nuevas instancias, los valores se inicializan para continuar. La palabra clave para crear la función de inicialización se lleva a cabo mediante el método 'init ()'. El inicializador Swift 4 difiere de Objective-C en que no devuelve ningún valor. Su función es verificar la inicialización de instancias recién creadas antes de su procesamiento. Swift 4 también proporciona un proceso de 'desinicialización' para realizar operaciones de administración de memoria una vez que se desasignan las instancias.

Rol de inicializador para propiedades almacenadas

La propiedad almacenada tiene que inicializar las instancias para sus clases y estructuras antes de procesar las instancias. Las propiedades almacenadas usan el inicializador para asignar e inicializar valores, erradicando así la necesidad de llamar a observadores de propiedades. El inicializador se usa en la propiedad almacenada

  • Para crear un valor inicial.

  • Para asignar un valor de propiedad predeterminado dentro de la definición de propiedad.

  • Para inicializar una instancia para un tipo de datos particular, se usa 'init ()'. No se pasan argumentos dentro de la función init ().

Sintaxis

init() {
   //New Instance initialization goes here
}

Ejemplo

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)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

area of rectangle is 72.0

Aquí, la estructura 'rectángulo' se inicializa con miembros de longitud y anchura como tipos de datos 'Doble'. El método Init () se utiliza para inicializar los valores de la longitud y el doble de los miembros recién creados. El área del rectángulo se calcula y se devuelve llamando a la función rectángulo.

Establecer valores de propiedad de forma predeterminada

El lenguaje Swift 4 proporciona la función Init () para inicializar los valores de propiedad almacenados. Además, el usuario tiene la posibilidad de inicializar los valores de propiedad de forma predeterminada mientras declara los miembros de la clase o estructura. Cuando la propiedad toma el mismo valor solo en todo el programa, podemos declararlo solo en la sección de declaración en lugar de inicializarlo en init (). Establecer valores de propiedad de forma predeterminada habilita al usuario cuando se define la herencia para clases o estructuras.

struct rectangle {
   var length = 6
   var breadth = 12
}

var area = rectangle()
print("area of rectangle is \(area.length*area.breadth)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

area of rectangle is 72

Aquí, en lugar de declarar la longitud y la amplitud en init (), los valores se inicializan en la declaración misma.

Inicialización de parámetros

En el lenguaje Swift 4, el usuario tiene la posibilidad de inicializar parámetros como parte de la definición del inicializador usando 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)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

area is: 72.0
area is: 432.0

Parámetros locales y externos

Los parámetros de inicialización tienen nombres de parámetros locales y globales similares a los de los parámetros de función y método. La declaración de parámetro local se usa para acceder dentro del cuerpo de inicialización y la declaración de parámetro externo se usa para llamar al inicializador. Los inicializadores de Swift 4 difieren del inicializador de funciones y métodos en que no identifican qué inicializador se usa para llamar a qué funciones.

Para superar esto, Swift 4 introduce un nombre externo automático para todos y cada uno de los parámetros en init (). Este nombre externo automático es equivalente al nombre local escrito antes de cada parámetro de inicialización.

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)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

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

Parámetros sin nombres externos

Cuando no se necesita un nombre externo para un guión bajo de inicialización, se usa '_' para anular el comportamiento predeterminado.

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)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

area is: 180.0
area is: 370.0
area is: 110.0

Tipos de propiedad opcionales

Cuando la propiedad almacenada en alguna instancia no devuelve ningún valor, esa propiedad se declara con un tipo "opcional" que indica que "no se devuelve ningún valor" para ese tipo en particular. Cuando la propiedad almacenada se declara como 'opcional', automáticamente inicializa el valor para que sea 'nulo' durante la inicialización.

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)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

area is: Optional(180.0)
area is: Optional(370.0)
area is: Optional(110.0)

Modificación de propiedades constantes durante la inicialización

La inicialización también permite al usuario modificar el valor de la propiedad constante. Durante la inicialización, la propiedad de clase permite que sus instancias de clase sean modificadas por la superclase y no por la subclase. Considere, por ejemplo, que en el programa anterior 'longitud' se declara como 'variable' en la clase principal. La siguiente variable de programa 'longitud' se modifica como variable 'constante'.

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)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

area is: Optional(180.0)
area is: Optional(370.0)
area is: Optional(110.0)

Inicializadores predeterminados

Los inicializadores predeterminados proporcionan una nueva instancia a todas sus propiedades declaradas de clase base o estructura con valores predeterminados.

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)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado. -

result is: nil
result is: 98
result is: true

El programa anterior se define con el nombre de clase como 'ejemplo predeterminado'. Tres funciones miembro se inicializan de forma predeterminada como 'studname?' para almacenar valores 'nil', 'stmark' como 98 y 'pass' como valor booleano 'true'. Asimismo, los valores de los miembros de la clase se pueden inicializar de forma predeterminada antes de procesar los tipos de miembros de la clase.

Inicializadores Memberwise para tipos de estructura

Cuando el usuario no proporciona los inicializadores personalizados, los tipos de estructura en Swift 4 recibirán automáticamente el 'inicializador de miembros'. Su función principal es inicializar las nuevas instancias de estructura con la inicialización de miembro por defecto y luego las propiedades de la nueva instancia se pasan a la inicialización de miembro por nombre.

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)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Area of rectangle is: 24.0
Area of rectangle is: 32.0

Las estructuras se inicializan de forma predeterminada para sus funciones de pertenencia durante la inicialización para 'longitud' como '100.0' y 'amplitud' como '200.0'. Pero los valores se anulan durante el procesamiento de las variables longitud y amplitud como 24.0 y 32.0.

Delegación de inicializador para tipos de valor

La delegación de inicializadores se define como la llamada a inicializadores desde otros inicializadores. Su función principal es actuar como reutilización para evitar la duplicación de código en varios inicializadores.

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)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

(0.0,0.0) (0.0,0.0)
(2.0,2.0) 5.0,5.0)
(2.5,2.5) (3.0,3.0)

Reglas para la delegación del inicializador

Tipos de valor Tipos de clases
La herencia no se admite para tipos de valor como estructuras y enumeraciones. La referencia a otros inicializadores se realiza a través de self.init Se admite la herencia. Comprueba que todos los valores de propiedad almacenados estén inicializados

Herencia e inicialización de clases

Los tipos de clase tienen dos tipos de inicializadores para comprobar si las propiedades almacenadas definidas reciben un valor inicial, a saber, inicializadores designados e inicializadores de conveniencia.

Inicializadores designados e inicializadores de conveniencia

Inicializador designado Inicializador de conveniencia
Considerado como inicializaciones primarias para una clase Considerado como soporte de inicialización para una clase
Todas las propiedades de la clase se inicializan y se llama al inicializador de superclase apropiado para una inicialización adicional El inicializador designado se llama con un inicializador de conveniencia para crear una instancia de clase para un caso de uso específico o un tipo de valor de entrada
Se define al menos un inicializador designado para cada clase No es necesario tener definidos inicializadores de conveniencia obligatorios cuando la clase no requiere inicializadores.
Init (parámetros) {declaraciones} conveniencia init (parámetros) {declaraciones}

Programa para inicializadores designados

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)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

res is: 10
res is: 10
res is: 20

Programa para inicializadores de conveniencia

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)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

res is: 20
res is: 30
res is: 50

Herencia y anulación del inicializador

Swift 4 no permite que sus subclases hereden sus inicializadores de superclase para sus tipos de miembros de forma predeterminada. La herencia es aplicable a los inicializadores Superclase solo hasta cierto punto, lo que se discutirá en Herencia del inicializador automático.

Cuando el usuario necesita tener inicializadores definidos en superclase, el usuario debe definir una subclase con inicializadores como implementación personalizada. Cuando la subclase debe realizar la anulación a la superclase, se debe declarar la palabra clave 'anular'.

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)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Rectangle: 4 sides
Pentagon: 5 sides

Inicializadores designados y convenientes en acción

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)
   }
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Planet name is: Mercury
No Planets like that: [No Planets]

Inicializador fallido

El usuario debe ser notificado cuando haya fallas en el inicializador al definir una clase, estructura o valores de enumeración. La inicialización de variables a veces se convierte en una falla debido a:

  • Valores de parámetro no válidos.
  • Ausencia de fuente externa requerida.
  • Condición que impide que la inicialización se realice correctamente.

Para detectar las excepciones generadas por el método de inicialización, Swift 4 produce una inicialización flexible llamada 'inicializador fallido' para notificar al usuario que algo pasa desapercibido al inicializar la estructura, clase o miembros de enumeración. La palabra clave para detectar el inicializador fallido es 'init?'. Además, los inicializadores fallidos y no fallidos no se pueden definir con los mismos tipos y nombres de parámetros.

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")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Student name is specified
Student name is left blank

Inicializadores fallidos para enumeraciones

El lenguaje Swift 4 proporciona la flexibilidad de tener inicializadores Failable para enumeraciones también para notificar al usuario cuando los miembros de la enumeración quedan sin inicializar valores.

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")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

With In Block Two
Block Does Not Exist

Inicializadores fallidos para clases

Un inicializador que falla cuando se declara con enumeraciones y estructuras alerta de una falla de inicialización en cualquier circunstancia dentro de su implementación. Sin embargo, el inicializador que falla en las clases alertará sobre la falla solo después de que las propiedades almacenadas se hayan establecido en un valor inicial.

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)")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Module is Optional("Failable Initializers")

Anulación de un inicializador fallido

Al igual que en el caso de inicializar, el usuario también tiene la posibilidad de anular un inicializador fallido de superclase dentro de la subclase. La inicialización fallida de superclase también se puede anular con un inicializador no fallido de subclase.

El inicializador de subclase no puede delegar hasta el inicializador de superclase cuando se reemplaza un inicializador de superclase que falla con una inicialización de subclase que no falla.

Un inicializador que no falla nunca puede delegar en un inicializador que falla.

El programa que se proporciona a continuación describe los inicializadores fallidos y no fallidos.

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)
   }
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Planet name is: Mercury
No Planets like that: [No Planets]

El init! Inicializador fallido

Swift 4 proporciona 'init?' para definir un inicializador fallable de instancia opcional. Para definir una instancia opcional implícitamente desenvuelta del tipo específico 'init!' está especificado.

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")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Student name is specified
Student name is left blank

Inicializadores requeridos

Para declarar todas y cada una de las subclases de la palabra clave initialize 'required' debe definirse antes de la función 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()

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

10
30
10