Swift - Inizializzazione

Classi, strutture ed enumerazioni una volta dichiarate in Swift 4 vengono inizializzate per preparare l'istanza di una classe. Il valore iniziale viene inizializzato per la proprietà memorizzata e anche per le nuove istanze i valori vengono inizializzati per procedere ulteriormente. La parola chiave per creare la funzione di inizializzazione viene eseguita dal metodo 'init ()'. L'inizializzatore di Swift 4 differisce da Objective-C per il fatto che non restituisce alcun valore. La sua funzione è controllare l'inizializzazione delle istanze appena create prima della sua elaborazione. Swift 4 fornisce anche un processo di "deinizializzazione" per eseguire operazioni di gestione della memoria una volta che le istanze sono state deallocate.

Ruolo inizializzatore per proprietà archiviate

La proprietà memorizzata deve inizializzare le istanze per le sue classi e strutture prima di elaborare le istanze. Le proprietà memorizzate utilizzano l'inizializzatore per assegnare e inizializzare i valori, eliminando così la necessità di chiamare osservatori di proprietà. L'inizializzatore viene utilizzato nella proprietà archiviata

  • Per creare un valore iniziale.

  • Per assegnare un valore di proprietà predefinito all'interno della definizione della proprietà.

  • Per inizializzare un'istanza per un particolare tipo di dati viene utilizzato 'init ()'. Nessun argomento viene passato all'interno della funzione init ().

Sintassi

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

Esempio

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 eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:

area of rectangle is 72.0

Qui la struttura "rettangolo" viene inizializzata con la lunghezza e la larghezza dei membri come tipi di dati "doppi". Il metodo Init () viene utilizzato per inizializzare i valori per i membri appena creati length e double. L'area del rettangolo viene calcolata e restituita chiamando la funzione rettangolo.

Impostazione dei valori delle proprietà per impostazione predefinita

Il linguaggio Swift 4 fornisce la funzione Init () per inizializzare i valori delle proprietà memorizzate. Inoltre, l'utente ha la possibilità di inizializzare i valori delle proprietà per impostazione predefinita mentre dichiara i membri della classe o della struttura. Quando la proprietà assume lo stesso valore da sola in tutto il programma, possiamo dichiararla solo nella sezione della dichiarazione invece di inizializzarla in init (). L'impostazione dei valori delle proprietà per impostazione predefinita abilita l'utente quando l'ereditarietà è definita per classi o strutture.

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

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

Quando eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:

area of rectangle is 72

Qui invece di dichiarare lunghezza e larghezza in init () i valori vengono inizializzati nella dichiarazione stessa.

Inizializzazione dei parametri

Nella lingua Swift 4 l'utente ha la possibilità di inizializzare i parametri come parte della definizione dell'inizializzatore utilizzando 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 eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:

area is: 72.0
area is: 432.0

Parametri locali ed esterni

I parametri di inizializzazione hanno nomi di parametri sia locali che globali simili a quelli dei parametri di funzione e metodo. La dichiarazione dei parametri locali viene utilizzata per accedere all'interno del corpo di inizializzazione e la dichiarazione dei parametri esterni viene utilizzata per chiamare l'inizializzatore. Gli inizializzatori di Swift 4 differiscono dall'inizializzatore di funzioni e metodi in quanto non identificano quale inizializzatore viene utilizzato per chiamare quali funzioni.

Per ovviare a questo, Swift 4 introduce un nome esterno automatico per ogni parametro in init (). Questo nome esterno automatico è equivalente al nome locale scritto prima di ogni parametro di inizializzazione.

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 eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:

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

Parametri senza nomi esterni

Quando non è necessario un nome esterno per l'inizializzazione, il trattino basso "_" viene utilizzato per sovrascrivere il comportamento predefinito.

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 eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:

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

Tipi di proprietà opzionali

Quando la proprietà memorizzata in qualche istanza non restituisce alcun valore, tale proprietà viene dichiarata con un tipo "opzionale" che indica che "nessun valore" viene restituito per quel particolare tipo. Quando la proprietà memorizzata viene dichiarata come 'opzionale', inizializza automaticamente il valore in modo che sia 'nullo' durante l'inizializzazione stessa.

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 eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:

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

Modifica delle proprietà delle costanti durante l'inizializzazione

L'inizializzazione consente inoltre all'utente di modificare anche il valore della proprietà costante. Durante l'inizializzazione, la proprietà della classe consente alle sue istanze di classe di essere modificate dalla super classe e non dalla sottoclasse. Si consideri ad esempio nel programma precedente "length" è dichiarato come "variabile" nella classe principale. La seguente variabile di programma "length" viene modificata come variabile "costante".

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 eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:

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

Inizializzatori predefiniti

Gli inizializzatori predefiniti forniscono una nuova istanza a tutte le sue proprietà dichiarate della classe base o della struttura con valori predefiniti.

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 eseguiamo il programma precedente usando playground, otteniamo il seguente risultato. -

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

Il programma precedente è definito con il nome della classe "defaultexample". Tre funzioni membro vengono inizializzate per impostazione predefinita come "studname?" per memorizzare i valori "nil", "stmark" come 98 e "pass" come valore booleano "true". Allo stesso modo, i valori dei membri nella classe possono essere inizializzati come predefiniti prima di elaborare i tipi di membri della classe.

Inizializzatori di membri per i tipi di struttura

Quando gli inizializzatori personalizzati non vengono forniti dall'utente, i tipi di struttura in Swift 4 riceveranno automaticamente l '"inizializzatore a livello di membro". La sua funzione principale è quella di inizializzare le nuove istanze della struttura con l'inizializzazione predefinita per il membro e quindi le nuove proprietà dell'istanza vengono passate per l'inizializzazione del membro per nome.

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 eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:

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

Le strutture vengono inizializzate per impostazione predefinita per le loro funzioni di appartenenza durante l'inizializzazione per "length" come "100.0" e "breadth" come "200.0". Ma i valori vengono sovrascritti durante l'elaborazione della lunghezza e della larghezza delle variabili come 24.0 e 32.0.

Delega dell'inizializzatore per i tipi di valore

La delega dell'inizializzatore è definita come la chiamata di inizializzatori da altri inizializzatori. La sua funzione principale è quella di agire come riutilizzabilità per evitare la duplicazione del codice su più inizializzatori.

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 eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:

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

Regole per la delega dell'inizializzatore

Tipi di valore Tipi di classe
L'ereditarietà non è supportata per tipi di valore come strutture ed enumerazioni. Il riferimento ad altri inizializzatori viene effettuato tramite self.init L'ereditarietà è supportata. Verifica che tutti i valori delle proprietà memorizzate siano inizializzati

Ereditarietà e inizializzazione delle classi

I tipi di classe hanno due tipi di inizializzatori per verificare se le proprietà memorizzate definite ricevono un valore iniziale, ovvero inizializzatori designati e inizializzatori di convenienza.

Inizializzatori designati e inizializzatori di convenienza

Inizializzatore designato Convenience Initializer
Considerato come inizializzazioni primarie per una classe Considerato come supporto dell'inizializzazione per una classe
Tutte le proprietà della classe vengono inizializzate e l'inizializzatore della superclasse appropriato viene chiamato per un'ulteriore inizializzazione L'inizializzatore designato viene chiamato con convenienza inizializzatore per creare un'istanza di classe per un caso d'uso specifico o un tipo di valore di input
Almeno un inizializzatore designato è definito per ogni classe Non è necessario avere inizializzatori di convenienza obbligatori definiti quando la classe non richiede inizializzatori.
Init (parametri) {istruzioni} convenienza init (parametri) {istruzioni}

Programma per inizializzatori designati

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 eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:

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

Programma per inizializzatori di convenienza

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 eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:

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

Ereditarietà e sostituzione dell'inizializzatore

Swift 4 non consente alle sue sottoclassi di ereditare i suoi inizializzatori di superclassi per i loro tipi di membri per impostazione predefinita. L'ereditarietà è applicabile agli inizializzatori di classi Super solo in una certa misura che verrà discussa in Ereditarietà degli inizializzatori automatici.

Quando l'utente deve avere inizializzatori definiti in superclasse, la sottoclasse con inizializzatori deve essere definita dall'utente come implementazione personalizzata. Quando la sottoclasse deve essere sostituita dalla parola chiave "override" della super classe, deve essere dichiarata.

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 eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:

Rectangle: 4 sides
Pentagon: 5 sides

Inizializzatori designati e convenienti in azione

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 eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:

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

Inizializzatore non riuscito

L'utente deve essere avvisato quando si verificano errori di inizializzazione durante la definizione di una classe, struttura o valori di enumerazione. L'inizializzazione delle variabili a volte diventa un errore a causa di -

  • Valori dei parametri non validi.
  • Assenza di fonte esterna richiesta.
  • Condizione che impedisce la riuscita dell'inizializzazione.

Per rilevare le eccezioni generate dal metodo di inizializzazione, Swift 4 produce un'inizializzazione flessibile chiamata "inizializzatore non riuscito" per notificare all'utente che qualcosa viene lasciato inosservato durante l'inizializzazione dei membri della struttura, della classe o dell'enumerazione. La parola chiave per rilevare l'inizializzatore non riuscito è "init?". Inoltre, gli inizializzatori failable e non failable non possono essere definiti con gli stessi tipi di parametri e nomi.

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 eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:

Student name is specified
Student name is left blank

Inizializzatori non riusciti per le enumerazioni

Il linguaggio Swift 4 offre la flessibilità di avere inizializzatori non riusciti anche per le enumerazioni per notificare all'utente quando i membri dell'enumerazione sono lasciati dall'inizializzazione dei valori.

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 eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:

With In Block Two
Block Does Not Exist

Inizializzatori non riusciti per le classi

Un inizializzatore non riuscito quando dichiarato con enumerazioni e strutture avvisa un errore di inizializzazione in qualsiasi circostanza all'interno della sua implementazione. Tuttavia, l'inizializzatore non riuscito nelle classi avviserà l'errore solo dopo che le proprietà memorizzate sono state impostate su un valore iniziale.

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 eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:

Module is Optional("Failable Initializers")

Sostituzione di un inizializzatore non riuscito

Come per l'inizializzazione, l'utente ha anche la possibilità di sovrascrivere un inizializzatore non riuscito di superclasse all'interno della sottoclasse. L'inizializzazione non riuscita della super classe può anche essere sovrascritta con un inizializzatore non fallibile della sottoclasse.

L'inizializzatore di sottoclasse non può delegare l'inizializzatore di superclasse quando sovrascrive un inizializzatore di superclasse non riuscito con un'inizializzazione di sottoclasse non fallibile.

Un inizializzatore non fallibile non può mai delegare a un inizializzatore non riuscito.

Il programma fornito di seguito descrive gli inizializzatori non guasti e non guasti.

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 eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:

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

L'init! Inizializzatore non riuscito

Swift 4 fornisce "init?" per definire un inizializzatore non riuscito dell'istanza facoltativa. Per definire un'istanza facoltativa implicitamente scartata del tipo specifico 'init!' è specificato.

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 eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:

Student name is specified
Student name is left blank

Inizializzatori richiesti

Per dichiarare ogni sottoclasse della parola chiave initialize 'required' deve essere definita prima della funzione 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 eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:

10
30
10