Auffüllen NSImage mit Daten aus einer asynchronen NSURLConnection

Habe ich Treffer die sprichwörtliche Wand zu versuchen, um herauszufinden, wie füllen Sie ein NSImage mit Daten zurückgegeben, die von einem asynchronen NSURLConnection in meinem desktop-app (KEINE iPhone-Anwendung!!).

Hier ist die situation.

Ich habe eine Tabelle, die mithilfe von benutzerdefinierten Zellen. In jede benutzerdefinierte Zelle ist ein NSImage, welche gezogen wird von einem web-server. Um zu füllen das Bild, das ich tun kann, eine synchrone Anforderung leicht:

myThumbnail = [[NSImage alloc] initWithContentsOfFile:myFilePath];

Das problem mit diesem ist, dass die Tabelle blockiert, bis die Bilder aufgefüllt werden (natürlich, weil es eine synchrone Anfrage). Auf einem großen Tisch, das macht das scrollen unerträglich, aber auch nur, bevölkern die Bilder auf der ersten laufen ist mühsam, wenn Sie von einer beträchtlichen Größe.

Also ich erstelle eine asynchrone Anforderung-Klasse wird das abrufen der Daten in einem eigenen thread als pro Die Dokumentation von Apple. Kein problem. Ich kann die Daten sehen, die gezogen und aufgefüllt (über mein log-Dateien).

Das problem was ich habe ist sobald ich die Daten brauche ich einen Rückruf in meine aufrufende Klasse (die benutzerdefinierte Tabelle anzeigen).

Ich hatte den Eindruck, dass ich tun könnte etwas wie diese, aber es funktioniert nicht, weil (ich gehe davon aus), dass das, was meine Berufung-Klasse wirklich braucht, ist ein delegieren:

NSImage * myIMage;
myImage = [myConnectionClass getMyImageMethod];

In meiner connection-Klasse delegieren kann ich sehen, ich bekomme die Daten, ich weiß nur nicht sehen wie gehen Sie zurück auf die aufrufende Klasse. Meine connectionDidFinishLoading Methode ist direkt aus dem Apple-docs:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    //do something with the data
    //receivedData is declared as a method instance elsewhere
    NSLog(@"Succeeded! Received %d bytes of data",[receivedData length]);

    //release the connection, and the data object
    [connection release];
    [receivedData release];
}

Ich hoffe das ist ein einfaches problem zu lösen, aber ich fürchte, ich bin an der Grenze meiner Kenntnisse auf diesem ein, und trotz einiger ernsthafter Google-suchen und versuchen, viele verschiedene empfohlene Ansätze, die ich bin kämpfen, um zu einer Lösung zu kommen.

Irgendwann werde ich schon einen ausgeklügelten caching-Mechanismus für meine Anwendung, in der Sie die Tabelle anzeigen überprüft den lokalen Computer für die Bilder vor dem ausgehen und Sie bilden den server und vielleicht hat eine Fortschrittsanzeige, bis die Bilder abgerufen werden. Jetzt auch lokale Bild der Bevölkerung kann träge werden, wenn das Bild groß genug sind, über einen synchronen Prozess.

Jegliche Hilfe würde sehr geschätzt werden.

Lösung Update

In Fall, jemand Bedürfnisse eine ähnliche Lösung, Dank Ben ' s Hilfe, hier ist was ich kam mit (generisch geändert für die Buchung natürlich). Bedenken Sie, dass habe ich auch implementiert eine benutzerdefinierte Zwischenspeichern von Bildern und habe mein Bild laden-Klasse generisch genug sind, um verwendet werden, von verschiedenen Orten in meinem app zum aufrufen von Bildern.

In meine aufrufende Methode, in meinem Fall war es eine benutzerdefinierte Zelle innerhalb einer Tabelle...

ImageLoaderClass * myLoader = [[[ImageLoaderClass alloc] init] autorelease];

    [myLoader fetchImageWithURL:@"/my/thumbnail/path/with/filename.png"
                     forMethod:@"myUniqueRef"
                        withId:1234
                   saveToCache:YES
                     cachePath:@"/path/to/my/custom/cache"];

Diese erstellt eine Instanz von myLoader-Klasse und übergibt 4 Parameter. Die URL von dem Bild, das ich bekommen will, ist eine einmalige Referenz, die ich verwenden, um zu bestimmen, welche Klasse aus der Anruf beim einrichten der Benachrichtigung der Beobachter, die ID des Bildes, ob ich das Bild speichern möchten, um cache-oder nicht-und der Weg zum cache.

Meine ImageLoaderClass definiert die aufgerufene Methode oben, wo ich was übergeben wird, die vom aufrufenden Zelle:

-(void)fetchImageWithURL:(NSString *)imageURL 
           forMethod:(NSString *)methodPassed 
              withId:(int)imageIdPassed 
         saveToCache:(BOOL)shouldISaveThis
           cachePath:(NSString *)cachePathToUse
{

    NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:imageURL]
                                          cachePolicy:NSURLRequestUseProtocolCachePolicy
                                      timeoutInterval:60.0];

    //Create the connection with the request and start loading the data

    NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];

    if (theConnection) {

        //Create the NSMutableData that will hold
        //the received data 
        //receivedData is declared as a method instance elsewhere

        receivedData = [[NSMutableData data] retain];

        //Now set the variables from the calling class

        [self setCallingMethod:methodPassed];
        [self setImageId:imageIdPassed];
        [self setSaveImage:shouldISaveThis];
        [self setImageCachePath:cachePathToUse];

    } else {
        //Do something to tell the user the image could not be downloaded
    }
}

In der connectionDidFinishLoading Methode, die ich gespeichert, die Datei-cache wenn nötig, und machte einen Benachrichtigungs-Anruf an ein Zuhören Beobachter:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSLog(@"Succeeded! Received %d bytes of data",[receivedData length]);

    //Create an image representation to use if not saving to cache
    //And create a dictionary to send with the notification    

    NSImage * mImage = [[NSImage alloc ] initWithData:receivedData];
    NSMutableDictionary * mDict = [[NSMutableDictionary alloc] init];

    //Add the ID into the dictionary so we can reference it if needed

    [mDict setObject:[NSNumber numberWithInteger:imageId] forKey:@"imageId"];

    if (saveImage)
    {
        //We just need to add the image to the dictionary and return it
        //because we aren't saving it to the custom cache

        //Put the mutable data into NSData so we can write it out

        NSData * dataToSave = [[NSData alloc] initWithData:receivedData];

        if (![dataToSave writeToFile:imageCachePath atomically:NO])
    NSLog(@"An error occured writing out the file");
    }
    else
    {
        //Save the image to the custom cache

        [mDict setObject:mImage forKey:@"image"];
    }

    //Now send the notification with the dictionary

    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];

    [nc postNotificationName:callingMethod object:self userInfo:mDict];

    //And do some memory management cleanup

    [mImage release];
    [mDict release];
    [connection release];
    [receivedData release];
}

Schließlich in der Tabelle controller-set-up einen Beobachter zu hören für die Meldung und schicken Sie es ab, um die Methode zum verarbeiten der re-Anzeige der benutzerdefinierten Zelle:

-(id)init
{
    [super init];

    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];

    [nc addObserver:self selector:@selector(updateCellData:) name:@"myUniqueRef" object:nil];

    return self;
}

Problem gelöst!

InformationsquelleAutor Hooligancat | 2009-11-16
Schreibe einen Kommentar