NSView从超级视图中删除一些子视图

问题描述:

我有一个构建页面(NSView类页面)的广告布局程序,并在每个页面上放置页边距和排水沟(更多NSViews),然后放置广告(NSView类广告)。该应用会自动放置来自数据库源的广告,并在每个页面上寻找适当的空间。然后,用户可以选择将广告从第4页移动到第2页。他们还可以选择手动流动广告或让应用自动流动,假设您刚刚移动的广告将以0/0 x/y位置,然后其他人将流向任何可用空间,如果当前空间没有空间(由于您刚刚移动了广告),将被推送到下一页。NSView从超级视图中删除一些子视图

我在做的是获取所有页面(它们自己的NSView的子视图,称为masterpage),然后循环遍历它们以将所有子视图获取到数组中。循环访问该数组,过滤边距和排水沟,如果是广告,则将其从超级视图中移除。我的想法是从一个干净的页面开始,并替换所有的广告。问题是我不断收到此错误:

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

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

由于每个页面上的广告数量都是动态的,我怎样才能在不使用数组的情况下从他们的超级视图中删除它们?

正如错误所述,在使用快速枚举浏览数组时,不能修改数组的内容。 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]; 
+0

感谢您的快速答复,我打算试一试。但我仍然对如何修改数组内容感到困惑。是否因为当我循环访问数组时,我将视图从其超级视图中移除,因此数组对象指向的对象不再存在? – PruitIgoe

+0

也要感谢isMemberOfClass方法。不知道那个。 – PruitIgoe

+0

在列举数组的同时在有关变更数组的答案中增加了一条说明行。 – jrturton

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

while([[superView subviews] count] > 0) { 
    [[[superView subviews] objectAtIndex:0] removeFromSuperview]; 
} 

编辑:我新的目标C和Cocoa,所以我不知道如果这能工作没有ARC,因为我从来没有编码没有它。

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

Good Luck !!! 

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

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

如果检查类是一个问题(在原来的问题确实如此),那么,同样没有一个枚举,这个问题可以从后端解决:

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

我有这个代码在实践中,它的工作原理:-)