Swift - przegląd ARC

Funkcje zarządzania pamięcią i jej użycie są obsługiwane w języku Swift 4 poprzez automatyczne liczenie referencji (ARC). ARC służy do inicjowania i deinicjalizacji zasobów systemowych, zwalniając tym samym przestrzenie pamięci używane przez instancje klas, gdy instancje nie są już potrzebne. ARC śledzi informacje o relacjach między naszymi instancjami kodu, aby efektywnie zarządzać zasobami pamięci.

Funkcje ARC

  • ARC przydziela porcję pamięci do przechowywania informacji za każdym razem, gdy nowa instancja klasy jest tworzona przez init ().

  • Informacje o typie instancji i jej wartościach są przechowywane w pamięci.

  • Gdy instancja klasy nie jest już potrzebna, automatycznie zwalnia przestrzeń pamięci przez deinit () w celu dalszego przechowywania i pobierania instancji klasy.

  • ARC śledzi aktualnie odwołujące się właściwości instancji klas, stałe i zmienne, dzięki czemu funkcja deinit () jest stosowana tylko do tych nieużywanych instancji.

  • ARC utrzymuje „silne odniesienie” do tych właściwości instancji klasy, stałych i zmiennych, aby ograniczyć cofanie alokacji, gdy instancja klasy jest aktualnie używana.

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

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

Swift 4
98

ARC Strong Reference Cycles Class Instances

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

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

Initializing: Swift 4
Initializing: ARC

Słabe i nieznane referencje ARC

Właściwości typu klasy mają dwa sposoby rozwiązywania silnych cykli odwołań -

  • Słabe odniesienia
  • Nieznane referencje

Te odwołania są używane, aby umożliwić jednej instancji odwoływanie się do innych instancji w cyklu referencyjnym. Wtedy instancje mogą odnosić się do każdego wystąpienia, zamiast dbać o silny cykl odniesienia. Gdy użytkownik wie, że jakaś instancja może zwrócić wartości „nil”, możemy wskazać na to, używając słabego odwołania. Kiedy instancja zwróci coś, a nie zero, zadeklaruj to z odwołaniem, którego nie jesteś właścicielem.

Słaby program referencyjny

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

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

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

Nieznany program referencyjny

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

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

ARC
Marks Obtained by the student is 98

Silne cykle referencyjne dla zamknięć

Kiedy przypiszemy zamknięcie do właściwości instancji klasy i do treści zamknięcia w celu przechwycenia określonej instancji, może wystąpić silny cykl odniesienia. Silne odniesienie do zamknięcia jest definiowane przez „self.someProperty” lub „self.someMethod ()”. Silne cykle referencyjne są używane jako typy referencyjne dla zamknięć.

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

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

<p>Welcome to Closure SRC</p>

Słabe i nieznane referencje

Gdy zamknięcie i wystąpienie odnoszą się do siebie nawzajem, użytkownik może zdefiniować wychwycenie w zamknięciu jako odniesienie nieposiadane. Wtedy nie pozwoliłoby użytkownikowi na jednoczesne zwolnienie instancji. Kiedy instancja kiedyś zwróci wartość „zero”, zdefiniuj zamknięcie słabą instancją.

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

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

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