Swift ARC簡述


Swift 4語言中記憶體管理功能及用法通過自動參照計數(ARC)來處理。 ARC用於初始化和取消初始化系統資源,從而在不再需要範例時釋放類範例使用的記憶體空間。 ARC會跟蹤有關程式碼範例之間關係的資訊,以便有效地管理記憶體資源。

ARC的功能特性

  • ARC分配一塊記憶體來儲存每次由init()建立新類範例時的資訊。
  • 有關範例型別及其值的資訊儲存在記憶體中。
  • 當不再需要類範例時,它會通過deinit()自動釋放記憶體空間,以進行進一步的類範例儲存和檢索。
  • ARC跟蹤當前參照的類範例屬性,常數和變數,以便deinit()僅應用於那些未使用的範例。
  • ARC保持對那些類範例屬性,常數和變數的「強參照」,以在當前使用類範例時限制釋放。

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)

當使用playground 執行上述程式時,得到以下結果 -

Swift 4
98

ARC強參照回圈類範例

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

當使用playground 執行上述程式時,得到以下結果 -

Initializing: Swift 4
Initializing: ARC

ARC弱和無主參照

類型別屬性有兩種方法可以解決強參照週期 -

  • 弱參照
  • 無主參照

這些參照用於使一個範例能夠參照參考週期中的其他範例。 然後,範例可以參考每個範例而不是關注強參照迴圈。 當使用者知道某個範例可能返回nil值時,可指出使用弱參照。 當範例返回某些內容而不是nil時,則使用無主參照宣告它。

弱參照程式

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

當使用playground 執行上述程式時,得到以下結果 -

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

無主參照程式

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

當使用playground 執行上述程式時,得到以下結果 -

ARC
Marks Obtained by the student is 98

閉包的強參照週期

當要為類範例屬性和閉包的主體分配閉包以捕獲特定範例時,可能會發生強參照週期。 對閉包的強參照由self.somePropertyself.someMethod()定義。 強參照周期用作閉包的參照型別。

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

當使用playground 執行上述程式時,得到以下結果 -

<p>Welcome to Closure SRC</p>

弱和無主參照

當閉包和範例相互參照時,使用者可以將閉包中的捕獲定義為無主參照。 然後它不允許使用者同時解除分配範例。 當範例有時返回nil值時,用弱範例定義閉包。

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

當使用playground 執行上述程式時,得到以下結果 -

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