图像持久性和延迟加载与Dispatch_Async的冲突

我正在一个饲料阅读器,我通过使用nsxmlparserparsingRSS源。 我也有从CDATA块取得的缩略图对象。

-(void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSString *someString = [[NSString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding]; NSString *storyImageURL = [self getFirstImageUrl:someString]; NSURL *tempURL = [NSURL URLWithString:storyImageURL]; NSData *tempData = [NSData dataWithContentsOfURL:tempURL]; thumbnail = [UIImage imageWithData:tempData]; }); } 

我坚持使用归档和编码和解码方法的图像和其他tableview对象。

问题是,当我使用上面的代码,它不会保留图像,而像标题和发布date等其他tableview对象仍然存在。 但是,当我使用上面的代码没有dispatch_async周围,然后开始持久化图像,但locking用户界面。

如何在不locking用户界面的情况下坚持图像?

请不要回答一些库来存储和caching图片或苹果的懒加载示例。 谢谢

更新:

根据所提供的答案和斯坦福大学在iTunes上观看multithreading讲座后,我已经实现了以上代码:

  NSString *someString = [[NSString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding]; NSString *storyImageURL = [self getFirstImageUrl:someString]; NSURL *tempURL = [NSURL URLWithString:storyImageURL]; dispatch_queue_t downloadQueue = dispatch_queue_create("image downloader", NULL); dispatch_async(downloadQueue, ^{ NSData *tempData = [NSData dataWithContentsOfURL:tempURL]; dispatch_async(dispatch_get_main_queue(), ^{ thumbnail = [UIImage imageWithData:tempData]; }); }); } 

从逻辑上讲,现在一切正确,但仍然无法正常工作。 我都被封锁了如何解决这个问题。

更新:

我正在使用模型视图控制器存储方法,我的存储和连接代码是在单独的文件中定义的。 下面是我使用NSKeyedArchiver的代码。

 - (FeedChannel *) FeedFetcherWithCompletion:(void (^)(FeedChannel *, NSError *))block { NSURL *url = [NSURL URLWithString:@"http://techcrunch.com/feed/"]; NSURLRequest *req = [NSURLRequest requestWithURL:url]; FeedChannel *channel = [[FeedChannel alloc] init]; TheConnection *connection = [[TheConnection alloc] initWithRequest:req]; NSString *pathOfCache = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; pathOfCache = [pathOfCache stringByAppendingPathComponent:@"check.archive"]; FeedChannel *channelCache = [NSKeyedUnarchiver unarchiveObjectWithFile:pathOfCache]; if (!channelCachel) { channelCache = [[FeedChannel alloc] init]; } FeedChannel *channelCopy = [channelCache copy]; [connection setCompletionBlock:^(FeedChannel *obj, NSError *err) { if (!err) { [channelCopy addItemsFromChannel:obj]; [NSKeyedArchiver archiveRootObject:channelCopy toFile:pathOfCache]; } block(channelCopy, err); }]; [connection setXmlObject:channel]; [connection start]; return channelCache; } 

以下是我的编码和解码方法。

 - (void)encodeWithCoder:(NSCoder *)aCoder { [aCoder encodeObject:title forKey:@"title"]; [aCoder encodeObject:link forKey:@"link"]; [aCoder encodeObject:creator forKey:@"creator"]; [aCoder encodeObject:pubDate forKey:@"pubDate"]; [aCoder encodeObject:thumbnail forKey:@"thumbnail"]; //[aCoder encodeObject:UIImagePNGRepresentation(thumbnail) forKey:@"thumbnail"]; [aCoder encodeObject:publicationDate forKey:@"publicationDate"]; } - (id)initWithCoder:(NSCoder *)aDecoder { self = [super init]; if (self) { [self setTitle:[aDecoder decodeObjectForKey:@"title"]]; [self setLink:[aDecoder decodeObjectForKey:@"link"]]; [self setCreator:[aDecoder decodeObjectForKey:@"creator"]]; [self setPubDate:[aDecoder decodeObjectForKey:@"pubDate"]]; [self setThumbnail:[aDecoder decodeObjectForKey:@"thumbnail"]]; //[self setThumbnail:[UIImage imageWithData:[aDecoder decodeObjectForKey:@"thumbnail"]]]; [self setPublicationDate:[aDecoder decodeObjectForKey:@"publicationDate"]]; } return self; } 

基于这个答案,我不知道我是否需要使用一些额外的代码来保存图像。 因为像标题,创造者等其他对象正在坚持。

阅读你的评论后,我倾向于认为这个问题与你如何坚持dispatch_async块相关的图像。 我会尽力解释,但这只是一个猜测,因为我不知道你坚持这个形象在哪里:

  1. 在某个时候你的parser:foundCDATA:被执行,你asynchronous检索你的图像;

  2. 图像不会在那里一段时间(直到同步块完成),所以在完成parser:foundCDATA:之后, thumbnail ivar /属性在一段时间内将不具有正确的值parser:foundCDATA:

  3. 现在,如果在asynchronous块完成之前坚持thumbnail ,则会持续错误的(nil?)值;

  4. 事实上,如果你不执行asynchronous获取的图像,那么一切正常,使我认为你太早坚持图像(在上述意义上)。

只有在asynchronous块完成之后,才能修复此问题。 这可能意味着像这样:

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSString *someString = [[NSString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding]; NSString *storyImageURL = [self getFirstImageUrl:someString]; NSURL *tempURL = [NSURL URLWithString:storyImageURL]; NSData *tempData = [NSData dataWithContentsOfURL:tempURL]; thumbnail = [UIImage imageWithData:tempData]; <code here to make the thumbnail be persisted> }); 

<code here to make the thumbnail be persisted>可能是一个方法调用,通知post,无论适合您当前的devise。 如果您的持久性代码不是线程安全的,您可能还需要使用将调用分派给主线程的技巧:

  dispatch_async(dispatch_get_main_queue(), ^{ <persist thumbnail>; } 

希望能帮助到你。

编辑:

我们聊天后,上述分析得到确认。 事实上,你不是简单地下载一个图像:你正在下载一组图像,都属于同一个“通道”。 这意味着应用于整个频道的持续操作只有在所有这些图像被下载后才能执行。

因此,我已经分出了你的要点,并添加了一些逻辑,以便使用GCD dispatch_group来跟踪所有的下载操作。 你可以在这里find它。