Swift - Panoramica ARC

Le funzioni di gestione della memoria e il suo utilizzo vengono gestiti nel linguaggio Swift 4 tramite il conteggio automatico dei riferimenti (ARC). ARC viene utilizzato per inizializzare e deinizializzare le risorse di sistema rilasciando così gli spazi di memoria utilizzati dalle istanze della classe quando le istanze non sono più necessarie. ARC tiene traccia delle informazioni sulle relazioni tra le nostre istanze di codice per gestire in modo efficace le risorse di memoria.

Funzioni di ARC

  • ARC alloca un pezzo di memoria per memorizzare le informazioni ogni volta che una nuova istanza di classe viene creata da init ().

  • Le informazioni sul tipo di istanza e sui relativi valori vengono archiviate in memoria.

  • Quando l'istanza della classe non è più necessaria, libera automaticamente lo spazio di memoria tramite deinit () per ulteriore archiviazione e recupero dell'istanza della classe.

  • ARC tiene traccia delle proprietà, delle costanti e delle variabili delle istanze di classe attualmente referenti in modo che deinit () venga applicato solo a quelle istanze inutilizzate.

  • ARC mantiene un "forte riferimento" a quelle proprietà, costanti e variabili dell'istanza di classe per limitare la deallocazione quando l'istanza di classe è attualmente in uso.

Programma ARC

class StudDetails {
   var stname: String!
   var mark: Int!
   
   init(stname: String, mark: Int) {
      self.stname = stname
      self.mark = mark
   }
   deinit {
      print("Deinitialized \(self.stname)")
      print("Deinitialized \(self.mark)")
   }
}

let stname = "Swift 4"
let mark = 98

print(stname)
print(mark)

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

Swift 4
98

Istanze di classe dei cicli di riferimento ARC Strong

class studmarks {
   let name: String
   var stud: student?
   
   init (name: String) {
      print("Initializing: \(name)")
      self.name = name
   }
   deinit {
      print("Deallocating: \(self.name)")
   }
}

class student {
   let name: String
   var strname: studmarks?
   
   init (name: String) {
      print("Initializing: \(name)")
      self.name = name
   }
   deinit {
      print("Deallocating: \(self.name)")
   }
}

var shiba: studmarks?
var mari: student?

shiba = studmarks(name: "Swift 4")
mari = student(name: "ARC")

shiba!.stud = mari
mari!.strname = shiba

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

Initializing: Swift 4
Initializing: ARC

Riferimenti ARC deboli e sconosciuti

Le proprietà del tipo di classe hanno due modi per risolvere i cicli di riferimento forti:

  • Riferimenti deboli
  • Riferimenti sconosciuti

Questi riferimenti vengono utilizzati per consentire a un'istanza di fare riferimento ad altre istanze in un ciclo di riferimento. Quindi le istanze possono fare riferimento a ciascuna di esse invece di preoccuparsi di un ciclo di riferimento forte. Quando l'utente sa che qualche istanza può restituire valori "nulli", possiamo indicarlo utilizzando un riferimento debole. Quando l'istanza restituirà qualcosa anziché zero, dichiararla con riferimento non proprietario.

Programma di riferimento debole

class module {
   let name: String
   init(name: String) { self.name = name }
   var sub: submodule?
   deinit { print("\(name) Is The Main Module") }
}

class submodule {
   let number: Int
   init(number: Int) { self.number = number }
   weak var topic: module?

   deinit { print("Sub Module with its topic number is \(number)") }
}

var toc: module?
var list: submodule?
toc = module(name: "ARC")
list = submodule(number: 4)
toc!.sub = list
list!.topic = toc

toc = nil
list = nil

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

ARC Is The Main Module
Sub Module with its topic number is 4

Programma di riferimento sconosciuto

class student {
   let name: String
   var section: marks?
   init(name: String) {
      self.name = name
   }
   deinit { print("\(name)") }
}

class marks {
   let marks: Int
   unowned let stname: student
   
   init(marks: Int, stname: student) {
      self.marks = marks
      self.stname = stname
   }
   deinit { print("Marks Obtained by the student is \(marks)") }
}

var module: student?
module = student(name: "ARC")
module!.section = marks(marks: 98, stname: module!)
module = nil

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

ARC
Marks Obtained by the student is 98

Forti cicli di riferimento per chiusure

Quando assegniamo una chiusura alla proprietà dell'istanza di classe e al corpo della chiusura per catturare un'istanza particolare, può verificarsi un forte ciclo di riferimento. Un forte riferimento alla chiusura è definito da 'self.someProperty' o 'self.someMethod ()'. I cicli di riferimento forti vengono utilizzati come tipi di riferimento per le chiusure.

class HTMLElement {
   let samplename: String
   let text: String?
   
   lazy var asHTML: () -> String = {
      if let text = self.text {
         return "<\(self.samplename)>\(text)</\(self.samplename)>"
      } else {
         return "<\(self.samplename) />"
      }
   }
   init(samplename: String, text: String? = nil) {
      self.samplename = samplename
      self.text = text
   }
   deinit {
      print("\(samplename) is being deinitialized")
   }
}

var paragraph: HTMLElement? = HTMLElement(samplename: "p", text: "Welcome to Closure SRC")
print(paragraph!.asHTML())

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

<p>Welcome to Closure SRC</p>

Riferimenti deboli e sconosciuti

Quando la chiusura e l'istanza si riferiscono l'una all'altra, l'utente può definire l'acquisizione in una chiusura come un riferimento non proprietario. Quindi non consentirebbe all'utente di deallocare l'istanza allo stesso tempo. Quando l'istanza a volte restituisce un valore 'nil', definire la chiusura con l'istanza debole.

class HTMLElement {
   let module: String
   let text: String?
   
   lazy var asHTML: () -> String = {
      [unowned self] in
      if let text = self.text {
         return "<\(self.module)>\(text)</\(self.module)>"
      } else {
         return "<\(self.module) />"
      }
   }
   init(module: String, text: String? = nil) {
      self.module = module
      self.text = text
   }
   deinit {
      print("\(module) the deinit()")
   }
}

var paragraph: HTMLElement? = HTMLElement(module: "Inside", text: "ARC Weak References")
print(paragraph!.asHTML())
paragraph = nil

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

<Inside>ARC Weak References</Inside>
Inside the deinit()