NSURLConnection下载多个图像

时间:2011-05-17 06:34:32

标签: objective-c xml cocoa macos nsurlconnection

我正在尝试从存储在XML Feed中的网址下载多个图片。从XML获取图像URL正常工作。但是,NSURLConnection正在创建空文件,但是如NSLog中所述接收数据。在connectionDidFinishLoading:(NSURLConnection *)connection中,接收到数据和正确的字节,问题是如何将receivedData写入正确的文件。

半工作代码:

-(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 个答案:

答案 0 :(得分:3)

您必须等到连接告诉您已完成,然后才能写入数据。连接在另一个线程上处理;如果您尝试在原始线程上立即访问数据,则不会有任何内容。

您应该将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 :(得分:1)

您可以使用带有标记的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

然后在parsingComplete中创建连接,自定义url连接:

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

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

现在,您可以将imageNameCustomURLConnection标记一起使用,并将其保存在connectionDidFinishLoading:

CustomURLConnection *urlConec = (CustomURLConnection*)connection;

NSMutableData *dataFromConnection = [self dataForConnection:urlConec];

这是函数dataForConnection:

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

希望有所帮助。