Pregunta

Mis descargas de código de imágenes utilizando de forma asíncrona InternetImage en el método tableview: cellForRowAtIndexPath: inicializando una IntentImage con initWithURL y downloadImage llamando. Este código funciona perfectamente después de desplazarse a una nueva célula UITableViewCell en el UITableView, pero no antes, a pesar de que la URL es correcta en ambos casos. Ninguno de los métodos de delegado NSURLConnection de InternetImage están llamados a un mensaje si hay éxito o el fracaso de la conexión, como debe ser. Llamando reloadData:, setNeedsDisplay: y setNeedsLayout: hacer nada ya que la imagen no se descarga correctamente.

Este es el código de mi subclase de UITableViewController:

   - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        Object *object = (Object *)[self.array objectAtIndex:indexPath.row];

        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
        if (cell == nil) {
            cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"] autorelease];
        }

        cell.textLabel.text = object.attribute;

        if (object.image == nil && object != nil) {
            NSString *URLString = [[MyAppDelegate imageURLFromLink:(object.link) withExtension:@".jpg"]absoluteString];

            InternetImage *asynchImage = [[InternetImage alloc] initWithUrl:URLString object:object];
            [asynchImage downloadImage:self];
        }

        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

        if (object.image != nil && object.thumbnailImage == nil) {

            UIImage *image= (UIImage *) object.image;
            UIImage *thumbnail = [image _imageScaledToSize:CGSizeMake(75.0, 50.0) interpolationQuality:20];
            object.thumbnailImage = thumbnail;
        }
        cell.imageView.image = object.thumbnailImage;

        return cell;
    }
¿Fue útil?

Solución

Una solución que funcionó para mí es pasar la responsabilidad para la descarga de objetos, y moviendo la responsabilidad de manejar el refresco de la imagen a la misma celda de la tabla. Si el objeto es visible en la pantalla y tiene una celda de la tabla correspondiente, la imagen se actualizará de inmediato una vez que se haya descargado.

Este enfoque requeriría los siguientes cambios:

  • Mover la responsabilidad de descargar la imagen al objeto.
  • Modificar objeto de enviar un evento / llamar a un delegado / notificar que una propiedad ha cambiado cuando la imagen ha cambiado.
  • Subclase UITableViewCell a saber sobre el objeto que va a mostrar que se suma a sí mismo como un cambio delegado al objeto cuando se le asigna.

Aquí hay un bosquejo de cómo esto podría funcionar:

// in the UITableViewController
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  Object *object = (Object *)[self.array objectAtIndex:indexPath.row];

  ObjectTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"objectcell"];
  if (nil == cell) {
    cell = [[[ObjectTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"objectcell"] autorelease];
  }

  cell.object = object;

  return cell;
}

// in Object

- (void) downloadImageIfNeeded {
  if (nil == image && nil == internetImage) {
     NSString *URLString = [[MyAppDelegate imageURLFromLink:(object.link) withExtension:@".jpg"]absoluteString];

     internetImage = [[InternetImage alloc] initWithUrl:URLString object:object];
     [internetImage downloadImage:self];
  }
} 

- (void) internetImageReady:(InternetImage*)downloadedImage {
  self.image = downloadedImage.image;
  self.thumbnailImage = [image _imageScaledToSize:CGSizeMake(75.0, 50.0) interpolationQuality:20];

  // notify the delegate
  [imageDelegate imageChanged: self];
}

// in ObjectTableViewCell.h
@property (nonatomic, retain) Object *object;

// in ObjectTableViewCell.m
- (Object *) object {
  return object;
}

- (void) setObject: (Object *) obj {
  if (obj != object) {
    object.imageDelegate = nil;
    [object release];
    object = nil;

    if (nil != object) {
      object = [obj retain];
      object.imageDelegate = self;

      [object downloadImageIfNeeded];
      self.textLabel.text = object.attribute;
      self.imageView.image = object.thumbnailImage;

      self.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
   }
}

- (void) imageChanged: (Object *) o {
  self.imageView.image = object.thumbnailImage;
}

Otros consejos

Si se está preguntando por qué sus imágenes no se descargan en segundo plano una vez que se carga la tabla, es porque tableView:cellForRowAtIndexPath: Sólo se invoca con indexPaths de las células que aparecen en pantalla.

Si desea que todas sus imágenes para ser descargados a la vez en lugar de cuando un rollos de células en la pantalla, escribir un método que recorre su propiedad array y insantiates objetos InternetImage allí. Un lugar probable para esto podría ser en viewDidLoad.

A continuación, poner en práctica en su tableView:willDisplayCell:forRowAtIndexPath: delegado UITableView y que sea responsable de asignar el objeto InternetImage correcta a la propiedad imageView de cada célula.

De hecho, parece que NSUrlConnections no recuperan los datos, siempre y cuando la mesa se desplaza. Una vez que el desplazamiento se detiene, sigue al instante para recuperar los datos. Este comportamiento, sin embargo se puede ver en cualquier aplicación iPhone (las imágenes no se cargan siempre y cuando la mesa se desplaza) y, al final, me decidieron a vivir con eso en mi solicitud, también. Creo, Apple lo hizo a propósito. Tal vez para evitar que el dispositivo martillando el servidor con un montón de solicitudes de imágenes si el usuario se desplaza muy rápido; o tal vez incluso para mantener el desplazamiento suave para el usuario en cualquier momento.

Sería sin embargo bueno si lo haría, al menos, el trabajo mientras se desplaza lentamente y sólo descargan bloque mientras se desplaza rápidamente.

Bueno, antes que nada, lo que se ha publicado aquí no es lo que está utilizando, o ha realizado modificaciones en InternetImage usted no ha mencionado, ya que InternetImage no responde a initWithUrl: objeto :. Tampoco se ha incluido el código para el método internetImageReady delegado :. Yo entiendo que no está siendo llamada cuando algo va mal, pero se llama una vez que comience el desplazamiento, y teniendo el contrario de lo que sucede en el caso correcto ayudará a la gente a diagnosticar su problema.

Además, no está del todo claro a partir de la descripción de lo que sucede cuando se desplaza. Es evidente que las llamadas posteriores funcionan, pero todos los intentos de conexiones previamente repente comienzan a partir de ese punto, o están completamente perdidos?

En cuanto a lo que está pasando, así, por las razones expuestas, no creo que nadie puede hacer más que darle algunas conjeturas. Si tuviera que adivinar apuesta que si lo que dije en el último párrafo que está pasando entonces el problema es que (por cualquier razón) los hilos principales runloop no está procesando los eventos NSURLConnections hasta que algo ceba la bomba. Esto puede ser por varias razones, por ejemplo, el runloop estar en el modo incorrecto. Usted podría intentar ejecutar el NSRunLoop manualmente, o cambiar a InternetImage establecer explícitamente runloop, o manualmente de iniciar la descarga.

Dos apartes rápidos

  1. InternetImage parece hacer un montón de cosas que son idiomáticamente incompatibles con las convenciones de programación Cocoa general. Al menos para mí que hace que sea más difícil de leer con rapidez y no estoy del todo seguro de que está haciendo las cosas correctamente.
  2. No utilice _imageScaledToSize :. Esto es un método de Apple privado y si se dan cuenta de que está utilizando los mismos que puedan dar lugar a un rechazo.

No tengo una respuesta, pero te puedo decir que estoy viendo el mismo tipo de problema.

Estoy utilizando una versión ligeramente modificada del AsyncImageView clase de Mark Johnson . Las peticiones asincrónicas para las imágenes no causan ningún delegados a ser llamados, hasta que desplazarse por la tableview. Tan pronto como me desplazo una celda fuera de la vista y la espalda, los incendios llamar de nuevo y obtiene los datos correctamente.

He leído en otro lugar que NSURLConnection depende del bucle de ejecución para estar en un cierto modo - No sé si es que las cifras en una situación en la que una solicitud URLConnection se inició en tableView: cellForIndexPath.

¿Cómo uno va sobre la depuración de elementos internos NSURLConnection?

[ACTUALIZACIÓN]

Bueno, por lo que resolví mi caso particular de este problema iniciando la conexión en el hilo principal de forma explícita. Pongo el código de configuración de conexión en un selector diferente, y se invoca a que a través de performSelectorOnMainThread, y todo estaba bien otra vez.

Usted debe tratar de ingresar al modo de runloop actual en el selector que se inicia la conexión - descubrí que es no era el modo por defecto runloop, que necesita NSURLConnection

.

En realidad pasé algún tiempo buscando en el código.

En InternetImage me di cuenta de que existe esta función. Lo que vas a tener que hacer es conseguir esta función para informar a su TableView para "refrescar". Se podría hacer esto pasando una función delegada a su clase que se llamó más tarde, pero ahora las cosas se ponen difíciles reales. Porque cuando salga de la vista en la que tendrá que configurar la función de delegado a "cero" para cada imagen que está intentando descargar.

-(void) internetImageReady:(InternetImage*)downloadedImage
{   
    // The image has been downloaded. Put the image into the UIImageView
    [imageView setImage:downloadedImage.Image];
}

do publicar la respuesta aquí cuando lo tienes, estoy interesado en ver si esto resuelve o no.

enfoque bien bonito? En primer lugar comprobar que donde la asignación de imageview? Segundo, si su imagen se fija significa que el código específico simplemente en toda

if(cell == nil)
{

}

lado esa condición. Me enfrento a algo mismo problema y lo resolvió de esta manera. quisiera saber si esto funciona o no.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top