Ios 将映像异步下载到NSData和缓存

Ios 将映像异步下载到NSData和缓存,ios,objective-c,nsdata,grand-central-dispatch,Ios,Objective C,Nsdata,Grand Central Dispatch,首先,这不是一个重复的问题。我已经阅读了许多关于堆栈溢出的问题,但它们并没有帮助我完全解决问题 我正在从web服务下载图像。因为没有人喜欢UI被暂停,所以我使用线程分别下载图像 NSURL *imageUrl = [NSURL URLWithString:storyImageURL]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ thumbnailData = [NS

首先,这不是一个重复的问题。我已经阅读了许多关于堆栈溢出的问题,但它们并没有帮助我完全解决问题

我正在从web服务下载图像。因为没有人喜欢UI被暂停,所以我使用线程分别下载图像

NSURL *imageUrl = [NSURL URLWithString:storyImageURL];

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    thumbnailData = [NSData dataWithContentsOfURL:imageUrl];

    dispatch_async(dispatch_get_main_queue(), ^{
        thumbnail = [UIImage imageWithData:thumbnailData];
    });
});
如果我完全按照上面的方式使用代码,UI将不会停止,直到它从web服务获取数据,但是图像不会被缓存

如果我不使用线程,那么UI将暂停,但是使用NSCoding方法(归档)缓存图像

我的问题是:如何使用线程并同时缓存缩略图?请不要建议任何第三方图书馆

更新:反复阅读代码后,我可能会想到两个问题:

1) 看起来在线程下载完图像之前调用了NSKeyedArchiver和NSKeyedUnarchiver,但这只是一个猜测。在单独的存储文件中,我使用NSKeyedArchiver和NSKeyedUnachiver:

- (RSSChannel *)fetchRSSFeedWithCompletion:(void (^)(RSSChannel *, NSError *))block
{
    NSURL *url = [NSURL URLWithString:@"http://techcrunch.com/feed"];
    NSURLRequest *req = [NSURLRequest requestWithURL:url];

    RSSChannel *channel = [[RSSChannel alloc] init];
    TheConnection *connection = [[TheConnection alloc] initWithRequest:req];

    //[connection setCompletionBlock:block];

    NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    cachePath = [cachePath stringByAppendingPathComponent:@"HAHAHA.archive"];

    RSSChannel *cachedChannel = [NSKeyedUnarchiver unarchiveObjectWithFile:cachePath];

    if (!cachedChannel) 
        cachedChannel = [[RSSChannel alloc] init];

    RSSChannel *channelCopy = [cachedChannel copy];

    [connection setCompletionBlock:^(RSSChannel *obj, NSError *err) {
        if (!err) {

            [channelCopy addItemsFromChannel:obj];
            [NSKeyedArchiver archiveRootObject:channelCopy toFile:cachePath];
        }
        block(channelCopy, err);
    }];


    [connection setXmlRootObject:channel];
    [connection start];

    return cachedChannel;
}

2) 我能想到的第二个问题是,在尝试从缓存中解码缩略图后,UI没有刷新。

是否将
thumbnailData
保存为实例变量?在分派之前,请检查实例变量是否已设置,如果已设置,请返回该值。如果没有,则运行分派块并将其另存为实例变量。

假设您的目标是iOS 5+,最自然的解决方案是使用
NSURLCache
NSURLConnection+sendAsynchronousRequest:queue:completionHandler:
。第三方解决方案通常只是忽略这些方法,要么是出于无知,要么是出于支持iOS 4的愿望,所以您的选择要么是将这些东西的维护工作有效地外包给苹果,要么是信任第三方,要么是花自己的时间在上面

例如

NSURLCache
在iOS 5之前存在,但只是一个内存缓存。因为它也是一个磁盘缓存。

试试这个

    NSURL *imageUrl = [NSURL URLWithString:storyImageURL];

    UIButton *btnThumbnail = [[UIButton alloc] initWithFrame:CGRectMake(0, 10, 180, 280)];
    [self downloadingServerImageFromUrl:btnThumbnail AndUrl:imageUrl];
    [btnThumbnail addTarget:self action:@selector(onSelectEPaper:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:viewPaperBg];

 - (void)onSelectEPaper:(id)sender
  {
  }


  -(void)downloadingServerImageFromUrl:(UIButton*)imgView AndUrl:(NSString*)strUrl
{
//    strUrl = [strUrl encodeUrl];
//    strUrl = [strUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

NSString* theFileName = [NSString stringWithFormat:@"%@.jpg",[[strUrl lastPathComponent] stringByDeletingPathExtension]];


NSFileManager *fileManager =[NSFileManager defaultManager];
NSString *fileName = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"tmp/%@",theFileName]];


imgView.backgroundColor = [UIColor darkGrayColor];
UIActivityIndicatorView *actView = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[imgView addSubview:actView];
[actView startAnimating];
CGSize boundsSize = imgView.bounds.size;
CGRect frameToCenter = actView.frame;
// center horizontally
if (frameToCenter.size.width < boundsSize.width)
    frameToCenter.origin.x = (boundsSize.width - frameToCenter.size.width) / 2;
else
    frameToCenter.origin.x = 0;

// center vertically
if (frameToCenter.size.height < boundsSize.height)
    frameToCenter.origin.y = (boundsSize.height - frameToCenter.size.height) / 2;
else
    frameToCenter.origin.y = 0;

actView.frame = frameToCenter;


dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{

    NSData *dataFromFile = nil;
    NSData *dataFromUrl = nil;

    dataFromFile = [fileManager contentsAtPath:fileName];
    //      NSLog(@"%@",fileName);
    if(dataFromFile==nil){
        //      NSLog(@"%@",strUrl);
        NSString *url =[strUrl stringByReplacingOccurrencesOfString:@"\n" withString:@""];
        url=[url stringByReplacingOccurrencesOfString:@"\t" withString:@""];
        url=[url stringByReplacingOccurrencesOfString:@" " withString:@""];

        url = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        //       dataFromUrl=[[[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]] autorelease];
        //       dataFromUrl=[[NSData dataWithContentsOfURL:[NSURL URLWithString:url]] autorelease];
        NSError* error = nil;
        //     NSLog(@"%@", [NSURL URLWithString:url]);
        dataFromUrl = [NSData dataWithContentsOfURL:[NSURL URLWithString:url] options:NSDataReadingUncached error:&error];

        if (error) {
            NSLog(@"%@", [error localizedDescription]);
        } else {
            //    NSLog(@"Data has loaded successfully.");
        }
    }

    dispatch_sync(dispatch_get_main_queue(), ^{

        if(dataFromFile!=nil){
            //    imgView.image = [UIImage imageWithData:dataFromFile];
            [imgView setBackgroundImage:[UIImage imageWithData:dataFromFile] forState:UIControlStateNormal];
        }else if(dataFromUrl!=nil){
            //    imgView.image = [UIImage imageWithData:dataFromUrl];
            [imgView setBackgroundImage:[UIImage imageWithData:dataFromUrl] forState:UIControlStateNormal];
            NSString *fileName = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"tmp/%@",theFileName]];

            BOOL filecreationSuccess = [fileManager createFileAtPath:fileName contents:dataFromUrl attributes:nil];
            if(filecreationSuccess == NO){
                //    NSLog(@"Failed to create the html file");
            }

        }else{
            //     imgView.image = [UIImage imageNamed:@"no_image.jpg"];
            [imgView setBackgroundImage:[UIImage imageNamed:@"no_image.jpg"] forState:UIControlStateNormal];
        }
        [actView removeFromSuperview];
        //            [actView release];
        //    [imgView setBackgroundColor:[UIColor clearColor]];
    });
});
}
NSURL*imageUrl=[NSURL-URLWithString:storyImageURL];
UIButton*btnThumbnail=[[UIButton alloc]initWithFrame:CGRectMake(0,10,180,280)];
[自下载ServerImageFromURL:BTN缩略图和URL:imageUrl];
[btnThumbnail addTarget:self action:@selector(onselectepper:)for controlEvents:UIControlEventTouchUpInside];
[self.view addSubview:viewPaperBg];
-(无效)onSelectEPaper:(id)发件人
{
}
-(void)下载ServerImagefromURL:(UIButton*)imgView和URL:(NSString*)strUrl
{
//strUrl=[strUrl encodeUrl];
//strUrl=[strUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString*文件名=[NSString stringWithFormat:@“%@.jpg”,[[strUrl lastPathComponent]stringByDeletingPathExtension];
NSFileManager*fileManager=[NSFileManager defaultManager];
NSString*文件名=[NSHomeDirectory()stringByAppendingPathComponent:[NSString stringWithFormat:@“tmp/%@”,文件名]];
imgView.backgroundColor=[UIColor darkGrayColor];
UIActivityIndicatorView*actView=[[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[imgView添加子视图:actView];
[actView startAnimating];
CGSize boundsSize=imgView.bounds.size;
CGRect frameToCenter=actView.frame;
//水平居中
if(frameToCenter.size.width    NSURL *imageUrl = [NSURL URLWithString:storyImageURL];

    UIButton *btnThumbnail = [[UIButton alloc] initWithFrame:CGRectMake(0, 10, 180, 280)];
    [self downloadingServerImageFromUrl:btnThumbnail AndUrl:imageUrl];
    [btnThumbnail addTarget:self action:@selector(onSelectEPaper:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:viewPaperBg];

 - (void)onSelectEPaper:(id)sender
  {
  }


  -(void)downloadingServerImageFromUrl:(UIButton*)imgView AndUrl:(NSString*)strUrl
{
//    strUrl = [strUrl encodeUrl];
//    strUrl = [strUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

NSString* theFileName = [NSString stringWithFormat:@"%@.jpg",[[strUrl lastPathComponent] stringByDeletingPathExtension]];


NSFileManager *fileManager =[NSFileManager defaultManager];
NSString *fileName = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"tmp/%@",theFileName]];


imgView.backgroundColor = [UIColor darkGrayColor];
UIActivityIndicatorView *actView = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[imgView addSubview:actView];
[actView startAnimating];
CGSize boundsSize = imgView.bounds.size;
CGRect frameToCenter = actView.frame;
// center horizontally
if (frameToCenter.size.width < boundsSize.width)
    frameToCenter.origin.x = (boundsSize.width - frameToCenter.size.width) / 2;
else
    frameToCenter.origin.x = 0;

// center vertically
if (frameToCenter.size.height < boundsSize.height)
    frameToCenter.origin.y = (boundsSize.height - frameToCenter.size.height) / 2;
else
    frameToCenter.origin.y = 0;

actView.frame = frameToCenter;


dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{

    NSData *dataFromFile = nil;
    NSData *dataFromUrl = nil;

    dataFromFile = [fileManager contentsAtPath:fileName];
    //      NSLog(@"%@",fileName);
    if(dataFromFile==nil){
        //      NSLog(@"%@",strUrl);
        NSString *url =[strUrl stringByReplacingOccurrencesOfString:@"\n" withString:@""];
        url=[url stringByReplacingOccurrencesOfString:@"\t" withString:@""];
        url=[url stringByReplacingOccurrencesOfString:@" " withString:@""];

        url = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        //       dataFromUrl=[[[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]] autorelease];
        //       dataFromUrl=[[NSData dataWithContentsOfURL:[NSURL URLWithString:url]] autorelease];
        NSError* error = nil;
        //     NSLog(@"%@", [NSURL URLWithString:url]);
        dataFromUrl = [NSData dataWithContentsOfURL:[NSURL URLWithString:url] options:NSDataReadingUncached error:&error];

        if (error) {
            NSLog(@"%@", [error localizedDescription]);
        } else {
            //    NSLog(@"Data has loaded successfully.");
        }
    }

    dispatch_sync(dispatch_get_main_queue(), ^{

        if(dataFromFile!=nil){
            //    imgView.image = [UIImage imageWithData:dataFromFile];
            [imgView setBackgroundImage:[UIImage imageWithData:dataFromFile] forState:UIControlStateNormal];
        }else if(dataFromUrl!=nil){
            //    imgView.image = [UIImage imageWithData:dataFromUrl];
            [imgView setBackgroundImage:[UIImage imageWithData:dataFromUrl] forState:UIControlStateNormal];
            NSString *fileName = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"tmp/%@",theFileName]];

            BOOL filecreationSuccess = [fileManager createFileAtPath:fileName contents:dataFromUrl attributes:nil];
            if(filecreationSuccess == NO){
                //    NSLog(@"Failed to create the html file");
            }

        }else{
            //     imgView.image = [UIImage imageNamed:@"no_image.jpg"];
            [imgView setBackgroundImage:[UIImage imageNamed:@"no_image.jpg"] forState:UIControlStateNormal];
        }
        [actView removeFromSuperview];
        //            [actView release];
        //    [imgView setBackgroundColor:[UIColor clearColor]];
    });
});
}
RSSChannel *channelCopy = [cachedChannel copy];

INCREMENT_COUNTER
    [channelCopy addItemsFromChannel:obj];
    DECREMENT_COUNTER;
 }
block(channelCopy, err);
}];
NSURL *imageUrl = [NSURL URLWithString:storyImageURL];

INCREMENT_COUNTER;

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

thumbnailData = [NSData dataWithContentsOfURL:imageUrl];

dispatch_async(dispatch_get_main_queue(), ^{
  thumbnail = [UIImage imageWithData:thumbnailData];
  DECREMENT_COUNTER;
  if (COUNTER_REACHED_ZERO)
    CALL_ARCHIVE_METHOD_ON_CHANNEL OBJECT
  });
});