すべてのサブビューを削除しますか?


316

アプリがルートビューコントローラーに戻ったら、viewDidAppear:メソッドですべてのサブビューを削除する必要があります。

これどうやってするの?

回答:


569

編集:cocoafanのおかげで:この状況は、物事を異なる方法NSViewUIView処理するという事実によって混乱しています。以下のためにNSView(のみデスクトップのMac開発)、あなたは、単に以下のように使用することができます。

[someNSView setSubviews:[NSArray array]];

以下のためにUIView(のみのiOS開発)、あなたは安全に使用することができますmakeObjectsPerformSelector:ので、subviewsプロパティが返されますコピーサブビューの配列のを:

[[someUIView subviews]
 makeObjectsPerformSelector:@selector(removeFromSuperview)];

ありがとうトミーことを指摘するためにmakeObjectsPerformSelector:表示され、変更するsubviewsことが列挙されている間、(それがためていた配列をNSView、ではないためUIView)。

詳細については、このSOの質問を参照してください。

注:これらの2つの方法のいずれかを使用すると、メインビューに含まれているすべてのビューが削除され他の場所に保持されていない場合は解放されます。removeFromSuperviewに関するAppleのドキュメントから:

レシーバーのスーパービューがnilでない場合、このメソッドはレシーバーを解放します。ビューを再利用する予定がある場合は、このメソッドを呼び出す前にビューを保持し、必要に応じて、またはビューを別のビュー階層に追加した後は、必要に応じて解放してください。


9
これは安全ですか?それはそれを繰り返しながらリストを変更します、そして私はAppleのドキュメントで決定的なステートメントを見つけることができません。
トミー

8
@トミー:それは良い点です。一部のグーグルは答えを出しました:可変配列のコピーUIView返すので、このコードはうまくいきます。デスクトップ上のまったく異なるストーリー。同じコードが例外をスローします。stackoverflow.com/questions/4665179/…を参照してくださいsubviews
e.James

3
UIViewはsetSubviews:に応答しませんか?
cocoafan 2011年

4
Xamarinの方法:someUIView.Subviews.All(p => p.RemoveFromSuperview);
Benoit Jadinon

3
@BenoitJadinon-コンパイルされません-あなたはForEachを実行するためにAllを悪用することを意味しているようsomeUIView.Subviews.All( v => { v.RemoveFromSuperview(); return true; } );です。あなたが何を意味するか言うために私見クリーナー: someUIView.Subviews.ToList().ForEach( v => v.RemoveFromSuperview() );
ToolmakerSteve 2016

173

ルートコントローラーからすべてのサブビューを取得し、それぞれにremoveFromSuperviewを送信します。

NSArray *viewsToRemove = [self.view subviews];
for (UIView *v in viewsToRemove) {
    [v removeFromSuperview];
}

+1、ありがとうございます。私もself.viewあなたのように使うべきだった。
e.James、2010年

2
何故なの!?for (UIView *v in [self.view subviews])簡単
Frade

4
@Frade彼が行った方法よりもはるかに明確で冗長です。詳細と読みやすさ>キーストロークの保存
taylorcressy 14

33
@taylorcressy「読みやすさ>キーストロークの保存」ではなく、「キーストロークの保存よりも読みやすさの方が重要」と言ったほうがいいでしょう。そうすれば、コメントが読みやすくなります。:-)
arlomedia 2015年

1
[self.view subviews]が内部で計算を実行する場合、それをforループに直接置くと、それらの計算が何度も実行される可能性があるという事実を忘れないでください。ループの前に宣言すると、確実に1回だけ実行されます。
ブライアンサシェッタ

116

スウィフトを使用でき、機能的なアプローチこのように:

view.subviews.forEach { $0.removeFromSuperview() }

比較として、命令型アプローチは次のようになります。

for subview in view.subviews {
    subview.removeFromSuperview()
}

これらのコードスニペットはiOS / tvOSでのみ機能しますが、macOSでは少し異なります。


4
(subviews as [UIView]).map { $0.removeFromSuperview() }
DeFrenZ、2015年

8
関数は値を返し、これはの結果を破棄するだけなので、機能しません.map。これは純粋な副作用であると、より良い、このように処理されますview.subviews.forEach() { $0.removeFromSuperview() }
マーティンAlgesten

1
あなたは正しい、マーティン、私はあなたに同意します。配列にforEach()メソッドがあることを知りませんでした。追加されたのはいつですか、それとも監督しただけですか?回答を更新しました!
Jeehut 2015年

1
私はとても面倒なので、サブビューをクリアする方法を知っていても、スニペットをコピーして貼り付け、+ 1を付けるためにここに来ました
Vilmir

13

UIView(ここyourView)のすべてのサブビューを削除する場合は、ボタンをクリックしてこのコードを記述します。

[[yourView subviews] makeObjectsPerformSelector: @selector(removeFromSuperview)];

12
Stack Overflowへようこそ!このコードが機能する理由を説明するための説明を追加することを検討しますか?また、それが質問に対する答えとなる理由は何ですか?これは、質問をする人や、一緒に来た人にとって非常に役立ちます。さらに、すでに受け入れられている回答には、基本的にこれと同じコードが含まれています。
Andrew Barberが

5
これは、受け入れられた答えよりもどのように役立つのでしょうか。同じです。なぜこれを書くのですか?
Rambatino、2014年

8

iOSでは配列のコピーが保持されるため、これはOSXにのみ適用されます

すべてのサブビューを削除する場合は、配列の最後から削除を開始し、最初に到達するまで削除を続けることをお勧めします。これは、次の2行のコードで実現できます。

for (int i=mySuperView.subviews.count-1; i>=0; i--)
        [[mySuperView.subviews objectAtIndex:i] removeFromSuperview];

SWIFT 1.2

for var i=mySuperView.subviews.count-1; i>=0; i-- {
    mySuperView.subviews[i].removeFromSuperview();
}

または(効率は落ちますが、読みやすくなります)

for subview in mySuperView.subviews.reverse() {
    subview.removeFromSuperview()
}

注意

メッセージが配列のすべてのオブジェクトに送信される前にUIViewインスタンスが削除されると、クラッシュを引き起こす可能性があるため、通常の順序でサブビューを削除しないでくださいremoveFromSuperview。(明らかに、最後の要素を削除してもクラッシュは発生しません)

したがって、コード

[[someUIView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];

使用しないでください。

makeObjectsPerformSelectorに関するAppleドキュメントからの引用:

最初のオブジェクトから最後のオブジェクトまで、指定されたセレクターで識別されたメッセージを配列内の各オブジェクトに送信します。

(これはこの目的のために間違った方向になるでしょう)


あなたが言及しているものの例を挙げていただけますか?「要素」とは何を指しているのかわからない。そして、removeFromSuperViewを呼び出す前に、この要素をどのように削除するのか。
牧師

しかし、このメソッドを呼び出すときに、UIViewのインスタンスをどのように削除できますか?サブビュー配列から削除されたということですか?
牧師

ときremoveFromSuperview仕上げは、UIViewのは、配列から削除されますのUIViewに強い関係を持つ他の生活のインスタンスが存在しない場合、および、UIViewのも削除されます。これにより、範囲外の例外が発生する可能性があります。
Daniel

1
ゲッチャ!ありがとうございました。IOSでサブビュー配列のコピーを取得していると思います。いずれにしても、サブビューを削除したい場合は、自分でコピーを作成することをお勧めします。
牧師の

@simpleBob-承認された回答について2011年に書かれたコメントを読みましたか?これらのコメントによると、iOSでは[yourView subviews]配列のCOPYが返されるため、安全です。(OSXでは、あなたの言うことは正しいことに注意してください。)
ToolmakerSteve

4

この方法をすぐに試してください2.0

view.subviews.forEach { $0.removeFromSuperview() }

2
回答日が早いのがわかりませんか?私の回答リンクをその回答に貼り付けてみませんか?
William Hu

1
正解...回答はあなたの前に投稿されましたが、forEachベースのソリューションがあなたの後に追加されました、私はそれを逃しました。謝罪。
Cristik 2016年

4

次のコードを使用して、すべてのサブビューを削除します。

for (UIView *view in [self.view subviews]) 
{
 [view removeFromSuperview];
}

2

Swift UIView拡張機能の使用:

extension UIView {
    func removeAllSubviews() {
        for subview in subviews {
            subview.removeFromSuperview()
        }
    }
}

2

Objective-Cで、UIViewクラスからカテゴリメソッドを作成します。

- (void)removeAllSubviews
{
    for (UIView *subview in self.subviews)
        [subview removeFromSuperview];
}

2
view.subviews.forEach { $0.removeFromSuperview() }

2
このコードは質問に答えることがありますが、問題を解決する方法および/または理由に関する追加のコンテキストを提供すると、回答の長期的な価値が向上します。
Nic3500 2018

1

すべてのサブビューを削除するには構文:

- (void)makeObjectsPerformSelector:(SEL)aSelector;

使用法 :

[self.View.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];

このメソッドはNSArray.hファイルにあり、NSArray(NSExtendedArray)インターフェイスを使用します


1

Swiftを使用している場合は、次のように簡単です。

subviews.map { $0.removeFromSuperview }

哲学はmakeObjectsPerformSelectorアプローチと似ていますが、型の安全性が少し高くなっています。


これは意味的に正しくmapなく、副作用をもたらすことはありません。さらに、を使用しても同じ結果が得られますforEach
Cristik 2018年

0

autolayoutを使用するios6の場合も、制約を削除するためにコードを少し追加する必要がありました。

NSMutableArray * constraints_to_remove = [ @[] mutableCopy] ;
for( NSLayoutConstraint * constraint in tagview.constraints) {
    if( [tagview.subviews containsObject:constraint.firstItem] ||
       [tagview.subviews containsObject:constraint.secondItem] ) {
        [constraints_to_remove addObject:constraint];
    }
}
[tagview removeConstraints:constraints_to_remove];

[ [tagview subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];

これを行うためのよりきちんとした方法があると確信していますが、それは私にとってはうまくいきました。私の場合[tagview removeConstraints:tagview.constraints]、XCodeで設定された制約がクリアされていたため、直接使用できませんでした。


0

monotouch / xamarin.iosでこれは私のために働きました:

SomeParentUiView.Subviews.All(x => x.RemoveFromSuperview);

-10

スーパービューからすべてのサブビューを削除するには:

NSArray *oSubView = [self subviews];
for(int iCount = 0; iCount < [oSubView count]; iCount++)
{
    id object = [oSubView objectAtIndex:iCount];
    [object removeFromSuperview];
    iCount--;
}

ここ@Pravinでのいくつかの重大な誤り。最初に、「オブジェクト」をUIView *として定義する必要があります。そうしないと、[object removeFromSuperview]でコンパイラエラーが発生します。次に、あなたのforループはすでにiCountを減らしているので、iCount--行で余分なものをスキップしています。そして最後に、上記の2つの有効で正しいアプローチがあり、あなたのアプローチはよりエレガントでも速くもありません。
amergin 2014

5
各反復あなたがやるiCount++iCount--、それがあれば、無限ループになり、同じインデックスを残します[oSubView count]>0。これは間違いなくバグがあり、使用できないコードです。
ダニエル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.