2009-11-03 11 views
0

Cela semble être la méthode classique pour numériser des images à partir de l'iPhone. J'ai un fil qui est envoyé à partir du fil principal pour aller chercher des codes. Il crée essentiellement un nouveau UIImage à chaque fois puis le supprime.UIImage dans le thread n'est pas libéré/écrasé

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    { 
     while (![thread isCancelled]) { 
#ifdef DEBUG 
      NSLog(@"Decoding Loop"); 
#endif 
     // [self performSelectorOnMainThread:@selector(updateImageBuffer) withObject:nil waitUntilDone:YES];   
      CGImageRef cgScreen = UIGetScreenImage(); 
      UIImage *uiimage = [UIImage imageWithCGImage:cgScreen]; 

      if (uiimage){ 
       CGSize size = [uiimage size]; 
       CGRect cropRect = CGRectMake(0.0, 80.0, size.width, 360); // Crop to centre of the screen - makes it more robust 
#ifdef DEBUG 
       NSLog(@"picked image size = (%f, %f)", size.width, size.height); 
#endif 
       [decoder decodeImage:uiimage cropRect:cropRect]; 
      } 
      [uiimage release]; 
      CGImageRelease(cgScreen); 
     } 
    } 
    [pool release]; 

le problème est que la [version de la piscine] provoque une ERROR_BAD_EXC (ce vieux classique) et les bombes de programme. On me dit qu'il n'est pas nécessaire d'appeler [uiimage] car je n'ai pas explicitement attribué un UIImage, mais cela ne semble pas être le cas. Si je sors cette ligne, l'utilisation de la mémoire passe à travers le toit et le programme quitte les cotisations dues au manque de mémoire. Il semble que je ne peux pas avoir ce travail comme je le voudrais.

Y at-il un moyen de créer un UIImage "in-place"? I.e, avez un tampon qui est écrit encore et encore comme un UIImage? Je soupçonne que cela fonctionnerait?

Mettre à jour!

Essayé l'exécution des appels liés à UIKit sur le thread principal comme suit:

-(void)performDecode:(id)arg{ 

    // Perform the decoding in a seperate thread. This should, in theory, bounce back with a 
    // decoded or not decoded message. We can quit at the end of this thread. 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    { 
     while (![thread isCancelled]) { 

#ifdef DEBUG 
      NSLog(@"Decoding Loop"); 
#endif 
      [self performSelectorOnMainThread:@selector(updateImageBuffer) withObject:nil waitUntilDone:YES];   

      if (uiimage){ 
       CGSize size = [uiimage size]; 
       CGRect cropRect = CGRectMake(0.0, 80.0, 320, 360); // Crop to centre of the screen - makes it more robust 
#ifdef DEBUG 
       NSLog(@"picked image size = (%f, %f)", size.width, size.height); 
#endif 
       [decoder decodeImage:uiimage cropRect:cropRect]; 
      } 
     } 
    } 
    [pool drain]; 


#ifdef DEBUG 
    NSLog(@"finished decoding."); 
#endif 


} 

-(void) updateImageBuffer { 
    CGImageRef cgScreen = UIGetScreenImage(); 
    uiimage = [UIImage imageWithCGImage:cgScreen]; 
    //[uiimage release]; 
    CGImageRelease(cgScreen); 
} 

Pas de joie mais comme EXC_BAD_ACCESS dresse sa tête hideuse quand on veut saisir la « taille » du UIImage

Répondre

1

Comme cela a été dit par d'autres, vous ne devriez pas libérer le retour de UIImage imageWithCGImage:. Il est auto-libéré. Lorsque votre pool se vide, il tente d'envoyer un message de relâchement à vos objets image déjà libérés, conduisant à votre plantage.

La raison pour laquelle votre utilisation de la mémoire ne cesse de grimper est que vous ne vidangez que le pool autorelease en dehors de la boucle. Vos objets auto-libérés continuent d'accumuler à l'intérieur de la boucle. (Soit dit en passant, vous devez libérer votre pool autorelease à la fin de cette méthode, car il est en train de fuir.) Pour éviter cette accumulation, vous pouvez drainer la piscine à intervalles réguliers dans la boucle.

Cependant, je suggère de passer à [[UIImage alloc] initWithCGImage:cgScreen] puis de libérer l'image lorsque vous avez terminé.J'essaie d'éviter d'utiliser des objets autoreleased où je peux dans les applications iPhone afin d'avoir un contrôle plus serré sur l'utilisation de la mémoire et de meilleures performances globales.

+0

Salut! Je l'ai mentionné dans le commentaire précédent mais merci pour le conseil avec Drain. La clé était de comprendre que les méthodes de commodité s'en tiennent à la libération automatique et que la libération anticipée ne fonctionne donc pas correctement. – Oni

0

[uiimage release] est définitivement faux dans ce contexte. En outre, Apple souligne que toutes les méthodes UIKit doivent être exécutées sur le thread principal. Cela inclut UIGetScreenImage() et +[UIImage imageWithCGImage:].

Modifier: Vous obtenez une exception lorsque vous appelez -[UIImage size] sur le mauvais thread. Cela ne devrait probablement pas vous surprendre parce que ce n'est pas permis.

+0

Oui, c'était ce que je pensais. Je l'ai coupé mais la bibliothèque interne que j'utilise fait de telles choses à UIImage aussi ... donc pas de joie avec celle-là. – Oni

1

UIGetScreenImage() est privé et non documenté de sorte que vous ne pouvez pas l'utiliser. Dire que rien à ce sujet suggère que vous possédez maintenant CGImageRef cgScreen alors pourquoi le relâchez-vous? Vous n'avez pas non plus le moyen de savoir si le thread est sûr et il devrait donc supposer que ce n'est pas le cas. Vous continuez ensuite à libérer la IImage * uiimage que vous n'avez pas initialisée, conservée ou copiée, donc encore une fois - vous ne le possédez pas. Passez en revue le docs.

+0

privé ou non privé est sans importance pour moi à ce stade. La méthode de publication sur cgScreen a été prise à partir d'un autre morceau de code. J'ai passé en revue les docs et je suis d'accord que uiimage ne devrait pas être libéré CEPENDANT, comme je l'ai dit, la mémoire ne cesse de grimper si cette ligne n'est pas mise en place – Oni

0
UIImage *uiimage = [[UIImage alloc] initWithCGImage: cgScreen]; 

indiquant que je Explicitement connais le mieux quand libérer l'objet semblait fonctionner. La mémoire virtuelle augmente encore mais physique reste maintenant constante. Merci d'avoir signalé les problèmes liés à UIKit Thread Safe. C'est un point que j'avais manqué mais qui semble ne pas affecter la course à ce stade.

Aussi, je tiens à souligner, laser rouge et Quickmark deux utilisent cette méthode d'information de la caméra de balayage;)