10943


下記のように階層化されたViewがあるとします。

MainViewController: ViewController  
|- A_UIView: UIView  
|- B_UIView: UIView  
|- C_UIview: UIView  
|- C_a_UIView: UIView  
|- C_b_UIView: UIView

全てのUIViewで、自分の子要素を削除するためにdeinit内に下記の記述をしています。

[code]

    deinit {
        NSNotificationCenter.defaultCenter().removeObserver(self)
        var subviews = self.subviews
        for subview in subviews {
            subview.removeFromSuperview()
        }
    }
    
[/code]

MainViewControllerからC_UIViewを削除する時の記述は下記の通りです。

[code]

    self.C_UIView!.removeFromSuperview()
    self.C_UIView = nil
    
[/code]

すると、階層の深さに関係なくUIViewの中にあるanimateWithDurationについて、completionでEXC_BAD_ACCESSが発生してしまいます。

[code]

    UIView.setAnimationBeginsFromCurrentState(true)
        UIView.animateWithDuration(
            0.7,
            animations: {[unowned self]() -> Void in
            self.alpha = 0.0
            return
        },
        completion: {[unowned self](Bool) -> Void in <-この行で！
            self.hidden = false
        }
    )
    
[/code]

completionを削除すると問題なく動き、またどのアニメーションだから特別に発生するということはなく、おそらく参照や多重解放などが原因かとは思うのですが、親がremoveされた時に子供も全てremoveするにはどのような方法がベストなのでしょうか。


CC BY-SA 3.0
2015-02-12T07:57:37.823
6369
2015-06-03T09:23:52.513
2015-02-12T08:19:55.517
7352
7352
question
ios swift
removeFromSuperview時にanimateWithDurationのcompletionにEXC_BAD_ACCESS

[code]

    UIView.animateWithDuration(
        0.7,
        animations: {[unowned self]() -> Void in
        self.alpha = 0.0
        return
    },
    completion: {[unowned self](Bool) -> Void in <-この行で！
        self.hidden = false
    }
    
[/code]

これのselfは、UIViewControllerのサブクラスではなくて、UIViewのサブクラスですか？  
だったら、スレッドの無駄づかいを避ける意味でも、UIViewのアニメーションは、UIViewControllerのサブクラスに記述したほうがいいと思います。

（以下は、役に立たない情報として、削除しようと思いましたが、まあ、役に立たないという事実もまた、だれかの役に立つかもしれないと思い、残すことにしました。「for
- in」構文で、subviewsの全削除はできるらしいです。）

後に、ご質問の内容全体について検証するつもりですが、ぱっと見、これはまずいだろうと思った箇所があったので、そこだけ回答したいと思います。

[code]

    var subviews = parentView.subviews
    for subview in subviews {
        subview.removeFromSuperview()
    }
    
[/code]

ループを回しているあいだ、subviewsは、内容が変化し続けます。そういうループは予測のできない不具合が起きる危険があります。  
配列の要素を全削除というプログラムは、最後尾の要素から削除していくのが、定番です。

[code]

    // var subviews = parentView.subviews // この行はいらない。というか間違い。
    while parentView.subviews.count != 0 {
        parentView.subviews.last?.removeFromSuperview()
    }
    
[/code]


CC BY-SA 3.0
2015-02-12T08:16:34.737
6372
2015-02-12T18:36:09.523
2015-02-12T18:36:09.523
7362
7362
6369
answer


かなり時間が経っていますが、原因が確実になりましたので自己レスいたします。

結果的に原因は[unowned self]でした。

この記述を[weak self]に変更し、selfのものが参照されたときにnilであれば参照しないようにしてやることで、落ちることがなくなりました。

ありがとうございました。


CC BY-SA 3.0
2015-06-03T09:23:52.513
10943
2015-06-03T09:23:52.513
7352
6369
answer