我正在优化iOS应用的下载和展示流程。在这个应用程序中,我有一个Noticia对象,其中包含一个图像URL地址(存储为字符串)和一个带有实际图像的UIImage对象。
现在一切都是同步完成的,它为每个下载的图像打开一个连接,如下所示:
NSURL *imageURL = [NSURL URLWithString:noti.urlImagen];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
因此,当有很多新闻需要下载时,下载需要花费大量时间,而且应用程序完全没有响应。
所以我现在正在改变它,我现在可以使用this question中的代码异步下载所有图像,但现在我需要在新闻列表中下载后立即显示它们。我怎么能这样做?。
the noticia对象 Noticia.h
#import <UIKit/UIKit.h>
@interface Noticia : NSObject
@property (nonatomic) int identificacion;
@property (nonatomic, strong) NSString *titulo;
@property (nonatomic, strong) NSString *descripcion;
@property (nonatomic, strong) NSString *fecha;
@property (nonatomic, strong) NSString *urlImagen;
@property (nonatomic, strong) NSString *urlNoticia;
@property (nonatomic, strong) NSString *categoria;
@property (nonatomic, strong) NSString *fuente;
@property (nonatomic, strong) NSString *contenido;
@property (nonatomic) int tipo;
@property (nonatomic) UIImage *imagen;
-(id)initWithTitulo:(NSString *)ti descripcion:(NSString *)de fecha:(NSString *)fe urlImagen:(NSString *)uri urlNoticia:(NSString *)urn categoria:(NSString *)ca fuente:(NSString *)fu contenido:(NSString *)co tipo:(int)tip;
@end
Noticia.m
#import "Noticia.h"
@implementation Noticia
@synthesize titulo, descripcion, urlImagen, urlNoticia, categoria, fuente, contenido, tipo, fecha;
-(id)initWithTitulo:(NSString *)ti descripcion:(NSString *)de fecha:(NSString *)fe urlImagen:(NSString *)uri urlNoticia:(NSString *)urn categoria:(NSString *)ca fuente:(NSString *)fu contenido:(NSString *)co tipo:(int)tip{
if(self = [super init]){
self.titulo = ti;
self.descripcion = de;
self.fecha = fe;
self.urlImagen = uri;
self.urlNoticia = urn;
self.categoria = ca;
self.fuente = fu;
self.contenido = co;
self.tipo = tip;
}
return self;
}
-(NSString *)description{
return [NSString stringWithFormat:@"Noticia:\nTitulo:%@\nDescripcion:%@\nFecha:%@\nurlImagen:%@\nurlNoticia:%@\nCategoria:%@\nFuente:%@\nContenido:%@\nTipo:%i",titulo, descripcion, fecha, urlImagen, urlNoticia, categoria, fuente, contenido, tipo];
}
@end
如何下载Noticia(异步方式)
-(NSMutableArray *)traerNoticias{
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:kEndPointNews]];
if (data != NULL) {
NSError* error;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
NSMutableArray *arregloNoticias = [[NSMutableArray alloc]init];
for (NSDictionary *noticia in json) {
NSDictionary *noticiaInfo = [noticia objectForKey:@"noticia"];
Noticia *noti = [[Noticia alloc]initWithTitulo:[noticiaInfo objectForKey:@"titulo"] descripcion:[noticiaInfo objectForKey:@"descripcion"] fecha:[noticiaInfo objectForKey:@"fecha"] urlImagen:[noticiaInfo objectForKey:@"urlImagen"] urlNoticia:[noticiaInfo objectForKey:@"urlNoticia"] categoria:@"a" fuente:@"a" contenido:[noticiaInfo objectForKey:@"contenido"] tipo:[[noticiaInfo objectForKey:@"destacada"]intValue]];
noti.identificacion = [[noticiaInfo objectForKey:@"id"]intValue];
NSLog(@"%@", noti);
//NSURL *imageURL = [NSURL URLWithString:noti.urlImagen];
//NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
NSData *imageData = nil;
noti.imagen = [UIImage imageWithData:imageData];
[arregloNoticias addObject:noti];
}
arregloNoticias = [self cargarImagenesAsincrono:arregloNoticias];
return arregloNoticias;
}else{
return nil;
}
}
-(NSMutableArray *)cargarImagenesAsincrono:(NSMutableArray *)arregloNoticias
{
NSMutableArray *urlsNoticias = [[NSMutableArray alloc]init];
for (Noticia *Noticias in arregloNoticias) {
NSURL *url = [NSURL URLWithString:Noticias.urlImagen];
[urlsNoticias addObject:url];
}
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 7;
NSMutableArray *imagenes = [[NSMutableArray alloc]init];
for (NSURL* url in urlsNoticias)
{
[queue addOperationWithBlock:^{
NSData *data = [NSData dataWithContentsOfURL:url];
[imagenes addObject:data];
}];
}
int i=0;
for (NSData *imageData in imagenes) {
Noticia *noti=[arregloNoticias objectAtIndex:i];
noti.imagen=[UIImage imageWithData:imageData];
[arregloNoticias replaceObjectAtIndex:i withObject:noti];
i++;
}
return arregloNoticias;
}
主界面需要在Noticia对象中准备好一个UImage对象才能显示它。我也看到cargarImagenesAsincrono中的最后一个声明从未发生过,因此带有Noticia对象的原始数组永远不会真正更新图像。
我怎样才能做到这一点?主界面在另一个文件中。
如果需要,我可以发布更多代码。 (对不起西班牙语)
答案 0 :(得分:1)
我正在使用SDWebimage库异步下载图像。这个库也会缓存你的图像,它对图像非常有用。
https://github.com/rs/SDWebImage
我希望这会对你有所帮助。如果你想要一些代码,请告诉我。
答案 1 :(得分:0)
问题是您有一个for
循环,您可以在其中创建下载操作,然后立即(在完成下载操作之前)迭代更新映像的消息。
如果您要将图像存储在Noticia
对象中,我建议您在所创建的操作中执行此操作,以便每次下载完成时,相应的{{1对象已更新。确保将该模型对象的更新分发回主队列(从操作中)以避免同步问题。如果您还希望在下载完成后将其反映在UI中,您也可以在操作中触发主队列中的那个。
话虽如此,我同意nigelman和Ekta你不应该这样做,而是使用异步图像检索机制,例如AFNetworking或SDWebImage&#39; s Noticia
类别,UIImageView
实际上只应包含图片的网址。最好不仅异步检索图像,而且还使用漂亮的可取消机制懒惰地使用缓存等,例如由这两个(以及其他)类别提供的。
答案 2 :(得分:0)
你可以像这样下载async:
UIView *imgv = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
imgv.backgroundColor = [UIColor colorWithRed:198.0f/255.0f green:198.0f/255.0f blue:198.0f/255.0f alpha:1.0f];
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[imgv addSubview:activityIndicator];
activityIndicator.center = CGPointMake(imgv.frame.size.width / 2, imgv.frame.size.height / 2);
[activityIndicator startAnimating];
UIImageView *img = [[UIImageView alloc] initWithFrame:CGRectMake(5, 5, imgv.frame.size.width-10, imgv.frame.size.height - 10)];
img.clipsToBounds = YES;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSString *imgurl = URL_TO_IMAGE;
NSData * imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[imgurl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *image = [UIImage imageWithData:imageData];
img.image = image;
[imgv addSubview:img];
imgv.userInteractionEnabled = YES;
[activityIndicator removeFromSuperview];
});
});
这是我的应用程序中的代码..