【问题标题】:Collection <CALayerArray: 0x1ed8faa0> was mutated while being enumerated集合 <CALayerArray: 0x1ed8faa0> 在枚举时发生了变异
【发布时间】:2013-01-29 01:17:36
【问题描述】:

从屏幕上删除等待视图时,我的应用程序崩溃了一段时间。请指导我如何改进下面给出的代码。


仅当应用程序从服务器下载内容时才会调用等待视图。当它完成下载然后我调用 removeWaitView 方法。

异常类型:NSGenericException

原因:集合在枚举时发生了变异。

+(void) removeWaitView:(UIView *) view{
    NSLog(@"Shared->removeWaitView:");
    UIView *temp=nil;
    temp=[view viewWithTag:kWaitViewTag];
    if (temp!=nil) {
        [temp removeFromSuperview];
    }
}

我的waitview添加代码是

 +(void) showWaitViewInView:(UIView *)view withText:(NSString *)text{
   NSLog(@"Shared->showWaitViewWithtag");
   UIView *temp=nil;
   temp=[view viewWithTag:kWaitViewTag];
   if (temp!=nil)
   {
       return;
   }
   //width 110 height 40
   WaitViewByIqbal *waitView=[[WaitViewByIqbal alloc] initWithFrame:CGRectMake(0,0,90,35)];
   waitView.center=CGPointMake(view.frame.size.width/2,(view.frame.size. height/2) -15); 
   waitView.tag=kWaitViewTag;    // waitView.waitLabel.text=text;
   [view addSubview:waitView];
   [waitView release]; 
}

【问题讨论】:

  • 查看异常的完整回溯会很有用。 (如果您不确定如何找到这些信息,您可以 Google 搜索一下。)
  • removeWaitView 怎么叫?

标签: iphone ios objective-c


【解决方案1】:

例外情况非常明显 - 集合(在本例中类似于数组)在被枚举的同时被修改。

在这种特定情况下,我们讨论的是层数组,或者更好地说,UIView 的实例都由层支持。

当您调用removeFromSuperviewaddSubview 时会发生修改。枚举可以在重绘期间随时发生。

我的猜测是 - 你没有从主线程调用你的方法并且主线程当前正在重绘,所以你会得到一个竞速条件。

解决方案:仅从主线程调用这些方法。

【讨论】:

  • 嗯。我总是尝试在主线程上调用这些方法,但在我看来你是对的,因为这个异常只有在不从主线程调用时才会出现(根据我的代码)。我说的对吗?
  • @Developer Aaron Haymain 的回答是另一种可能的解释。从您的堆栈跟踪中应该很明显。
  • 非常聪明的分析。谢谢。
【解决方案2】:

您应该获得数组的副本,这样您就不会冒在代码枚举它时修改它的风险。当然,这留下了可能由于突变而添加新项目的机会,因此您的枚举将错过那个数组项目。这是一个特定于您问题标题的示例:

[[viewLayer.sublayers copy] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            CALayer * subLayer = obj;
            if(subLayer == theLayerToBeDeleted){
                [subLayer removeFromSuperlayer];
            }

        }];

【讨论】:

    【解决方案3】:

    您可能会在迭代 waitView 的兄弟姐妹(它是 superView 的子视图)时添加或删除 waitView。检查哪些方法调用了removeWaitViewshowWaitInView,以确保调用方法不会从迭代等待视图的兄弟(waitView 的父视图的子视图)的 for 循环中调用 show/remove 等待视图方法。

    【讨论】:

    • 是的,如果我在循环中使用过,这可能会产生问题,不,我没有在循环中使用它。正如我编辑了我的问题,感谢您提供信息
    • 很高兴为您提供帮助。通常,来自循环内的显式突变是最常见的罪魁祸首。但突变也可能发生在另一个线程(@sulthan 指出)。
    猜你喜欢
    • 1970-01-01
    • 2012-05-04
    • 2014-02-15
    • 2017-11-22
    • 1970-01-01
    • 2011-03-27
    • 2012-07-30
    • 2014-07-04
    • 2023-03-13
    相关资源
    最近更新 更多