Swift - Visão geral do ARC

As funções de gerenciamento de memória e seu uso são tratados na linguagem Swift 4 por meio de contagem automática de referência (ARC). O ARC é usado para inicializar e desinicializar os recursos do sistema, liberando assim os espaços de memória usados ​​pelas instâncias da classe quando as instâncias não são mais necessárias. O ARC mantém o controle das informações sobre os relacionamentos entre nossas instâncias de código para gerenciar os recursos de memória de maneira eficaz.

Funções do ARC

  • O ARC aloca um pedaço de memória para armazenar as informações toda vez que uma nova instância de classe é criada por init ().

  • Informações sobre o tipo de instância e seus valores são armazenados na memória.

  • Quando a instância de classe não é mais necessária, ela libera automaticamente o espaço de memória por deinit () para armazenamento e recuperação de instância de classe adicional.

  • O ARC mantém o controle das propriedades, constantes e variáveis ​​das instâncias de classe de referência, de forma que deinit () seja aplicado apenas às instâncias não utilizadas.

  • O ARC mantém uma 'referência forte' a essas propriedades, constantes e variáveis ​​de instância de classe para restringir a desalocação quando a instância de classe está em uso.

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

Swift 4
98

Instâncias de classe ARC Strong Reference Cycles

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

Initializing: Swift 4
Initializing: ARC

Referências ARC fracas e sem proprietário

As propriedades do tipo de classe têm duas maneiras de resolver os ciclos de referência fortes -

  • Referências fracas
  • Referências não proprietárias

Essas referências são usadas para permitir que uma instância se refira a outras instâncias em um ciclo de referência. Então, as instâncias podem se referir a cada uma das instâncias, em vez de se preocupar com o ciclo de referência forte. Quando o usuário sabe que alguma instância pode retornar valores 'nulos', podemos apontar isso usando uma referência fraca. Quando a instância vai retornar algo em vez de nil, declare-o com uma referência sem proprietário.

Programa de Referência Fraca

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

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

Programa de referência sem proprietário

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

ARC
Marks Obtained by the student is 98

Ciclos de referência fortes para fechamentos

Quando atribuímos um encerramento à propriedade da instância da classe e ao corpo do encerramento para capturar uma instância particular, o ciclo de referência forte pode ocorrer. Uma referência forte ao encerramento é definida por 'self.someProperty' ou 'self.someMethod ()'. Ciclos de referência fortes são usados ​​como tipos de referência para os fechamentos.

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

<p>Welcome to Closure SRC</p>

Referências fracas e sem proprietário

Quando o fechamento e a instância se referem um ao outro, o usuário pode definir a captura em um fechamento como uma referência sem proprietário. Então, não permitiria que o usuário desalocasse a instância ao mesmo tempo. Quando a instância em algum momento retornar um valor 'nulo', defina o fechamento com a instância fraca.

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

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