views:

291

answers:

2

I'm trying to download several images in response to a single http request. On the server side (java) I'm using oreilly multipart response and I'm getting my datas in my iPhone Simulator in didReceiveData (approximately one call for each image) after a call to didReceiveResponse (approximately one call for each image as well) in my delegate. The problem is this approximately... Has anyone ever managed to handle correctly multipart/x-mixed-re with iPhone SDK ? If yes what is the best strategy here ? Should I play with the expected length ? on server side ? on client side ? should I wait until I've received everything... mmmh that doesn't even seen enough as the calls to didReceiveData happens in a random order (I'm asking picture1,picture2 and I'm sometimes receiving picture2,picture1 even though the order is respected on server side !). Should i temporize between pictures on server side ? Or should I drop multipart/x-mixed-replace ? what would be the easiest then ?

That's a lot of questions but I'm really stuck here ! Thanks for you help !

+1  A: 

I'm not sure what your final use for the images is, but the intended purpose of the multipart/x-midex-replace content type is for each received part to completely replace the previously received responses. Think of it like frames of a video; only one picture is displayed at a time and the previous ones are discarded.

Temporizing is almost never a foolproof solution. Especially on the iPhone you're going to encounter an unimaginable variety of network situations and relying on a magic number delay between frames will probably still fail some of the time.

Since you have control of the server, I'd recommend dropping the multipart. Make sure when you are sending multiple requests to the server that you don't block the main thread of your iPhone app. Use NSOperations or an alternative HTTP library (like ASIHTTPRequest) to make your image fetch operations asynchronous.

Kirk van Gorkom
Thanks a lot ! I did not know what was the purpose of multipart/x-mixed-replace. This explains a lot !
Adrien Montfort
A: 

Hi Adrien, I did that successfully using this code. The important thing is to create 2 buffers to receive your data. If you use only one you will have some double access problems (stream access and jpg CODEC access) and corrupted JPG data. Do not hesitate to ask me for more details.

- (IBAction)startDowload:(id)sender {

    NSURL *url = [NSURL URLWithString:@"http://210.236.173.198/axis-cgi/mjpg/video.cgi?resolution=320x240&fps=5"];
    NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];

    [req setHTTPMethod:@"GET"];
    /*
    I create 2 NSMutableData buffers. This points is very important.
    I swap them each frame.
    */
    receivedData = [[NSMutableData data] retain];
    receivedData2 = [[NSMutableData data] retain];
    currentData = receivedData;

    urlCon = [[NSURLConnection alloc] initWithRequest:req delegate:self];
    noImg = YES;
    frame = 0;

}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response
{
    // this method is called when the server has determined that it
    // has enough information to create the NSURLResponse

    // it can be called multiple times, for example in the case of a
    // redirect, so each time we reset the data.
    // receivedData is declared as a method instance elsewhere

    UIImage *_i;
    @try
    {
        _i = [UIImage imageWithData:currentData];
    }
    @catch (NSException * e)
    {
        NSLog(@"%@",[e description]);
    }
    @finally
    {
    }

    CGSize _s = [_i size];
    [imgView setImage:_i];

    [imgView setNeedsDisplay];
    [[self view] setNeedsDisplay];
}   
/*
Buffers swap
*/
    if (currentData == receivedData)
    {
        currentData = receivedData2;        
    }
    else
    {
        currentData = receivedData;     
    }

    [currendData setLength:0];
}



- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    // append the new data to the currentData (NSData buffer)
    [currendData appendData:data];
}
Vincent Zgueb