/*
ARC
- automatic reference counting, only for reference types
- Closure and Class etc are reference typesx
Tips:
ARC allocates memory to object instance and deallocates when not used.
if instance been deallocate and you access it, it will crash
Hence ARC counts how many active reference to that instane, it will not
deallocate when at least one active reference on it
String reference - assignt to property/var/constant etc
*/
class Person{
var name: String
init(name:String){
self.name=name
print("\(name) allocated")
}
deinit{
print("\(name) deallocated")
}
}
var ref1:Person?//by default nil
var ref2:Person?
var ref3:Person?
/*
similar to dead lock, strong reference cycle happens between 2 instance
hold each other
*/
class Tenant{
var name:String
var apartment:Apartment?
init(name:String){
self.name=name
}
deinit{
print("\(name) is deallocated")
}
}
class Apartment{
var roomid:Int
var tenant:Tenant?
init(roomid:Int){
self.roomid=roomid
}
deinit{
print("\(roomid) is deallocated")
}
}
var ppl1:Tenant? =Tenant(name: "zhangsan")// use ? to nil it later
var room1:Apartment? =Apartment(roomid: 1)
ppl1!.apartment =room1 // use ! to unwrap
room1!.tenant =ppl1
ppl1=nil ;room1=nil// notice that both instance didn't quote deinit{}
class Tenant2{
var name:String
weak var apartment:Apartment2?
init(name:String){
self.name=name
}
deinit{
print("\(name) is deallocated")
}
}
class Apartment2{
var roomid:Int
weak var tenant:Tenant2?
init(roomid:Int){
self.roomid=roomid
}
deinit{
print("\(roomid) is deallocated")
}
}
var ppl2:Tenant2?=Tenant2(name:"Lisi")
var appart2:Apartment2?=Apartment2(roomid:2)
ppl2?.apartment=appart2
appart2?.tenant=ppl2
ppl2=nil// print Lisi is deallocated
class Tenant3{
var name:String
unowned var apartment:Apartment3
init(name:String,apartment:Apartment3){
self.name=name
self.apartment=apartment
}
deinit{
print("\(name) is deallocated, because of no room")
}
}
class Apartment3{
var roomid:Int
var tenant:Tenant3?
init(roomid:Int){
self.roomid=roomid
}
deinit{
print("room\(roomid) is deallocated")
}
}
var apart3:Apartment3?=Apartment3(roomid:3)
//Question here
//Approach A will not call deinit of Tenant3
var ternant3:Tenant3?=Tenant3(name:"wangwu", apartment: apart3!)
apart3?.tenant=ternant3
//Approach B will call deinit of Tenant3
// apart3?.tenant=Tenant3(name: "wangwu", apartment: apart3!)
ternant3=nil
apart3=nil
// Question here, when you use upper case C below, make country -> Country
// unexpected error
class City{
var name:String
var country:Country! // when you use var Country:Country! it will error
init(name:String,countryName:String){
self.name=name
self.country=Country(name:countryName,city:self)
}
}
class Country{
var name:String
unowned var Capital:City
init(name:String,city:City){
self.name=name
self.Capital=city
}
}
var city = City(name:"hangzhou",countryName:"zhongguo")
// Strong reference cycle with Closure
class A{
var name:String?
var age:Int
lazy var speak:()->String = {
if let name = self.name{
return "\(self.name) got a name"
}else{
return "ain't got no name, but he got \(self.age)"
}
}
init(name:String?,age:Int){
self.name=name
self.age=age
}
deinit{
print("A class now been terminated and deallocated")
}
}
var a:A? = A(name: nil, age: 3)
//a=nil // this can run successfully
a?.speak()
//a=nil // until now, a string reference cycle been created, you cant release
/*
Define a capture in a closure as an unowned reference when the closure and the instance it captures will always refer to each other, and will always be deallocated at the same time.
Conversely, define a capture as a weak reference when the captured reference may become nil at some point in the future. Weak references are always of an optional type, and automatically become nil when the instance they reference is deallocated.
*/
class B{
var name:String?
var age:Int
lazy var speak:()->String = {
[unowned self] in
if let name = self.name{
return "\(self.name) got a name"
}else{
return "ain't got no name, but he got \(self.age)"
}
}
init(name:String?,age:Int){
self.name=name
self.age=age
}
deinit{
print("A class now been terminated and deallocated")
}
}
var b:B? = B(name: nil, age: 3)
b?.speak()
b=nil