Ios 为什么NSMutableDictionary的setObjectForKey方法会导致崩溃?

Ios 为什么NSMutableDictionary的setObjectForKey方法会导致崩溃?,ios,objective-c,nsmutabledictionary,Ios,Objective C,Nsmutabledictionary,在NSMutableDictionary对象上调用setObjectForKey方法时,应用程序崩溃。iUrlSavedWithThumbDic和url字符串的值如控制台中所示 [isUrlSavedWithThumbDic setObject:[NSNumber numberWithBool:YES] forKey:url]; 代码正在UIImageView类别中运行。isURLSavedWithThumbDic是类别内的静态变量,声明为: static NSMutableDictiona

在NSMutableDictionary对象上调用setObjectForKey方法时,应用程序崩溃。iUrlSavedWithThumbDic和url字符串的值如控制台中所示

[isUrlSavedWithThumbDic setObject:[NSNumber numberWithBool:YES] forKey:url];

代码正在UIImageView类别中运行。isURLSavedWithThumbDic是类别内的静态变量,声明为:

static NSMutableDictionary *isUrlSavedWithThumbDic;
isURlSavedWithThumbDic在category方法中初始化,然后再对其设置任何值

if (isUrlSavedWithThumbDic == NULL || isUrlSavedWithThumbDic == nil){
     isUrlSavedWithThumbDic = [NSMutableDictionary new];
}
崩溃不会每次都发生,应用程序运行基本上没有问题。在类别中声明静态变量是否存在逻辑问题

UIImageView类别方法的完整源代码:

-(void)SetThumbImageForDownloadURL:(NSString*)url  indexPath:(NSIndexPath*)indexPath  waterMarkData:(CLWaterMarkModel*)watermarkData genericUrl:(NSString*)genericUrl placeHolder:(NSString*)placeHolder WillHaveWaterMark:(BOOL)willHaveWaterMark{


    __weak __typeof__(self) weakSelf = self;
    [self setImage:nil];
    if([url isEqualToString:@""]  || ![url caseInsensitiveCompare:@"unknown"] ) {
        [self  setImage:[UIImage imageNamed:placeHolder]];
    }
    else
    {
        NSData *imageData = [CMCache getThumbImageForKey:[url MD5] withPath:CacheDir];
        if(imageData)
        {
             UIImage *image = [UIImage imageWithData:imageData];
            if(!willHaveWaterMark){
                //my projects
                 [self  setImage:image];
            }else{
                if(watermarkData == nil){
                    //don't show image if watermark data is not there. Every thumb Image should have watermark data
                   // [self  setImage:image];

                }else{
                    if (isUrlSavedWithThumbDic == NULL || isUrlSavedWithThumbDic == nil){
                        isUrlSavedWithThumbDic = [NSMutableDictionary new];
                    }@try {
                        BOOL isSavedWithThumb = [[isUrlSavedWithThumbDic objectForKey:url] boolValue];
                        if( isSavedWithThumb){
                            [self  setImage:image];
                        }else{
                            //save image with thumb this time
                            image = [UIImage renderWaterMarkImage:image withModel:watermarkData generic:genericUrl];
                            [self  setImage:image];
                            [CMCache saveThumbnailImageAndCompressIfRequired:UIImagePNGRepresentation(image) forKey:[url MD5] withNewPath:CacheDir size:self.frame.size] ;

                            [isUrlSavedWithThumbDic setObject:[NSNumber numberWithBool:YES] forKey:url];

                        }

                    } @catch (NSException *exception) {
                        DLog(@"Exception:%@",exception);

                    }
                }
            }


        }
        else
        {

            if(downloadInProgress == nil){
                downloadInProgress = [NSMutableDictionary new];
                isUrlSavedWithThumbDic = [NSMutableDictionary new];
            }

            if (downloadInProgress[url] == nil ){
                downloadInProgress[url] = url;

                [CMRestInterface asyncImageDownload:url withProgressHandler:nil andCompletionHandler:^(UIImage *image, NSUInteger errorCode)
                 {
                     [downloadInProgress removeObjectForKey:url];

                     __typeof__(self) strongSelf = weakSelf;
                     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{

                         if (image)
                         {
                             @try {
                             //
                                 UIImage *customImage = image;
                                 if(watermarkData != nil){
                                     customImage = [UIImage renderWaterMarkImage:image withModel:watermarkData generic:genericUrl];

                                     [isUrlSavedWithThumbDic setObject:[NSNumber numberWithBool:YES] forKey:url];

                                 } else {
                                     [isUrlSavedWithThumbDic setObject:[NSNumber numberWithBool:NO] forKey:url];
                                 }
                                 [CMCache saveThumbnailImageAndCompressIfRequired:UIImagePNGRepresentation(customImage) forKey:[url MD5] withNewPath:CacheDir size:self.frame.size] ;
                                 dispatch_async(dispatch_get_main_queue(), ^{

                                UIView *parentView = strongSelf.superview;
                                while(parentView != nil && ![parentView isKindOfClass:NSClassFromString(@"UICollectionView")]
                                      && ![parentView isKindOfClass:NSClassFromString(@"UITableView")]){

                                    parentView = parentView.superview;

                                }
                                //ImageViewInsideTAbleViewCell
                                if(parentView == nil){
                                    if(willHaveWaterMark){
                                        if(watermarkData){
                                            if(!customImage){
                                                [ strongSelf setImage:[UIImage imageNamed:placeHolder]];
                                            }else{
                                                [strongSelf setImage:customImage];
                                            }
                                        }else{
                                            //[ strongSelf setImage:[UIImage imageNamed:placeHolder]];
                                        }

                                    }else{
                                        if(!customImage){
                                            [ strongSelf setImage:[UIImage imageNamed:placeHolder]];
                                        }else{
                                            [strongSelf setImage:customImage];
                                        }
                                    }

                                } else if([parentView isKindOfClass:NSClassFromString(@"UICollectionView")]){
                                    UICollectionView *cv = (UICollectionView*)parentView;


                                    UICollectionViewCell *cell = [cv cellForItemAtIndexPath:indexPath];
                                    if(cell){
                                        if(willHaveWaterMark){
                                            if(watermarkData){
                                                if(!customImage){
                                                    [ strongSelf setImage:[UIImage imageNamed:placeHolder]];
                                                }else{
                                                    [strongSelf setImage:customImage];
                                                }
                                            }else{
                                                // [ strongSelf setImage:[UIImage imageNamed:placeHolder]];
                                            }

                                        }else{
                                            if(!customImage){
                                                [ strongSelf setImage:[UIImage imageNamed:placeHolder]];
                                            }else{
                                                [strongSelf setImage:customImage];
                                            }
                                        }

                                    }



                                } else if ([parentView isKindOfClass:NSClassFromString(@"UITableView")]){
                                    UITableView *tv  = (UITableView*)parentView;

                                    //  [tv reloadRowsAtIndexPaths:[tv indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationNone];
                                    UITableViewCell *cell = [tv cellForRowAtIndexPath:indexPath];
                                    if(cell){
                                        if(willHaveWaterMark){
                                            if(watermarkData){
                                                if(!customImage){
                                                    [ strongSelf setImage:[UIImage imageNamed:placeHolder]];
                                                }else{
                                                    [strongSelf setImage:customImage];
                                                }
                                            }else{
                                                //  [ strongSelf setImage:[UIImage imageNamed:placeHolder]];
                                            }

                                        }else{
                                            if(!customImage){
                                                [ strongSelf setImage:[UIImage imageNamed:placeHolder]];
                                            }else{
                                                [strongSelf setImage:customImage];
                                            }
                                        }

                                    }

                                }


                            });
                            }@catch (NSException *exception) {
                                 DLog(@"Exception:%@",exception);
                             }

                         }else{
                             dispatch_async(dispatch_get_main_queue(), ^{
                                [strongSelf setImage:[UIImage imageNamed:placeHolder]];
                             });

                         }

                    });


                }];

            }

        }

    }



}

我终于找到了坠机的原因。这是一个并发问题。多个线程并行运行,其中每个线程都试图下载一个映像,下载成功后,它正在更新一个可变字典。当两个单独的线程试图同时在字典中写入时,应用程序将崩溃,因为代码不是线程安全的。一个快速修复方法是移动串行队列中的共享资源,以便所有线程一次写入一个字典。

我认为您应该遵循EXC_BAD_访问(code=1,address=0x0),这通常指的是nil/NULL,我可以在图像中看到“po”调用,因此,您可能需要搜索一些NSzombie。这个错误是因为在您可以使用它之前,iUrlSavedWithThumbdic已被解除分配。