Swift vs. C# : Automatic Reference Counting


[ref](https://developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-XID_88)


- ARC = Automatic Reference Counting
- ランタムでは無くコンパイラがGabage Collectするコードを作成する
- 同期的にオブジェクトが解放されるようです
- ARCは "Retain Cycles"に関して自動的に面倒みてくれないので、コンパイラに適切にGCコードいれるようなヒントを与える必要があるようです。

# How ARC Works

- 問題になるのはまだ使用中のインスタンスがARCでdeallocate されようとしたとき

## １個インスタンスを作る
~~~
  1> class Point{  
  2.     var X: Int=0  
  3.     deinit{ println("deallocated") }  
  4.     func moveby(x: Int){  
  5.         X += x  
  6.     }         
  7. }
~~~

~~~
  8> var p : Point? = Point()
p: Point? = (X = 0)
~~~  

- deinit されている
 
~~~
  9> p!.moveby(5) 
 10> p = nil
deallocated
~~~

~~~
 11> p!.moveby(10)
fatal error: unexpectedly found nil while unwrapping an Optional value
Execution interrupted. Enter Swift code to recover and continue.
Enter LLDB commands to investigate (type :help for assistance.)
~~~


## 参照をつくってみる

~~~
Welcome to Swift!  Type :help for assistance.
  1> class Point{  
  2.     var X: Int=0  
  3.     deinit{ println("deallocated") }  
  4.     func moveby(x: Int){  
  5.         X += x  
  6.     }         
  7. }
  8> var p1 : Point? = Point()
p1: Point? = (X = 0)
  9> var p2 : Point? = p1
p2: Point? = (X = 0)
 10> p2 = nil
 11> p1 = nil
deallocated
~~~

~~~
Welcome to Swift!  Type :help for assistance.
  1> class Point{  
  2.     var X: Int=0  
  3.     deinit{ println("deallocated") }  
  4.     func moveby(x: Int){  
  5.         X += x  
  6.     }         
  7. }
  8> var p1 : Point? = Point()
p1: Point? = (X = 0)
  9> var p2 : Point? = p1
p2: Point? = (X = 0)
 10> p1 = nil
 11> p2 = nil
deallocated
~~~

# ARC in Action

~~~
Welcome to Swift!  Type :help for assistance.
  1> class Person { 
  2.     let name: String 
  3.     init(name: String) { 
  4.         self.name = name 
  5.         println("\(name) is being initialized") 
  6.     } 
  7.     deinit { 
  8.         println("\(name) is being deinitialized") 
  9.     } 
 10. }
 11> var reference1: Person? 
 12. var reference2: Person? 
 13. var reference3: Person?
reference1: Person? = nil
reference2: Person? = nil
reference3: Person? = nil
 14> reference1 = Person(name: "John Appleseed")
John Appleseed is being initialized
 15>  
 16> reference2 = reference1
 17> reference3 = reference1
 18> reference1 = nil
 19> reference2 = nil
 20> reference3 = nil
John Appleseed is being deinitialized
~~~

# Strong Reference Cycles Between Class Instances

> However, it is possible to write code in which an instance of a class never gets to a point where it has zero strong references. 

> This can happen if two class instances hold a strong reference to each other, such that each instance keeps the other alive. 


> This is known as a strong reference cycle.

- PersonとApartmentはお互いの参照を持つように設計してみる

~~~
  1> class Person { 
  2.     let name: String 
  3.     init(name: String) { self.name = name } 
  4.     var apartment: Apartment? 
  5.     deinit { println("\(name) is being deinitialized") } 
  6. } 

  8. class Apartment { 
  9.     let number: Int 
 10.     init(number: Int) { self.number = number } 
 11.     var tenant: Person? 
 12.     deinit { println("Apartment #\(number) is being deinitialized") } 
 13. }
~~~ 
 
~~~ 
 14> var john: Person? 
 15. var number73: Apartment?
john: Person? = nil
number73: Apartment? = nil
~~~

~~~
 16> john = Person(name: "John Appleseed")
 17> number73 = Apartment(number: 73)
~~~

- 相互に参照
~~~ 
 18> john!.apartment = number73
 19> number73!.tenant = john
~~~
 
~~~ 
 20> john = nil
 21> number73 = nil
 
 22> john
$R0: Person? = nil
 23> number73
$R1: Apartment? = nil
~~~

メモリが足りなくなるかもってよ:

> Note that neither deinitializer was called when you set these two variables to nil. 

> The strong reference cycle prevents the Person and Apartment instances from ever being deallocated, causing a memory leak in your app.

- 相互参照からnil化していけば消える

~~~
 21> john!.apartment = nil
 22> number73!.tenant = nil
 23> john = nil
John Appleseed is being deinitialized
 24> number73 = nil
Apartment #73 is being deinitialized
~~~

# Resolving Strong Reference Cycles Between Class Instances

- Strong Reference Cycles の問題の解決

    1. Weak Reference
    2. Unowned Reference


## Weak References

- Apartment の tenant(Person)をweak で宣言

~~~
  1> class Person { 
  2.     let name: String 
  3.     init(name: String) { self.name = name } 
  4.     var apartment: Apartment? 
  5.     deinit { println("\(name) is being deinitialized") } 
  6. } 
  7.   
  8. class Apartment { 
  9.     let number: Int 
 10.     init(number: Int) { self.number = number } 
 11.     weak var tenant: Person? 
 12.     deinit { println("Apartment #\(number) is being deinitialized") } 
 13. }
~~~

~~~
 14> var john: Person? = Person(name: "John Appleseed")
john: Person? = Some {
  name = "John Appleseed"
  apartment = nil
}
 15> var number73: Apartment? = Apartment(number: 73)
number73: Apartment? = Some {
  number = 73
  tenant = nil
}
 16> john!.apartment = number73
 17> number73!.tenant = john   
~~~

- deinit呼ばれる

~~~
 18> john = nil
John Appleseed is being deinitialized
 19> number73 = nil
Apartment #73 is being deinitialized
~~~ 

- 逆にApartmentからnilすると、最後に両方deinitされる

~~~
 14> var john: Person? = Person(name: "John Appleseed") 
 15. var number73: Apartment? = Apartment(number: 73) 
 16.  
 17. john!.apartment = number73 
 18. number73!.tenant = john   
john: Person? = Some {
  name = "John Appleseed"
  apartment = Some {
    number = 73
    tenant = Some: {
      name = ""
      apartment = Some {
        number = <read memory from 0x13 failed (0 of 8 bytes read)>
        tenant = <read memory from 0x1b failed (0 of 8 bytes read)>

      }
    }
  }
}
number73: Apartment? = Some {
  number = 73
  tenant = Some: {
    name = ""
    apartment = Some {
      number = <read memory from 0x13 failed (0 of 8 bytes read)>
      tenant = <read memory from 0x1b failed (0 of 8 bytes read)>

    }
  }
}
 19> number73 = nil
 20> john = nil
John Appleseed is being deinitialized
Apartment #73 is being deinitialized
~~~


## Unowned References

~~~
  1> class Customer { 
  2.     let name: String 
  3.     var card: CreditCard? 
  4.     init(name: String) { 
  5.         self.name = name 
  6.     } 
  7.     deinit { println("\(name) is being deinitialized") } 
  8. } 
  9.   
 10. class CreditCard { 
 11.     let number: UInt64 
 12.     unowned let customer: Customer 
 13.     init(number: UInt64, customer: Customer) { 
 14.         self.number = number 
 15.         self.customer = customer 
 16.     } 
 17.     deinit { println("Card #\(number) is being deinitialized") } 
 18. }
 19> var john: Customer? = Customer(name: "John Appleseed")
john: Customer? = Some {
  name = "John Appleseed"
  card = nil
}
 20> john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
~~~ 

- johnをnilにすると、CreditCardの customerが unownedなので、johnのcardもdeinitされる

~~~ 
 22> john = nil
John Appleseed is being deinitialized
Card #1234567890123456 is being deinitialized
~~~

ちなみに、johnにcardを設定した段階で、johnを参照するとREPLが死にます。

~~~
Bus error: 10
~~~

## Unowned References and Implicitly Unwrapped Optional Properties

1) Weak, 2) Unowned,

> However, there is a third scenario, 

> in which both properties should always have a value, 

> and neither property should ever be nil once initialization is complete. 

3) unowned + implicity unwrapped optional

> In this scenario, it is useful to combine an unowned property on one class with an implicitly unwrapped optional property on the other class.

~~~
class Country {
    let name: String
    let capitalCity: City!                      //Implicitly Optionally Unwrapped
    init(name: String, capitalName: String) {
        self.name = name
        self.capitalCity = City(name: capitalName, country: self)
        println("Country init:\(name) \(capitalName)")
    }
    deinit{ println("Goodby Country") }
}
 
class City {
    let name: String
    unowned let country: Country                // Unowned
    init(name: String, country: Country) {
        self.name = name
        self.country = country
        println("City init:\(name) \(country.name)")
    }
    deinit{ println("Goodby City") }
}

var country :Country! = Country(name: "Canada", capitalName: "Ottawa")
println("\(country.capitalCity!.name)")
country = nil
~~~
~~~
City init:Ottawa Canada
Country init:Canada Ottawa
Ottawa
Goodby Country
Goodby City
~~~

もしもオプショナルじゃないと

~~~

let capitalCity: City    //Not Optional

~~~
~~~
./swift6.swift:8:28: error: variable 'self.capitalCity' used before being initialized
        self.capitalCity = City(name: capitalName, country: self)
~~~

なので、すくなくもオプショナルじゃないと。


# Strong Reference Cycles for Closures

- Strong Reference Cycles はクロージャでも起きる
- なぜならクロージャも参照型なので

> A strong reference cycle can also occur if you assign a closure to a property of a class instance, and the body of that closure captures the instance. 


~~~
 1> class HTMLElement { 
  2.      
  3.     let name: String 
  4.     let text: String? 
  5.      
  6.     lazy var asHTML: () -> String = { 
  7.         if let text = self.text { 
  8.             return "<\(self.name)>\(text)</\(self.name)>" 
  9.         } else { 
 10.             return "<\(self.name) />" 
 11.         } 
 12.     } 
 13.      
 14.     init(name: String, text: String? = nil) { 
 15.         self.name = name 
 16.         self.text = text 
 17.     } 
 18.      
 19.     deinit { 
 20.         println("\(name) is being deinitialized") 
 21.     } 
 22.      
 23. }
~~~

- textがバインドされるまえにnilするとdeinitされる

~~~
 23> var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
paragraph: HTMLElement? = Some {
  name = "p"
  text = "hello, world"
  asHTML.storage = nil
}
 24> paragraph = nil
p is being deinitialized
~~~


しかし、nilをするまえに asHTML()を呼んでしまうと textがクロージャに強く参照されてしまって、nilしてもdeinitされない

~~~

 25> var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world") 

paragraph: HTMLElement? = Some {
  name = "p"
  text = "hello, world"
  asHTML.storage = nil
}
 26> paragraph!.asHTML()
$R0: String = "<p>hello, world</p>"
 27> paragraph = nil

~~~


- closure capture list で解決するらしい


## Defining a Capture List


クロージャを修飾する

- [unowned self]
- [weak someInstance]

リストというからには複数してい可能なんでしょう


## Weak and Unowned References

-　asHTML() に対して、 selfをownしないこと！と修飾すると self.text が クロージャから弱い参照になるので selfがnilされると deinitが呼ばれるようになる

~~~
  2.          
  3.     let name: String 
  4.     let text: String? 
  5.          
  6.     lazy var asHTML: () -> String = {  
  7.         [unowned self] in 
  8.         if let text = self.text { 
  9.             return "<\(self.name)>\(text)</\(self.name)>" 
 10.         } else { 
 11.             return "<\(self.name) />" 
 12.         }    
 13.     }    
 14.          
 15.     init(name: String, text: String? = nil) { 
 16.         self.name = name 
 17.         self.text = text 
 18.     }    
 19.          
 20.     deinit { 
 21.         println("\(name) is being deinitialized") 
 22.     }    
 23.          
 24. }

 25>  
 26> var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
paragraph: HTMLElement? = Some {
  name = "p"
  text = "hello, world"
  asHTML.storage = nil
}
 27> paragraph!.asHTML()
$R0: String = "<p>hello, world</p>"
 28> paragraph = nil
p is being deinitialized
~~~

# GC

## C# 

-  [自動メモリ管理](http://msdn.microsoft.com/ja-jp/library/aa691138.aspx)
-  [System.GC](http://msdn.microsoft.com/ja-jp/library/system.gc.aspx)


## 参考

### [Transitioning to ARC Release Notes](https://developer.apple.com/library/mac/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html)

> Note: For apps targeting the Mac App Store, Apple strongly recommends you replace garbage collection with ARC as soon as feasible, because Mac App Store guidelines (see App Store Review Guidelines for Mac Apps) prohibit the use of deprecated technologies.

- [Mac App Store Review Guidelines](https://developer.apple.com/app-store/review/guidelines/mac/)


### [Why doesn't Apple Swift adopt the memory management method of garbage collection like in Java?](https://www.quora.com/Why-doesnt-Apple-Swift-adopt-the-memory-management-method-of-garbage-collection-like-in-Java)


### [Swift: ARC vs Flash GC](http://www.bytearray.org/?p=5439)


### [Why no Reference Counting + Garbage Collection in C#?](https://stackoverflow.com/questions/867114/why-no-reference-counting-garbage-collection-in-c)

### [Automatic Reference Counting vs. Garbage Collection](http://www.elementswiki.com/en/Automatic_Reference_Counting_vs._Garbage_Collection)

> ARC provides a method to avoid retain cycles, but it does require some explicit thought and design by the developer. To achieve this, ARC introduces Storage Modifiers that can be applied to object references (such as fields or properties) to specify how the reference will behave. By default, references are strong, which means that they will behave as described above, and storing an object reference will force the object to stay alive until the reference is removed. Alternatively, a reference can be marked as weak. In this case, the reference will not keep the object alive, instead, if all other references to the stored object go away, the object will indeed be freed and the weak reference will automatically be set to nil.


### [Objective-C ARCによるメモリ管理](http://cx5software.sakura.ne.jp/blog/2011/12/31/objective-c-memory_management_by_arc/)

> MRCがCOM(AddRef/Release)、ARCがATL(CComPtr)と思ってください。