在NSMutableDictionary对象上调用setObjectForKey方法时应用程序崩溃。 isUrlSavedWithThumbDic和url字符串具有在控制台中显示的值。
[isUrlSavedWithThumbDic setObject:[NSNumber numberWithBool:YES] forKey:url];
代码在UIImageView类别中运行。 isURLSavedWithThumbDic是类别中的静态变量,声明为:
static NSMutableDictionary *isUrlSavedWithThumbDic;
isURlSavedWithThumbDic在类别方法中初始化,然后在其上设置任何值。
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]];
});
}
});
}];
}
}
}
}
答案 0 :(得分:0)
我能够找出崩溃背后的原因。问题是并发问题。多个线程并行运行,每个线程都试图下载图像,下载成功后,它正在更新可变字典。当两个单独的线程试图在字典中同时写入时,应用程序崩溃,因为代码不是线程安全的。快速解决方法是在串行队列中移动共享资源,以便所有线程一次写入一个字典。