複数回addSubviewを呼んだ時の挙動について


# 概要
動的に`UIView`に別の`UIView`を追加したい場合には、`addSubview`というメソッドが利用できます。

```Swift
//view1にview2を追加したい場合
        var view1 = UIView(frame:CGRectMake(0, 0, 200, 200))
        view1.backgroundColor = UIColor.blueColor()
        var view2 = UIView(frame:CGRectMake(50, 50, 100, 100))
        view2.backgroundColor = UIColor.greenColor()
        view1.addSubview(view2)
```
![Figure:1](https://qiita-image-store.s3.amazonaws.com/0/65758/4ef4aec7-bf50-9e12-b87b-ad4b4f9bc715.png "スクリーンショット 2015-07-18 11.10.00.png")

では、`view2`を`view1`以外のビューに対して`addSubview`を使って追加したらどうなるのでしょうか??

```Swift
        //view1, view1Aにview2を追加したい場合
        var view1 = UIView(frame:CGRectMake(0, 0, 200, 200))
        view1.backgroundColor = UIColor.blueColor()
        var view1A = UIView(frame:CGRectMake(0, 300, 200, 200))
        view1A.backgroundColor = UIColor.redColor()
        var view2 = UIView(frame:CGRectMake(50, 50, 100, 100))
        view2.backgroundColor = UIColor.greenColor()
        view1.addSubview(view2)
        view1A.addSubview(view2)
```

![スクリーンショット 2015-07-18 13.14.26.png](https://qiita-image-store.s3.amazonaws.com/0/65758/c250c842-5252-8cb4-c610-20620f57192a.png)


最後に追加したview1Aにのみ追加されるようです。
ということは、`view1`に追加されていた`view2`は`removeFromSuperview`によって削除されたのでしょうか？
view1にもview1Aにも追加されると思ってしまうケースも多いような気がします :sweat: 

# 検証
### Case1: 追加先を順々に変更してみる
見た目で挙動を確認するために次のようなコードを書いてみました。

```Swift
        let averageHeight = CGRectGetHeight(UIScreen.mainScreen().bounds) / 11.0
        let averageWidth = CGRectGetWidth(UIScreen.mainScreen().bounds) / 2.0
        //5つviewを追加するためのviewを用意する
        var subview1 = UIView(frame: CGRectMake(averageHeight,
                                                averageHeight,
                                                averageHeight,
                                                averageHeight))
        subview1.backgroundColor = UIColor.blueColor()
        subview1.center = CGPointMake(averageWidth, subview1.center.y)
        var subview2 = UIView(frame: CGRectMake(averageHeight,
                                                averageHeight*3,
                                                averageHeight,
                                                averageHeight))
        subview2.backgroundColor = UIColor.greenColor()
        subview2.center = CGPointMake(averageWidth, subview2.center.y)
        var subview3 = UIView(frame: CGRectMake(averageHeight,
                                                averageHeight*5,
                                                averageHeight,
                                                averageHeight))
        subview3.backgroundColor = UIColor.redColor()
        subview3.center = CGPointMake(averageWidth, subview3.center.y)
        var subview4 = UIView(frame: CGRectMake(averageHeight,
                                                averageHeight*7,
                                                averageHeight,
                                                averageHeight))
        subview4.backgroundColor = UIColor.yellowColor()
        subview4.center = CGPointMake(averageWidth, subview4.center.y)
        var subview5 = UIView(frame: CGRectMake(averageHeight,
                                                averageHeight*9,
                                                averageHeight,
                                                averageHeight))
        subview5.backgroundColor = UIColor.blackColor()
        subview5.center = CGPointMake(averageWidth, subview5.center.y)

        //追加するビューを用意する
        targetView = UIView(frame: CGRectMake(averageHeight/4, averageHeight/4, averageHeight/2, averageHeight/2))
        targetView.layer.cornerRadius = 4.0
        targetView.backgroundColor = UIColor.purpleColor()
        NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: "moveTargetView:", userInfo: nil, repeats: true)
        viewList = [subview1, subview2, subview3, subview4, subview5]
        subview1.addSubview(targetView)

    func moveTargetView(timer:NSTimer) {
        //追加先ビューの変更
        currentIndex = (currentIndex >= viewList.count - 1) ? 0 : currentIndex + 1
        let view = viewList[currentIndex]
        view.addSubview(targetView)
    }
```

![gif.gif](https://qiita-image-store.s3.amazonaws.com/0/65758/ee9c78e6-7963-7b50-1233-be1077626542.gif "gif.gif")

`moveTargetView:`がcallされる度にビューの位置が変わっていますね。
追加される先は１つのように見えます。



### Case2: RetainCountの確認
以下の様なコードを書いて追加された`childView`のRetainCountを計測してみました。

```objc
    UIView *parentView = [[UIView alloc] init];
    UIView *childView = [[UIView alloc] init];
    NSLog(@"Number of RetainCount = %ld", (long)CFGetRetainCount((__bridge CFTypeRef)childView));
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    NSLog(@"Number of RetainCount = %ld", (long)CFGetRetainCount((__bridge CFTypeRef)childView));
```

```text

2015-07-18 13:00:03.168 test-objC[9989:328391] Number of RetainCount = 1
2015-07-18 13:00:03.170 test-objC[9989:328391] Number of RetainCount = 2
```

`childView`のRetainCountはインスタンス生成 & `parentView`への`addSubview`の2回分しかないみたいです。

念のため、`ParentView`の`subviews`の数も確認してみました。

```objc 
    UIView *parentView = [[UIView alloc] init];
    UIView *childView = [[UIView alloc] init];
    NSLog(@"Number of Subviews = %lu", (unsigned long)parentView.subviews.count);
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    [parentView addSubview:childView];
    NSLog(@"Number of Subviews = %lu", (unsigned long)parentView.subviews.count);
```
```text

2015-07-18 13:03:16.407 test-objC[10052:330128] Number of Subviews = 0
2015-07-18 13:03:16.408 test-objC[10052:330128] Number of Subviews = 1
```

### Case3: addSubviewをする先を変更した場合に[will|did]MoveToSuperviewを確認
例えば、view1にview2を追加した場合やview2をview1から削除した場合、view2に対して,
`willMoveToSuperview(newSuperview: UIView?)`、`didmoveToSuperView()`が呼ばれます。
`willMoveToSuperview`の第一引数が`nil`の場合は`、superviewから削除された場合です。
確認するため、以下のように`View2`クラスのそれぞれのメソッドでログを吐くようにしてみました :bow:
 
```Swift
        var view1 = UIView(frame:CGRectMake(0, 0, 200, 200))
        view1.backgroundColor = UIColor.blueColor()
        var view1A = UIView(frame:CGRectMake(0, 300, 200, 200))
        view1A.backgroundColor = UIColor.redColor()
        var view2 = View2(frame:CGRectMake(50, 50, 100, 100))
        view2.backgroundColor = UIColor.greenColor()
        view1.addSubview(view2)   //View2クラスのview2にview1を追加
        view1A.addSubview(view2)  //View2クラスのview2にview1Aを追加
    
class View2: UIView {
    override func willMoveToSuperview(newSuperview: UIView?) {
        let isExistSuperview = (newSuperview != nil) ? true : false
        println("willMoveToSuperview: \(isExistSuperview)")
    }
    override func didMoveToSuperview() {
        println("didMoveToSuperview")
    }
}
```

```text

willMoveToSuperview: true
didMoveToSuperview
willMoveToSuperview: true
didMoveToSuperview
```

あれ。。。?! 呼ばれてないというかここは通らないよう...。
明示的にview1からview1Aに追加先を変更する前に、`removeFromSuperview`を呼ぶと、やはりそれぞれ３回ずつ呼ばれました。

```text
willMoveToSuperview: true
didMoveToSuperview
willMoveToSuperview: false
didMoveToSuperview
willMoveToSuperview: true
didMoveToSuperview
```

# まとめ
* 同じ`UIView`クラスのオブジェクトを別の`UIView`クラスのオブジェクトに追加した場合、直前の追加先からは削除され、参照カウンタに変動はない
* 暗黙的に`removeFromSuperview`が呼ばれているような挙動だが、`willMoveToSuperview`などは呼ばれない

ということでした :smiley: