下载后立即显示图片?

时间:2015-11-30 22:28:56

标签: objective-c image asynchronous

我正在优化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对象的原始数组永远不会真正更新图像。

我怎样才能做到这一点?主界面在另一个文件中。

如果需要,我可以发布更多代码。 (对不起西班牙语)

3 个答案:

答案 0 :(得分:1)

我正在使用SDWebimage库异步下载图像。这个库也会缓存你的图像,它对图像非常有用。

https://github.com/rs/SDWebImage

我希望这会对你有所帮助。如果你想要一些代码,请告诉我。

答案 1 :(得分:0)

问题是您有一个for循环,您可以在其中创建下载操作,然后立即(在完成下载操作之前)迭代更新映像的消息。

如果您要将图像存储在Noticia对象中,我建议您在所创建的操作中执行此操作,以便每次下载完成时,相应的{{1对象已更新。确保将该模型对象的更新分发回主队列(从操作中)以避免同步问题。如果您还希望在下载完成后将其反映在UI中,您也可以在操作中触发主队列中的那个。

话虽如此,我同意nigelman和Ekta你不应该这样做,而是使用异步图像检索机制,例如AFNetworkingSDWebImage&#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];
    });
});

这是我的应用程序中的代码..

  1. 创建框架到图像
  2. show loader
  3. 下载图片async
  4. 删除装载程序,显示图像