Ios 映像持久性和延迟加载与Dispatch\u Async冲突
我正在开发一个提要阅读器,通过使用nsxmlparser解析rss提要来实现。我还有从CDATA块中获取的缩略图对象Ios 映像持久性和延迟加载与Dispatch\u Async冲突,ios,objective-c,uiimageview,grand-central-dispatch,Ios,Objective C,Uiimageview,Grand Central Dispatch,我正在开发一个提要阅读器,通过使用nsxmlparser解析rss提要来实现。我还有从CDATA块中获取的缩略图对象 -(void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSString *someString = [[NSStri
-(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对象
- (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;
}
问题是,当我按原样使用上述代码时,它不会持久化图像,而其他tableview对象(如标题和发布日期)会持久化。但是,当我使用上面的代码时,如果没有对其进行dispatch_async,那么它将开始持久化图像,但会锁定用户界面
如何在不锁定用户界面的情况下保存图像
请不要用一些用于存储和缓存图像的库或苹果的延迟加载示例来回答。谢谢
更新:
根据提供的答案,在观看了斯坦福大学在iTunes上关于多线程的演讲后,我实现了上述代码,如下所示:
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;
}
根据答案,我不知道是否需要使用一些额外的代码来保存图像。因为title、creator等其他对象能够准确地持久化。在阅读您的评论后,我倾向于认为问题与如何相对于dispatch\u async块持久化图像有关。我将尝试解释,但这只是一个猜测,因为我不知道您将图像保存在何处:
解析器:foundCDATA:
将被执行,您将异步检索图像缩略图
ivar/属性在完成解析器:foundCDATA:
后的一段时间内将没有正确的值缩略图
,则将保持错误的(nil?)值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>
});
dispatch\u async(dispatch\u get\u global\u queue(dispatch\u queue\u PRIORITY\u DEFAULT,0)^{
NSString*someString=[[NSString alloc]initWithData:CDATA块编码:NSUTF8StringEncoding];
NSString*storyImageURL=[self-getFirstImageUrl:someString];
NSURL*tempURL=[NSURL URLWithString:storyImageURL];
NSData*tempData=[NSData dataWithContentsOfURL:tempURL];
缩略图=[UIImage imageWithData:tempData];
});
可以是一个方法调用,一个通知帖子,任何适合您当前设计的东西。如果持久性代码不是线程安全的,您可能还需要使用将调用分派到主线程的技巧:
dispatch_async(dispatch_get_main_queue(), ^{
<persist thumbnail>;
}
dispatch\u async(dispatch\u get\u main\u queue()^{
;
}
希望能有帮助
编辑:
在我们的聊天之后,上述分析得到了证实。事实上,您并不是简单地下载一个图像:您正在下载一组图像,它们都属于同一个“频道”。这意味着应用于整个频道的持久化操作只有在下载完所有这些图像后才能执行
因此,我提出了你的要点,并添加了一些逻辑,使GCD dispatch_group能够跟踪所有下载操作。你可以找到它。@Jessica:花了一些时间才得到最终版本…希望它对你有用。我尝试了你的两种解决方案,但问题是相同的。当我使用dispatch_asyc或dispatch_sych时,我的法师停止持续。他们第一次加载时,但当我关闭并打开应用程序时,所有其他对象都在那里,但图像不在。你猜对了所有事情。一切都按照你的解释进行。我使用了你在更新答案中建议的使用主队列的代码,但仍然不起作用。你能猜出还有什么c可能是错的。谢谢,我需要知道你如何保存图像,尤其是在什么时候/在什么地方…你的代码只显示分配给道具/ivar的任务…实际上,在我的回答中,我建议在分配给道具/ivar后立即粘贴/调用代码来保存图像…我已经更新了问题中的代码。请检查一下。