/**
在少數情況下,ARC爲了能幫助你管理內存,需要更多的關於你的代碼之間關係的信息
引用計數僅僅應用於類的實例,結構體和枚舉類型是值類型,不是引用類型,也不是通過引用的方式存儲和傳遞
爲了使之成爲可能,無論你將實例賦值給屬性,常量或者是變量,屬性,常量或者變量,都會對此實例創建強引用。之所以稱之爲強引用,是因爲它會將實例牢牢的保持住,只要強引用還在,實例是不允許被銷燬的
*/
class Person {
let name: String;
init(name: String) {
self.name = name;
// print("\(name) is being initialized");
}
deinit {
// print("\(name) is being deinitialized");
}
}
var person1: Person?;
var person2: Person?
var person3: Person?
person1 = Person(name: "Jack");
person2 = person1;
person3 = person1;
//ARC會在第三個,也即最後一個強引用被斷開的時候,銷燬person實例,這也意味着不再使用這個person實例
person1 = nil;
person2 = nil;
person3 = nil;
//類實例之間的循環強引用
/**
一個類永遠不會有0個強引用,這種情況發生在兩個類實例互相保持對方的強引用,並讓對方不被銷燬,這就是所謂的循環強引用
可以通過定義類之間的關係爲弱引用或者無主引用,以此替代強引用,從而解決循環強引用的問題。
*/
class People {
let name: String;
init(name: String) {
self.name = name;
}
var apartment: Apartment?;
deinit {
// print("\(name) is being deinitialized");
}
}
class Apartment {
let number: Int;
init(number: Int) {
self.number = number;
}
var tenant: People?;
deinit{
// print("Apartment #\(number) is being deinitialized");
}
}
var john: People?;
var number73: Apartment?
john = People(name: "John");
number73 = Apartment(number: 73);
john!.apartment = number73;
number73!.tenant = john;
//無任何析構函數被調用,造成內存泄露
john = nil;
number73 = nil;
//解決實例之間的循環強引用
/**
swift提供了兩種辦法來解決在使用類的屬性時所遇到的循環強引用問題:弱引用和無主引用
弱引用和無主引用允許循環應用中的一個實例引用另一個實例而不保持強引用,這樣實例能夠互相引用而不產生循環引用
對於生命週期中會變爲nil的實例使用弱引用,相反,對於初始化賦值後再也不會被賦值爲nil的實例,使用無主引用
*/
//弱引用
/**
在聲明屬性或者變量時,在前面加上weak關鍵字表明這是一個弱引用.
弱引用必須被聲明爲變量,表明其值能在運行時被修改。弱引用不能被聲明爲常量
*/
class People2 {
let name: String;
init(name: String) {
self.name = name;
}
var apartment: Apartment2?;
deinit {
print("\(name) is being deinitialized");
}
}
class Apartment2 {
let number: Int;
init(number: Int) {
self.number = number;
}
weak var tenant: People2?;
deinit{
print("Apartment #\(number) is being deinitialized");
}
}
var john2: People2?;
var number732: Apartment2?
john2 = People2(name: "John2");
number732 = Apartment2(number: 73);
john2!.apartment = number732;
number732!.tenant = john2;
john2 = nil;
number732 = nil;
//無主引用
/**
和弱引用類似,無主引用不會牢牢保持住引用的實例。和弱引用不同的是,無主引用是永遠有值的。因此,無主引用總是被定義爲非可選類型。可以在聲明屬性或者變量時,在前面加上關鍵字unowned表示這是一個無主引用
如果試圖在實例被銷燬後,訪問該實例的無主引用,會觸發運行時錯誤,使用無主引用,你必須確保引用始終指向一個未銷燬的實例
還需要注意的是如果你試圖訪問實例已經被銷燬的無主引用,程序會直接崩潰,而不會發生無法預期的行爲
*/
class Customer {
let name: String;
var card: CreditCard?
init(name: String) {
self.name = name;
}
deinit {
print("\(name) is deing deinitialized");
}
}
class CreditCard {
let number: Int;
unowned let customer: Customer;
init(number: Int, customer: Customer) {
self.number = number;
self.customer = customer;
}
deinit {
print("Card \(number) is being deinitialized");
}
}
var nick: Customer?;
nick = Customer(name: "Nick");
nick!.card = CreditCard(number: 1234567890, customer: nick!);
nick = nil;
//無主引用以及顯式展開的可選屬性
/**
*/
class Country {
let name: String;
var capitalCity: City!;
init(name: String, capitalName: String) {
self.name = name;
self.capitalCity = City(name: capitalName, country: self);
}
deinit {
print("\(name) is being deinitialized");
}
}
class City {
let name: String;
unowned let country: Country;
init(name: String, country: Country) {
self.name = name;
self.country = country;
}
deinit {
print("\(name) is being deinitialized");
}
}
var country = Country(name: "Canada", capitalName: "Ottawa");
print("\(country.name)'s capital city is called \(country.capitalCity.name)");
//閉包引起的循環強引用
/**
類似block循環強引用
swift提供了一種優雅的方法來解決這個問題,稱之爲閉包占用列表
asHTML聲明爲lazy屬性,因爲只有當元素確實需要處理爲hy=tml輸出的字符串時,才需要使用asHTML,也就是說,在默認的閉包中可以使用self,因爲只有當初始化完成以及self確實存在後,才能訪問lazy屬性
*/
class HTMLElement {
let name: String?;
let text: String?;
lazy var asHTML: () -> String = {
[unowned self] in
if let text = self.text {
return "<\(self.name!)>\(text)</\(self.name!)>";
}else{
return "<\(self.name!)/>"
}
}
init(name: String, text: String? = nil) {
self.name = name;
self.text = text;
}
deinit {
print("\(name!) is being deinitialized");
}
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world");
//paragraph變量定義爲可選HTMLElement,因此我們可以賦值nil給它來演示循環強引用
print(paragraph!.asHTML());
paragraph = nil;
//解決閉包引起的循環強引用
/**
在定義閉包時同時定義佔有列表作爲閉包的一部分,通過這種方式可以解決閉包和類實例之間的循環強引用。佔有列表定義了閉包體內佔有一個或者多個引用類型的規則。跟解決兩個類實例間的循環強引用一樣,聲明每個佔有的引用爲弱引用或無主引用,而不是強引用,應當根據代碼關係來決定使用弱引用還是無主引用
佔有列表放置在閉包參數列表和返回類型之前:
lazy var someClosure: (Int, String) -> String = {
[unowned self] (index: Int, stringToProcess:
String) -> String in
// closure body goes here
}
如果閉包沒有指定參數列表或者返回類型,則可以通過上下文推斷,那麼可以佔有列表放在閉包開始的地方,跟着是關鍵字in:
lazy var someClosure: () -> String = {
[unowned self] in
// closure body goes here
}
*/