删除所有子视图?


316

当我的应用回到其根视图控制器时,在该viewDidAppear:方法中,我需要删除所有子视图。

我怎样才能做到这一点?

Answers:


569

编辑:感谢cocoafan:这种情况被NSViewUIView处理不同的事实所困扰。对于NSView(仅限桌面Mac开发),您可以简单地使用以下命令:

[someNSView setSubviews:[NSArray array]];

对于UIView(仅适用于iOS开发),您可以放心使用,makeObjectsPerformSelector:因为该subviews属性将返回子视图数组的副本

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

感谢Tommy指出,在枚举数组时makeObjectsPerformSelector:似乎会修改subviews数组(该数组用于NSView,但不用于UIView)。

请参阅此SO问题以获取更多详细信息。

注意:使用这两种方法之一将删除主视图包含的每个视图,并释放它们(如果未在其他位置保留它们)。从Apple关于removeFromSuperview的文档中:

如果接收方的超级视图不为零,则此方法释放接收方。如果计划重用该视图,请确保在调用此方法之前保留该视图,并确保在完成该视图或将其添加到另一个视图层次结构后将其适当地释放。


9
您确定这是安全的吗?它会在迭代时更改列表,而我无法在Apple文档中找到明确的声明。
汤米

8
@汤米:这是一个好点。一些谷歌搜索变成了答案:UIView返回一个副本中的subviews可变数组,所以这段代码只是工作。桌面上完全不同的故事,相同的代码将引发异常。见stackoverflow.com/questions/4665179/...
e.James

3
UIView不响应setSubviews :,对吗?
cocoafan 2011年

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

3
@BenoitJadinon-不会编译-您似乎要滥用All来执行ForEach,所以someUIView.Subviews.All( v => { v.RemoveFromSuperview(); return true; } );。恕我直言,清洁工说你的意思: someUIView.Subviews.ToList().ForEach( v => v.RemoveFromSuperview() );
ToolmakerSteve

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 2014年

33
@taylorcressy您应该说“可读性比保存击键更为重要”,而不是“可读性>保存击键”,然后您的注释将更具可读性。:-)
arlomedia

1
让我们不要忘记以下事实:如果[self.view subviews]在后台执行任何计算,将其直接放在for循环中可能会导致这些计算一遍又一遍地执行。在循环之前声明它可以确保它们仅执行一次。
Brian Sachetta

116

Swift中,您可以使用如下功能方法

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

作为比较,命令式方法如下所示:

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

这些代码段仅在iOS / tvOS中有效,但是在macOS上则有所不同。


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

8
它不起作用,因为函数会返回一个值,而这只会丢弃的结果.map。这是纯粹的副作用,可以这样处理:view.subviews.forEach() { $0.removeFromSuperview() }
Martin Algesten 2015年

1
你说得对,马丁,我同意你的看法。我只是不知道Arrays上有一个forEach()方法。它是何时添加的,还是我刚刚对其进行监视的?我已经更新了答案!
Jeehut 2015年

1
我很懒惰,即使我知道如何清除子视图,我仍然会来这里复制/粘贴您的代码片段并添加+1
Vilmir

13

如果要删除UIView(此处为yourView)上的所有子视图,请在单击按钮时编写以下代码:

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

12
欢迎使用Stack Overflow!您是否考虑添加一些叙述来解释此代码为何起作用,以及什么使其成为问题的答案?这对提出问题的人以及其他任何人都非常有帮助。另外,已经接受的答案包括与此基本相同的代码。
安德鲁·巴伯

5
与公认的答案相比,这有什么帮助呢?为什么写这个?
拉巴蒂诺2014年

8

这仅适用于OSX,因为在iOS中会保留阵列的副本

删除所有子视图时,最好在数组末尾开始删除,并一直删除直到到达开头为止。这可以通过以下两行代码来完成:

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)];

应该被使用。

Apple文档中关于makeObjectsPerformSelector的引用:

将给定选择器标识的消息发送到数组中的每个对象,从第一个对象开始,一直到数组的最后一个对象。

(这将是错误的方向)


你能举一个你所指的例子吗?不知道您所说的“元素”是什么?在调用removeFromSuperView之前如何删除这些元素?
2015年

但是,如何在调用此方法时删除UIView的实例?您的意思是从子视图数组中删除吗?
2015年

removeFromSuperview完成时,UIView的会从数组中删除,如果有一个强有力的关系UIView的没有其他生活的情况下,UIView的也将被删除。这可能会导致超出范围的异常。
丹尼尔(Daniel)

1
知道了!谢谢。我认为您正在IOS上获得subviews数组的副本。无论如何,如果要删除子视图,最好自己制作一个副本。
的牧师

@simpleBob-您是否阅读了2011年对已接受答案的评论?根据这些评论,在iOS上,[yourView subviews]返回数组的COPY,因此是安全的。(请注意,在OSX上您所说的是正确的。)
ToolmakerSteve16年

4

尝试这种方式swift 2.0

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

2
您没有看到我早些的约会日期吗?为什么不将我的答案链接粘贴到该答案中?
胡锦涛

1
是的...答案是在您之前发布的,但是forEach基础解决方案是在您之后添加的,我错过了。道歉。
Cristik '16

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 '18

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 '18 -10-26

0

对于使用自动布局的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--行中跳过了多余的一个。最后,上面有两种可行且正确的方法,您的方法既不优雅也不快捷。
amergin

5
每次迭代你做iCount++iCount--,使指数相同,所以这将是,如果一个无限循环[oSubView count]>0。这绝对是错误的,不是可用的代码。
丹尼尔(Daniel)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.