/**
在少数情况下,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
}
*/