Ios 为什么NSMutableDictionary的setObjectForKey方法会导致崩溃?
在NSMutableDictionary对象上调用setObjectForKey方法时,应用程序崩溃。iUrlSavedWithThumbDic和url字符串的值如控制台中所示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
[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已被解除分配。