

ベースとなるViewを生成し、その上に機能に応じたUIパーツを`addSubView()`します。  
その後機能を変えた場合はベースとなるViewの上のUIパーツを全て`removeFromSuperview()`してから値を再設定し`addSubView()`という処理を行ったのですが、  
再設定後の表示が画面の左上にUIパーツがまとまった状態になり、Debug View
Hierarchyで確認するとRuntimeErrorに以下のエラーが出ていました。

[code]

    Layout Issues 
       -> Position is ambiguous for UILabel
    
[/code]

StoryBoard上でAutoLayoutは設定はしてあります。  
なので、再設定をしない初回は正しく表示されます。

`removeFromSuperview()`をした場合、インスタンスは解放されずViewとの繋がりが絶たれるだけだという認識でいたので、制約が解除されるという想定はしていませんでしたが、  
UIパーツの制約が解除されてしまうということはあるのでしょうか？


CC BY-SA 3.0
2016-10-20T02:30:47.417
29726
2016-10-20T04:38:28.037
14782
question
swift xcode swift3
removeFromSuperview()をした場合の動きについて


> `removeFromSuperview()`をした場合、インスタンスは解放されずViewとの繋がりが絶たれるだけだという認識でいたので、

その認識は正しくありません。あるViewは、Superview以外のオブジェクトから強参照されていない場合、解放されます。そしてAuto
Layoutによる制約（Constraint）は、この「Superview以外のオブジェクト」にはあたりません。  
ここで「解放する」とは、いつでも解放されていい状態にするという意味で使われていて、直ちに解放することではないので、オブジェクトの監視システムが解放する直前の限られたタイミングで、`nil`をチェックすると、アドレスが取得できたりすることがあります。

こういう時は、検証用のプログラムを作ってみるといいでしょう。  
ひとつの`UILabel`と、ふたつの`UIButton`を作ります。インスタンス`label`は、Storyboard上で、Constraintの設定をしておいてください。

[code]

    import UIKit
    
    class ViewController: UIViewController {
    
        @IBOutlet weak var label: UILabel!
    
        override func viewDidLoad() {
            super.viewDidLoad()
        }
    
        @IBAction func removeLabel(_ sender: AnyObject) {
            label.removeFromSuperview()
        }
    
        @IBAction func nilCheck(_ sender: AnyObject) {
            if label == nil {
                print("Label is nil")
            } else {
                print("Label is not nil")
            }
        }
    }
    
[/code]

`removeLabel()`のボタンを押して、次に`nilCheck()`のボタンを押してください。

> 出力：Label is nil

Storyboard/Interface
Builderで配置したViewは、`removeFromSuperview()`しない。表示からViewを消したければ、`isHidden`（Swift2以前では、`hidden`）で、非表示にする方法を選ぶ。非表示にした場合、Constraintは維持しています。


CC BY-SA 3.0
2016-10-20T03:35:46.383
29729
2016-10-20T04:31:28.677
2016-10-20T04:31:28.677
18540
18540
29726
answer


AutoLayoutは隣接する他のビューや、superViewとの相対的な関係を表すものですので、`removeFromSuperView()`メソッドでビューを外した場合、たいていは制約の整合性が崩れて、書かれたような制約のエラーが起こります。  
ビューを実行時に外したり追加したりなど、構造を変えた場合は制約も合わせて変更する必要があります。  
実行時にコードでAutoLayoutの制約をビューに合わせて変更するのは面倒なので、可能なら別の構成のビューを用意しておいて、表示を切り替える、などとする方が簡単だと思います。


CC BY-SA 3.0
2016-10-20T04:04:14.883
29730
2016-10-20T04:04:14.883
5519
29726
answer


`removeFromSuperview()` の[API
Reference](https://developer.apple.com/reference/uikit/uiview/1622421-removefromsuperview)を参照してみてください。

> Calling this method removes any constraints that refer to the view you are
> removing, or that refer to any view in the subtree of the view you are
> removing.

とある通り、`removeFromSuperview()` では、view と同時に関連する制約も取り除かれます。

制約のエラーが出るのは、storyboard 上で設定していた制約が失われてしまうためです。

コードで AutoLayout を再設定するか、もしくは `removeFromSuperview()` を呼び出す前にその view
に関連する制約を退避させて、`addSubview()` 後に再度適用する必要があります。


CC BY-SA 3.0
2016-10-20T04:38:28.037
29732
2016-10-20T04:38:28.037
5337
29726
answer