【问题标题】:NSView remove some subviews from superviewNSView 从 superview 中删除一些子视图
【发布时间】:2011-11-01 15:49:27
【问题描述】:

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

我正在做的是获取所有页面(它们本身就是一个名为 masterpage 的 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];
            }
        }
    }

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

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

【问题讨论】:

    标签: arrays cocoa subview superview


    【解决方案1】:

    正如错误所说,在使用快速枚举遍历数组时,您无法修改数组的内容。 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];  
    

    【讨论】:

    • 感谢您的快速回复,我将尝试一下。但是我仍然对如何修改数组的内容感到困惑。是因为当我遍历数组时,我正在从其父视图中删除视图,因此数组对象指向的对象不再存在?
    • 也感谢 isMemberOfClass 方法。不知道那个。
    • 在您枚举数组时添加了关于改变数组的解释行。
    • 它成功了,只需要修复第一个NSMutableArray调用,没有*,除了它很好。
    • 啊,这个解释很有道理。谢谢。
    【解决方案2】:

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

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

    编辑:我是 Objective C 和 Cocoa 的新手,所以我不知道在没有 ARC 的情况下这是否可行,因为我从来没有在没有它的情况下进行编码。

    【讨论】:

      【解决方案3】:
      if([[yourView subviews] count] > 0) {
          [[[yourView subviews] objectAtIndex:0] removeFromSuperview];
      }
      
      Good Luck !!!
      

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          【解决方案5】:

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

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

          我在实践中有这段代码,它可以工作:-)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-02-08
            • 1970-01-01
            相关资源
            最近更新 更多