Muss drawInRect: für einen separaten Kontext auf dem Hauptthread ausgeführt werden?

[Update: Dieses Problem wurde behoben. Das Problem war nicht indrawInRect: aber inUIGraphicsBeginImageContext()]

In meiner App greife ich nach einer Reihe großer Bilder, beschneide sie auf Miniaturbildgröße und speichere die Miniaturbilder für die Vorschau.

Bitte beachten Sie, dass ich dies in einem separaten Bildkontext mache - das istnich über das erneute Zeichnen einesUIView das ist auf dem Bildschirm.

Dieser Code ist ziemlich intensiv, daher führe ich ihn in einem separaten Thread aus. Die tatsächliche Skalierung sieht wie folgt aus und ist eine Kategorieimplementierung über UIImage:

- (UIImage *) scaledImageWithWidth:(CGFloat)width andHeight:(CGFloat)height
{
    CGRect rect = CGRectMake(0.0, 0.0, width, height);
    UIGraphicsBeginImageContext(rect.size);
    [self drawInRect:rect]; // <-- crashing on this line
    UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return scaledImage;
}

Dies wird von einer separaten Methode aufgerufen, die nacheinander die Bilder durchläuft und die Verarbeitung durchführt. Der eigentliche Aufruf der obigen Methode sieht folgendermaßen aus:

UIImage *small = [bigger scaledImageWithWidth:24.f andHeight:32.f];

Das funktioniert die meiste Zeit, aber gelegentlich bekomme ich einEXC_BAD_ACCESS.

Backtrace:

#0  0x330d678c in ripc_RenderImage ()
#1  0x330dd5aa in ripc_DrawImage ()
#2  0x300e3276 in CGContextDelegateDrawImage ()
#3  0x300e321a in CGContextDrawImage ()
#4  0x315164c8 in -[UIImage drawInRect:blendMode:alpha:] ()
#5  0x31516098 in -[UIImage drawInRect:] ()
#6  0x0000d6e4 in -[UIImage(Scaling) scaledImageWithWidth:andHeight:] (self=0x169320, _cmd=0x30e6e, width=48, height=64) at /Users/me/Documents/svn/app/trunk/Classes/UIImage+Scaling.m:20
#7  0x00027df0 in -[mgMinimap loadThumbnails] (self=0x13df00, _cmd=0x30d05) at /Users/me/Documents/svn/app/trunk/Classes/mgMinimap.m:167
#8  0x32b15bd0 in -[NSThread main] ()
#9  0x32b81cfe in __NSThread__main__ ()
#10 0x30c8f78c in _pthread_start ()
#11 0x30c85078 in thread_start ()

[Update 4] Wenn ich dies im Simulator ausführe und dieses Problem auftritt, zeigt die Konsole zusätzlich Folgendes:

// the below is before loading the first thumbnail
<Error>: CGContextSaveGState: invalid context
<Error>: CGContextSetBlendMode: invalid context
<Error>: CGContextSetAlpha: invalid context
<Error>: CGContextTranslateCTM: invalid context
<Error>: CGContextScaleCTM: invalid context
<Error>: CGContextDrawImage: invalid context
<Error>: CGContextRestoreGState: invalid context
<Error>: CGBitmapContextCreateImage: invalid context
// here, the first thumbnail has finished loading and the second one
// is about to be generated
<Error>: CGContextSetStrokeColorWithColor: invalid context
<Error>: CGContextSetFillColorWithColor: invalid context

Mein Bauchgefühl ist, dass ich gelegentlich versuche,drawInRect: während das Betriebssystem auch versucht, etwas zu zeichnen, was gelegentlich zu einem Absturz führt. Ich habe immer angenommen, dass dies akzeptabel ist, solange Sie nicht auf dem tatsächlichen Bildschirm zeichnen. Ist dies nicht der Fall? Oder wenn es der Fall ist, eine Idee, was dies verursachen könnte?

Update (r2): Ich habe vergessen zu erwähnen, dass diese App unter sehr strengen Speicherbeschränkungen ausgeführt wird (ich habe zu einem bestimmten Zeitpunkt eine Menge Bilder geladen und diese werden ein- / ausgelagert). Dies kann also der Fall sein Der Speicher geht zur Neige (weiterlesen - nicht). Ich bin mir jedoch nicht sicher, wie ich das überprüfen soll, daher wären auch Gedanken dazu willkommen. Ich habe dies überprüft, indem ich die Anzahl der geladenen Bilder stark verringert und eine Überprüfung hinzugefügt habe, um sicherzustellen, dass die Zuordnung ordnungsgemäß aufgehoben wurde (und der Absturz weiterhin auftritt).

Update 3: Ich dachte, ich hätte das Problem gefunden. Unten ist die Antwort, die ich geschrieben habe, bevor der Absturz wieder passierte:

Der Code wird (nachdem ich diese Frage gestellt habe) gelegentlich mit dem Beendigungscode @ beende0 und manchmal mit Exit-Code10 (SIGBUS). 0 bedeutet "kein Fehler", das war also extrem merkwürdig.10 scheint ein bisschen von allem zu bedeuten, das war auch nicht hilfreich. DasdrawInRect: call war allerdings ein großer Hinweis, als der Absturz dort passierte.

Das Durchschleifen, um die Thumbnails zu erhalten, erzeugte viele automatisch freigegebene Bilder. Ich hatte einen Autorelease-Pool, der jedoch die gesamte for-Schleife umhüllte. Ich habe einen zweiten Autorelease-Pool im @ hinzugefüfor loop:

- (void)loadThumbnails
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    for (...) {
        NSAutoreleasePool *cyclePool = 
           [[NSAutoreleasePool alloc] init]; // <-- here
        UIImage *bigger = ...;
        UIImage *small = [bigger scaledImageWithWidth:24.f andHeight:32.f];
        UIImage *bloated = [i scaledImageWithWidth:48.f andHeight:64.f];
        [cyclePool release]; // <-- ending here
    }
    [pool release];
}

Ich dachte, dass das oben genannte Problem behoben ist, bis ich die App ausgeführt habe und sie kurz zuvor erneut mit "Beendigungscode 0" auf mir abgestürzt ist. Zurück zum Zeichenbrett..

Antworten auf die Frage(6)

Ihre Antwort auf die Frage