Swift - Inicialização

Classes, estruturas e enumerações, uma vez declaradas no Swift 4, são inicializadas para preparar a instância de uma classe. O valor inicial é inicializado para a propriedade armazenada e também para novas instâncias, os valores são inicializados para prosseguir. A palavra-chave para criar a função de inicialização é executada pelo método 'init ()'. O inicializador do Swift 4 difere do Objective-C porque não retorna nenhum valor. Sua função é verificar a inicialização de instâncias recém-criadas antes de seu processamento. O Swift 4 também fornece processo de 'desinicialização' para realizar operações de gerenciamento de memória, uma vez que as instâncias são desalocadas.

Função de inicializador para propriedades armazenadas

A propriedade armazenada deve inicializar as instâncias para suas classes e estruturas antes de processar as instâncias. As propriedades armazenadas usam o inicializador para atribuir e inicializar valores, eliminando assim a necessidade de chamar observadores de propriedade. O inicializador é usado na propriedade armazenada

  • Para criar um valor inicial.

  • Para atribuir o valor da propriedade padrão na definição da propriedade.

  • Para inicializar uma instância para um determinado tipo de dados, 'init ()' é usado. Nenhum argumento é passado dentro da função init ().

Sintaxe

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

Exemplo

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

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

area of rectangle is 72.0

Aqui, a estrutura 'retângulo' é inicializada com comprimento e largura dos membros como tipos de dados 'Double'. O método Init () é usado para inicializar os valores para os membros recém-criados length e double. A área do retângulo é calculada e retornada chamando a função retângulo.

Definindo valores de propriedade por padrão

A linguagem Swift 4 fornece a função Init () para inicializar os valores de propriedade armazenados. Além disso, o usuário pode inicializar os valores da propriedade por padrão ao declarar os membros da classe ou da estrutura. Quando a propriedade assume o mesmo valor sozinho em todo o programa, podemos declará-lo apenas na seção de declaração em vez de inicializá-lo em init (). Definir valores de propriedade por padrão habilita o usuário quando a herança é definida para classes ou estruturas.

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

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

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

area of rectangle is 72

Aqui, em vez de declarar comprimento e largura em init (), os valores são inicializados na própria declaração.

Inicialização de Parâmetros

Na linguagem Swift 4, o usuário tem a capacidade de inicializar parâmetros como parte da definição do 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)")

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

area is: 72.0
area is: 432.0

Parâmetros locais e externos

Os parâmetros de inicialização têm nomes de parâmetros locais e globais semelhantes aos dos parâmetros de função e método. A declaração de parâmetro local é usada para acessar dentro do corpo de inicialização e a declaração de parâmetro externo é usada para chamar o inicializador. Os inicializadores do Swift 4 diferem do inicializador de função e método porque não identificam qual inicializador é usado para chamar quais funções.

Para superar isso, o Swift 4 introduz um nome externo automático para cada um dos parâmetros em init (). Este nome externo automático é equivalente ao nome local escrito antes de cada parâmetro de inicialização.

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

Quando executamos o programa acima usando playground, obtemos o seguinte 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 sem nomes externos

Quando um nome externo não é necessário para um sublinhado de inicialização, '_' é usado para substituir o comportamento padrão.

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

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

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

Tipos de propriedade opcionais

Quando a propriedade armazenada em alguma instância não retorna nenhum valor, essa propriedade é declarada com um tipo 'opcional' indicando que 'nenhum valor' é retornado para aquele tipo específico. Quando a propriedade armazenada é declarada como 'opcional', ela inicializa automaticamente o valor como 'nulo' durante a própria inicialização.

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

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

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

Modificando propriedades constantes durante a inicialização

A inicialização também permite que o usuário modifique o valor da propriedade constante. Durante a inicialização, a propriedade da classe permite que suas instâncias de classe sejam modificadas pela superclasse e não pela subclasse. Considere, por exemplo, no programa anterior, 'comprimento' é declarado como 'variável' na classe principal. A variável de programa abaixo 'comprimento' é modificada como variável '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)")

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

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

Inicializadores padrão

Os inicializadores padrão fornecem uma nova instância para todas as suas propriedades declaradas da classe base ou estrutura com valores padrão.

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

Quando executamos o programa acima usando playground, obtemos o seguinte resultado. -

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

O programa acima é definido com o nome da classe como 'exemplo padrão'. Três funções-membro são inicializadas por padrão como 'studname?' para armazenar valores 'nulos', 'stmark' como 98 e 'passar' como valor booleano 'verdadeiro'. Da mesma forma, os valores dos membros da classe podem ser inicializados como padrão antes de processar os tipos de membros da classe.

Inicializadores de membro para tipos de estrutura

Quando os inicializadores personalizados não são fornecidos pelo usuário, os tipos de estrutura no Swift 4 receberão automaticamente o 'inicializador de membro'. Sua função principal é inicializar as novas instâncias da estrutura com a inicialização padrão por membro e, em seguida, as propriedades da nova instância são passadas para a inicialização por nome de membro.

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

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

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

As estruturas são inicializadas por padrão para suas funções de associação durante a inicialização para 'comprimento' como '100,0' e 'largura' como '200,0'. Mas os valores são substituídos durante o processamento das variáveis ​​de comprimento e largura como 24.0 e 32.0.

Delegação de inicializador para tipos de valor

Delegação de inicializador é definida como inicializadores de chamada de outros inicializadores. Sua principal função é atuar como capacidade de reutilização para evitar a duplicação de código em vários 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)")

Quando executamos o programa acima usando playground, obtemos o seguinte 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)

Regras para delegação de inicializador

Tipos de valor Tipos de classe
A herança não é compatível com tipos de valor, como estruturas e enumerações. A referência a outros inicializadores é feita por meio de self.init A herança é compatível. Verifica se todos os valores de propriedade armazenados foram inicializados

Herança e inicialização de classe

Os tipos de classe têm dois tipos de inicializadores para verificar se as propriedades armazenadas definidas recebem um valor inicial, a saber, inicializadores designados e inicializadores de conveniência.

Inicializadores designados e inicializadores de conveniência

Inicializador Designado Inicializador de conveniência
Considerado como inicializa primária para uma classe Considerado como suporte para inicialização de uma classe
Todas as propriedades da classe são inicializadas e o inicializador de superclasse apropriado é chamado para inicialização posterior O inicializador designado é chamado com o inicializador de conveniência para criar uma instância de classe para um caso de uso específico ou tipo de valor de entrada
Pelo menos um inicializador designado é definido para cada classe Não há necessidade de ter inicializadores de conveniência obrigatoriamente definidos quando a classe não requer inicializadores.
Init (parâmetros) {instruções} conveniência init (parâmetros) {instruções}

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

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

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

Programa para inicializadores de conveniência

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

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

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

Herança e substituição do inicializador

O Swift 4 não permite que suas subclasses herdem seus inicializadores de superclasse para seus tipos de membro por padrão. A herança é aplicável aos inicializadores de superclasse apenas até certo ponto, o que será discutido em Herança do inicializador automático.

Quando o usuário precisa ter inicializadores definidos em superclasse, a subclasse com inicializadores deve ser definida pelo usuário como implementação customizada. Quando a substituição deve ser realizada pela subclasse, a palavra-chave da superclasse 'substituição' deve ser declarada.

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

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

Rectangle: 4 sides
Pentagon: 5 sides

Inicializadores designados e de conveniência em ação

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

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

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

Inicializador disponível

O usuário deve ser notificado quando houver alguma falha no inicializador ao definir uma classe, estrutura ou valores de enumeração. A inicialização de variáveis ​​às vezes se torna uma falha devido a -

  • Valores de parâmetro inválidos.
  • Ausência de fonte externa necessária.
  • Condição que impede o sucesso da inicialização.

Para capturar exceções lançadas pelo método de inicialização, o Swift 4 produz uma inicialização flexível chamada 'inicializador failable' para notificar o usuário de que algo foi deixado despercebido durante a inicialização da estrutura, classe ou membros de enumeração. A palavra-chave para capturar o inicializador failable é 'init?'. Além disso, inicializadores failable e não failable não podem ser definidos com os mesmos tipos e nomes de parâmetro.

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

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

Student name is specified
Student name is left blank

Inicializadores disponíveis para enumerações

A linguagem Swift 4 fornece a flexibilidade de ter inicializadores Failable para enumerações também para notificar o usuário quando os membros da enumeração deixam de inicializar os 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")
}

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

With In Block Two
Block Does Not Exist

Inicializadores disponíveis para classes

Um inicializador failable quando declarado com enumerações e estruturas alerta uma falha de inicialização em qualquer circunstância dentro de sua implementação. No entanto, o inicializador failable nas classes alertará a falha somente depois que as propriedades armazenadas forem definidas com um 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)")
}

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

Module is Optional("Failable Initializers")

Substituindo um inicializador disponivel

Assim como o de inicializar, o usuário também tem a capacidade de substituir um inicializador failable da superclasse dentro da subclasse. A inicialização failable da superclasse também pode ser substituída por um inicializador não fiável da subclasse.

O inicializador de subclasse não pode delegar ao inicializador de superclasse ao substituir um inicializador de superclasse failable por uma inicialização de subclasse não failable.

Um inicializador não failable nunca pode delegar a um inicializador failable.

O programa fornecido a seguir descreve os inicializadores failable e não failable.

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

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

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

O init! Inicializador disponível

Swift 4 fornece 'init?' para definir um inicializador failable de instância opcional. Para definir uma instância opcional implicitamente desembrulhada do tipo específico 'init!' é 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")
}

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

Student name is specified
Student name is left blank

Inicializadores necessários

Para declarar toda e qualquer subclasse da palavra-chave initialize 'required' precisa ser definida antes da função 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()

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

10
30
10