NSArrayM 在枚举时发生了突变

Posted

技术标签:

【中文标题】NSArrayM 在枚举时发生了突变【英文标题】:NSArrayM was mutated while being enumerated 【发布时间】:2012-09-21 04:41:10 【问题描述】:

应用程序因错误而崩溃:

*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x21481c10> was mutated while being enumerated.'

只有当我在加载注释时移动到 mapview 时才会发生这种情况。如果我不触摸地图,则不会发生错误。

- (void) startloading

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
                   ^

                       [self loadPList];

                   );

我的代码是:

- (void) loadPList


@autoreleasepool 

    NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *path = [[documentPaths lastObject] stringByAppendingPathComponent:@"test.plist"];

    NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];

    NSMutableArray *annotations = [[NSMutableArray alloc]init];



            NSMutableArray * annotationsToRemove = [ mapView.annotations mutableCopy ] ;
            [ annotationsToRemove removeObject:mapView.userLocation ] ;
            [ mapView removeAnnotations:annotationsToRemove ] ;


        if ([[NSUserDefaults standardUserDefaults] boolForKey:@"blackKey"])
        

            NSArray *ann = [dict objectForKey:@"Black"];

            for(int i = 0; i < [ann count]; i++) 

                NSString *coordinates = [[ann objectAtIndex:i] objectForKey:@"Coordinates"];

                double realLatitude = [[[coordinates componentsSeparatedByString:@","] objectAtIndex:1] doubleValue];
                double realLongitude = [[[coordinates componentsSeparatedByString:@","] objectAtIndex:0] doubleValue];

                MyAnnotation *myAnnotation = [[MyAnnotation alloc] init];
                CLLocationCoordinate2D theCoordinate;
                theCoordinate.latitude = realLatitude;
                theCoordinate.longitude = realLongitude;

                myAnnotation.coordinate=CLLocationCoordinate2DMake(realLatitude,realLongitude);        
                myAnnotation.title = [[ann objectAtIndex:i] objectForKey:@"Name"];
                myAnnotation.subtitle = [[ann objectAtIndex:i] objectForKey:@"Address"];
                myAnnotation.icon = [[ann objectAtIndex:0] objectForKey:@"Icon"];

                [mapView addAnnotation:myAnnotation]; // SIGNAL SIGABRT
                [annotations addObject:myAnnotation];


            

           



        if ([[NSUserDefaults standardUserDefaults] boolForKey:@"blueyellowKey"])
        

            NSArray *ann = [dict objectForKey:@"BlueYellow"];

            for(int i = 0; i < [ann count]; i++) 

                NSString *coordinates = [[ann objectAtIndex:i] objectForKey:@"Coordinates"];

                double realLatitude = [[[coordinates componentsSeparatedByString:@","] objectAtIndex:1] doubleValue];
                double realLongitude = [[[coordinates componentsSeparatedByString:@","] objectAtIndex:0] doubleValue];

                MyAnnotation *myAnnotation = [[MyAnnotation alloc] init];
                CLLocationCoordinate2D theCoordinate;
                theCoordinate.latitude = realLatitude;
                theCoordinate.longitude = realLongitude;

                myAnnotation.coordinate=CLLocationCoordinate2DMake(realLatitude,realLongitude);        
                myAnnotation.title = [[ann objectAtIndex:i] objectForKey:@"Name"];
                myAnnotation.subtitle = [[ann objectAtIndex:i] objectForKey:@"Address"];
                myAnnotation.icon = [[ann objectAtIndex:0] objectForKey:@"Icon"];

                [mapView addAnnotation:myAnnotation];
                [annotations addObject:myAnnotation];              

            

           



   

【问题讨论】:

【参考方案1】:

我认为您应该将您的 loadPlist 方法更改为此,然后调用 [self loadPlist] 来调用它:

- (void) loadPList

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
        NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
        NSString *path = [[documentPaths lastObject] stringByAppendingPathComponent:@"test.plist"];
        NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];

        //ALL THIS CODE FROM HERE ON OUT IS NOT THREAD SAFE! YOU ARE ACCESSING THE UI AND MUST PERFORM IT ON THE MAIN THREAD!
        dispatch_async(dispatch_get_main_queue(), ^
            NSMutableArray *annotations = [[NSMutableArray alloc]init];
            NSMutableArray * annotationsToRemove = [ mapView.annotations mutableCopy ] ;
            [ annotationsToRemove removeObject:mapView.userLocation ] ;
            [ mapView removeAnnotations:annotationsToRemove ] ;


            if ([[NSUserDefaults standardUserDefaults] boolForKey:@"blackKey"])
            
                NSArray *ann = [dict objectForKey:@"Black"];
                for(int i = 0; i < [ann count]; i++) 
                    NSString *coordinates = [[ann objectAtIndex:i] objectForKey:@"Coordinates"];

                    double realLatitude = [[[coordinates componentsSeparatedByString:@","] objectAtIndex:1] doubleValue];
                    double realLongitude = [[[coordinates componentsSeparatedByString:@","] objectAtIndex:0] doubleValue];

                    MyAnnotation *myAnnotation = [[MyAnnotation alloc] init];
                    CLLocationCoordinate2D theCoordinate;
                    theCoordinate.latitude = realLatitude;
                    theCoordinate.longitude = realLongitude;

                    myAnnotation.coordinate=CLLocationCoordinate2DMake(realLatitude,realLongitude);        
                    myAnnotation.title = [[ann objectAtIndex:i] objectForKey:@"Name"];
                    myAnnotation.subtitle = [[ann objectAtIndex:i] objectForKey:@"Address"];
                    myAnnotation.icon = [[ann objectAtIndex:0] objectForKey:@"Icon"];

                    [mapView addAnnotation:myAnnotation]; // SIGNAL SIGABRT
                    [annotations addObject:myAnnotation];
                
               

            if ([[NSUserDefaults standardUserDefaults] boolForKey:@"blueyellowKey"])
            
                NSArray *ann = [dict objectForKey:@"BlueYellow"];

                for(int i = 0; i < [ann count]; i++) 
                
                    NSString *coordinates = [[ann objectAtIndex:i] objectForKey:@"Coordinates"];

                    double realLatitude = [[[coordinates componentsSeparatedByString:@","] objectAtIndex:1] doubleValue];
                    double realLongitude = [[[coordinates componentsSeparatedByString:@","] objectAtIndex:0] doubleValue];

                    MyAnnotation *myAnnotation = [[MyAnnotation alloc] init];
                    CLLocationCoordinate2D theCoordinate;
                    theCoordinate.latitude = realLatitude;
                    theCoordinate.longitude = realLongitude;

                    myAnnotation.coordinate=CLLocationCoordinate2DMake(realLatitude,realLongitude);        
                    myAnnotation.title = [[ann objectAtIndex:i] objectForKey:@"Name"];
                    myAnnotation.subtitle = [[ann objectAtIndex:i] objectForKey:@"Address"];
                    myAnnotation.icon = [[ann objectAtIndex:0] objectForKey:@"Icon"];

                    [mapView addAnnotation:myAnnotation];
                    [annotations addObject:myAnnotation];              
                
               
        
    );
 

这会在后台执行读取注释的 IO 工作,然后将 UI 工作传递回主线程。希望这会有所帮助!

【讨论】:

@PavelKaljunen 哪个对象在泄漏? NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path]; 如果我删除 dispatch_async,那么它就不会泄漏 内层还是外层?另外,对于您使用不同代码的两个问题,我不确定您到底在做什么。你为什么不解决这个问题,并用你当前的代码更新你的内存泄漏问题 - 你的 loadPlist 实现和你调用它的地方,以及任何指示泄漏的仪器结果。这真的会帮助我帮助你。 非常感谢您的帮助!我更新了这个问题:***.com/questions/12653016/…

以上是关于NSArrayM 在枚举时发生了突变的主要内容,如果未能解决你的问题,请参考以下文章

仅在发布模式下“枚举 NSArray 集合时发生突变”

NSArraym 在枚举时发生了变异,sqlite3 while 循环?

在目标 C 中枚举错误时,集合发生了突变

集合 <__NSSetM: 0x14ea0160> 在枚举时发生了突变

UIImagePickerController - 枚举时集合发生突变

枚举时发生突变的数组