NSURLConnection Скачать несколько изображений - PullRequest
2 голосов
/ 17 мая 2011

Я пытаюсь загрузить несколько изображений с URL-адреса, хранящегося в канале XML.Получение URL-адресов изображений из XML работает правильно.Однако NSURLConnection создает пустые файлы, но данные принимаются, как отмечено в NSLog.В connectionDidFinishLoading:(NSURLConnection *)connection получены данные и правильные байты, проблема заключается в том, как заставить записать полученные данные в правильный файл.

Полуработающий код:

-(void)parsingComplete:(XMLDataSource*)theParser 
{
    /*  iterate through the Categories and create the 
        sub-directory if it does not exist  
     */
    for (int i = 0; i < [categories count]; i++) {
        NSString *cat      = [NSString stringWithFormat:@"%@/%@",BASE_DIR,[[categories objectAtIndex:i] objectForKey:@"name"]];
        NSString *catName  = [[categories objectAtIndex:i] objectForKey:@"name"];
        NSArray  *catArray = [[categories objectAtIndex:i] objectForKey:@"images"];

        /*  create the sub-direcotry naming it the #category# key  */
        if (![FILEMANAGER fileExistsAtPath:cat]) {
            [FILEMANAGER createDirectoryAtPath:cat withIntermediateDirectories:NO attributes:nil error:nil];
        }

        //NSLog(@"\n\nCategory: %@",cat);
        for (int x = 0; x < [catArray count]; x++) {
            //NSLog(@"Image: %@",[[catArray objectAtIndex:x] objectForKey:@"imageUrl"]);   
            /*  download each file to the corresponding category sub-directory  */
            fileOut = [NSString stringWithFormat:@"%@/%@_0%i.jpg",cat,catName,x];

            NSURLRequest *imageRequest = 
            [NSURLRequest requestWithURL:[NSURL URLWithString:[[catArray objectAtIndex:x] objectForKey:@"imageUrl"]]
                             cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:30.0];
            NSURLConnection *imageConnection = [[NSURLConnection alloc] initWithRequest:imageRequest delegate:self];

            int counter = 0;
            //BOOL result = NO;
            if(imageConnection)
            {
                NSLog(@"Counter: %i",counter++);
                receivedData = [[NSMutableData data] retain];
                /*result = */[receivedData writeToFile:fileOut atomically:YES];
            }
            /*
                if (!result) NSLog(@"Failed"); else NSLog(@"Successful");
             */
        }
    }
}

#pragma mark NSURLConenction

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response  {  
    [receivedData setLength:0];  
} 
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data  {  
    [receivedData appendData:data];
}  
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    // release the connection, and the data object
    [connection release];
    // receivedData is declared as a method instance elsewhere
    [receivedData release];
    // inform the user
    NSLog(@"Connection failed! Error - %@ %@",
          [error localizedDescription],
          [[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
}
- (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]);  
    NSString *aStr = [[NSString alloc] initWithData:receivedData encoding:NSASCIIStringEncoding];  
    // release the connection, and the data object  
    //[receivedData release];  
} 

Ответы [ 2 ]

3 голосов
/ 17 мая 2011

Вам нужно подождать, пока соединение не сообщит вам, что оно установлено, прежде чем вы сможете записать данные. Соединение обрабатывается в другом потоке; если вы попытаетесь немедленно получить доступ к данным в исходном потоке, в этом ничего не будет.

Вы должны переместить вызов writeToFile: в конец connectionDidFinishLoading: или в другой метод, который вы вызываете оттуда. Это первый момент, когда вы знаете, что все данные были собраны.

Я бы также предложил создать экземпляр NSMutableData в didRecieveResponse:, чтобы вы знали, что он доступен в нужное время. Это будет более читабельным / понятным. Вы можете думать о методах делегатов как о коллективной «области видимости» - данные используются только внутри них, поэтому их следует создавать внутри одного из них.

В ответ на ваш комментарий:

Одна из возможностей, поскольку у вас есть так много, что нужно сделать для этой загрузки, и, кажется, что вы не затрагиваете GUI, это запустить весь метод parsingComplete: в фоновом потоке и использовать +[NSURLConnection sendSynchronousRequest:returningResponse:error:]. Таким образом, ваш код будет просто ждать, пока данные не вернутся, одним куском, и вы можете написать его сразу после возврата вызова sendSynchronous....

NSError * err;
NSURLResponse * response;
NSData * receivedData = [NSURLConnection sendSynchronousRequest:imageRequest
                                              returningResponse:&response
                                                          error:&err];
if( !receivedData ){
    /* Handle error */
}
/* Check response */

BOOL result = [receivedData writeToFile:fileOut atomically:YES];
/* check result, etc. */
1 голос
/ 23 мая 2011

Вы можете использовать CustomURLConnection с тегом для именования изображений перед их загрузкой.

С помощью этого кода вы можете создать customURLConnection, назвать его при выполнении запроса и запросить имяизображения в connectionDidFinishLoading:

CustomURLConnection.h

#import <Foundation/Foundation.h>

@interface CustomURLConnection : NSURLConnection 
{
NSString *tag;
}

@property (nonatomic, retain) NSString *tag;

- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately tag:(NSString*)aTag;

@end

CustomURLConnection.m

#import "CustomURLConnection.h"

@implementation CustomURLConnection

@synthesize tag;

- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately tag:(NSString*)aTag 
{
self = [super initWithRequest:request delegate:delegate startImmediately:startImmediately];

    if (self) {
        self.tag = aTag;
    }
    return self;
}

- (void)dealloc 
{
    [tag release];
    [super dealloc];
}

@end

Затем установите соединение, пользовательское URL-соединение в вашем parsingCompleteс помощью:

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:yourURL];
[request setTimeoutInterval:3000.0];

CustomURLConnection *connection = [[CustomURLConnection alloc]     initWithRequest:request delegate:self startImmediately:YES tag:imageTag];

Теперь вы можете взять imageName с тегом CustomURLConnection и сохранить его в connectionDidFinishLoading:

CustomURLConnection *urlConec = (CustomURLConnection*)connection;

NSMutableData *dataFromConnection = [self dataForConnection:urlConec];

, и это код дляфункция dataForConnection:

- (NSMutableData*)dataForConnection:(CustomURLConnection*)connection 
{
    NSMutableData *data = [receivedData objectForKey:connection.tag];
    return data;
}

Надеюсь, что поможет.

...