NSView从superview中删除一些子视图

时间:2011-11-01 15:49:28

标签: arrays cocoa subview superview

我有一个广告布局程序,用于构建页面(NSView类页面),并在每个页面上放置边距和装订线(更多NSView),然后是广告(NSView类广告)。该应用自动从数​​据库源中放置广告,寻找适当的空间来填充每个页面。然后,用户可以选择将广告从第4页移至第2页。他们还可以选择手动流动广告或让应用自动流动,假设您刚刚移动的广告最终会以0 / 0 x / y位置,然后其他人将流向任何可用空间,如果当前空间没有空间(由于您刚刚移动的广告),则推送到下一页。

我正在做的是获取所有页面(它们本身是NSView的子视图,称为母版页),然后循环遍历它们以将所有子视图放入数组中。循环遍历该数组,过滤边距和装订线,如果是广告,则将其从超级视图中删除。我的想法是从干净的页面开始并替换所有广告。问题是我一直收到这个错误:

Collection <NSCFArray: 0x1078900> was mutated while being enumerated.

我正在使用此代码:

//loop through all the pages
    for(NSView* thisPage in masterPageSubViews) { 

        //get all the ads on this page
        NSArray* thisPageSubviews = [thisPage subviews];
        for(NSView* thisPageSubview in thisPageSubviews) { 
            if ([[thisPageSubview className] isEqual:@"Ad"]) { 
                [thisPageSubview removeFromSuperview];
            }
        }
    }

我想我很困惑为什么我收到这个错误。我认为数组中的对象与循环中创建的对象是分开的。

由于每个页面上的广告数量是动态的,如何在不使用数组的情况下将其从超级视图中删除?

5 个答案:

答案 0 :(得分:7)

如错误所示,使用快速枚举时,无法修改数组的内容。 removeFromSuperview从其超级视图的subviews数组中移除视图(这是一个难以阅读的句子!)。这意味着当您枚举数组时, 会对数组进行变更。

可能有更好的方法,但您可以使用广告视图填充NSMutableArray,然后一旦完成,就可以让他们从超级视图中删除自己(未经测试的代码,输入浏览器!)

NSMutableArray *viewsToRemove = [[NSMutableArray alloc] init];
for(NSView* thisPage in masterPageSubViews) 
{           
    //get all the ads on this page         
    NSArray* thisPageSubviews = [thisPage subviews];         
    for(NSView* thisPageSubview in thisPageSubviews)              
        if ([thisPageSubview isMemberOfClass:[Ad class]]) 
            [viewsToRemove addObject:thisPageSubview];                                 
}         
[viewsToRemove makeObjectsPerformSelector:@selector(removeFromSuperview)];
[viewsToRemove release];  

答案 1 :(得分:5)

上面的答案相当昂贵,为什么在可以避免的情况下创建对象呢?你可以用更少的代码做同样的事情。

while([[superView subviews] count] > 0) {
    [[[superView subviews] objectAtIndex:0] removeFromSuperview];
}
编辑:我是Objective C和Cocoa的新手,所以我不知道如果没有ARC,这是否可行,因为如果没有它,我就不会编码。

答案 2 :(得分:0)

if([[yourView subviews] count] > 0) {
    [[[yourView subviews] objectAtIndex:0] removeFromSuperview];
}

Good Luck !!!

答案 3 :(得分:0)

至少从10.10开始,你可以在子视图上使用快速枚举,因为它会返回一个副本。

[view.subviews enumerateObjectsUsingBlock:^(NSView * subview, NSUInteger idx, BOOL *stop) {
    [subview removeFromSuperview];
}];

答案 4 :(得分:0)

如果检查类是一个问题(并且在原始问题中),那么,再次没有枚举器,问题可以从后端解决:

NSArray *subs = [myView subviews];
for(NSInteger i=[subs count]-1; i>0; i--){
    if([[subs[i] className]isEqual:@"nameOfClassToDelete"]){
        [subs[i] removeFromSuperviewWithoutNeedingDisplay];
    }
}

我在实践中有这个代码,它有效: - )