2015-11-30 2 views
1

Я оптимизирую процесс загрузки и показа приложения для iOS. В этом приложении у меня есть объект Noticia, который содержит, среди прочего, URL-адрес изображения (хранится как строка) и объект UIImage с фактическим изображением.Показать изображения как только они будут загружены?

Сейчас все делается синхронным, и это открывает соединение для каждого изображения, которое он загружает так:

NSURL *imageURL = [NSURL URLWithString:noti.urlImagen]; 
NSData *imageData = [NSData dataWithContentsOfURL:imageURL]; 

Итак, когда есть много новостей для загрузки, это занимает много времени для загрузки, и приложение абсолютно не отвечает, пока это происходит.

Поэтому я меняю его прямо сейчас, теперь я могу асинхронно загружать все изображения с кодом, найденным в this question, но теперь мне нужно показать их, как только они загрузятся в список новостей. Как я могу это сделать?

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; 
} 

Основной интерфейс рассчитывает уже есть объект UImage, готовый в объекте Noticia для его отображения. Я также видел, что последнее утверждение для cargarImagenesAsincrono никогда не происходит, поэтому исходный массив с объектами Noticia никогда не обновляется с изображениями.

Как я могу это достичь? Основной интерфейс находится в другом файле.

Я могу разместить больше кода, если вам это нужно. (извините за испанский)

+0

Привет compañero. Чтобы загрузить и показать изображения асинхронно, я использую AFNetworking. Конкретно AFNetworking/UIImageView + AFNetworking.h: https://github.com/AFNetworking/AFNetworking/blob/master/UIKit%2BAFNetworking/UIImageView%2BAFNetworking.h – nigelman

ответ

0

Проблема заключается в том, что у вас есть цикл for, в котором вы создаете операции загрузки, а затем сразу же (до того, как эти операции по загрузке выполняются) итерации через нотификаторы, обновляющие изображение.

Если вы собираетесь сохранить изображение в объекте Noticia, я предлагаю вам сделать это в созданных вами операциях, чтобы каждая загрузка заканчивалась, обновляется соответствующий объект Noticia. Обязательно отправьте это обновление этого объекта модели обратно в основную очередь (изнутри операции), чтобы избежать проблем с синхронизацией. И если вы также хотите, чтобы это отразилось в пользовательском интерфейсе по завершении загрузки, вы также можете запустить это в главной очереди изнутри операции.


Сказав это, я согласен с nigelman и Экта, что вы не должны делать это, и скорее с использованием асинхронного механизма поиска изображений, таких как AFNetworking или SDWebImage «s UIImageView категории, и что Noticia должны действительно только укажите URL-адрес изображения.Лучше получать изображения не только асинхронно, но и лениво использовать хороший механизм отмены и использовать кеширование и т. П., Например, предоставляемые этими двумя (среди прочих) категориями.

+0

Закончен с использованием SDWebImage, он идеально подходит – HaPK

1

Я использую библиотеку SDWebimage для загрузки изображения асинхронно. Эта библиотека также будет кэшировать изображения ур и очень полезна для изображений.

https://github.com/rs/SDWebImage

Я надеюсь, что это поможет. Если вам нужен какой-то код, то дайте мне знать.

+0

Спасибо, что связались с библиотекой, в конечном итоге использовали его, так как он идеально подходит с тем, как работает интерфейс – HaPK

0

вы можете скачать асинхронной так:

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. показать погрузчик
  3. загрузить изображение асинхронной
  4. удалить погрузчик, показать изображение
Смежные вопросы