2011-10-17 32 views
1

早上好, 我開發上傳一些文件的應用程序;沒有真正的問題,但只有一個大問題:如果我嘗試上傳1GB的文件,它會分配1GB的內存,並且您可以理解這不是一件好事。NSMutableURLRequest和內存問題

這裏是我的代碼:我分配數據的NSData,然後我用NSMutableURLRequest + NSURLConnection的上傳他們。我的問題是:有沒有辦法做到這一點,而不需要分配整個內存?我搜索了,但我沒有發現任何...

_uploadDataFile是之前分配的NSData子類的實例。

NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://my.server/page"] 
                  cachePolicy:NSURLRequestReloadIgnoringCacheData 
                 timeoutInterval:60.0] autorelease]; 

NSData *dataFile; 

if (_uploadDataFile == nil) { 
    NSError *error = nil; 
    dataFile = [[[NSData alloc] initWithContentsOfFile:@"pathToFile" options:NSDataReadingUncached error:&error] autorelease]; 

    if (error) { 
     NSLog(@"Error %i: %@", [error code], [error localizedDescription]); 
     [self fermaUpload]; //Stop Upload 
     return; 
    } 
} 

else 
    dataFile = [_uploadDataFile file]; 

NSMutableDictionary *dictPost = [[[NSMutableDictionary alloc] init] autorelease]; 
[dictPost setValue:dataFile forKey:@"uploads[]"]; 

NSData *mutData = [self dataForPOSTWithDictionary:dictPost boundary:@"0194784892923" nomeFile:[@"pathToFile" lastPathComponent]]; 

NSString *postLength = [NSString stringWithFormat:@"%d", [mutData length]]; 

[request setHTTPMethod:@"POST"]; 
[request setValue:postLength forHTTPHeaderField:@"Content-Length"]; 
[request setValue:@"multipart/form-data; boundary=0194784892923" forHTTPHeaderField:@"Content-Type"]; 
[request setHTTPBody:mutData]; 
[request setHTTPShouldHandleCookies:YES]; 

theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; 

,這裏是如何 - (NSData的*)dataForPOSTWithDictionary:邊界:nomeFile:方法是這樣的:

- (NSData *)dataForPOSTWithDictionary:(NSDictionary *)aDictionary boundary:(NSString *)aBoundary nomeFile:(NSString *)nomeFile { 
NSArray *myDictKeys = [aDictionary allKeys]; 
NSMutableData *myData = [NSMutableData dataWithCapacity:1]; 
NSString *myBoundary = [NSString stringWithFormat:@"--%@\r\n", aBoundary]; 

for(int i = 0;i < [myDictKeys count];i++) { 
    id myValue = [aDictionary valueForKey:[myDictKeys objectAtIndex:i]]; 
    [myData appendData:[myBoundary dataUsingEncoding:NSUTF8StringEncoding]]; 
    //if ([myValue class] == [NSString class]) { 
    if ([myValue isKindOfClass:[NSString class]]) { 
     [myData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", [myDictKeys objectAtIndex:i]] dataUsingEncoding:NSUTF8StringEncoding]]; 
     [myData appendData:[[NSString stringWithFormat:@"%@", myValue] dataUsingEncoding:NSUTF8StringEncoding]]; 
    } else if(([myValue isKindOfClass:[NSURL class]]) && ([myValue isFileURL])) { 
     [myData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", [myDictKeys objectAtIndex:i], [[myValue path] lastPathComponent]] dataUsingEncoding:NSUTF8StringEncoding]]; 
     [myData appendData:[[NSString stringWithFormat:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; 
     [myData appendData:[NSData dataWithContentsOfFile:[myValue path]]]; 
    } else if(([myValue isKindOfClass:[NSData class]])) { 
     [myData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", [myDictKeys objectAtIndex:i], nomeFile] dataUsingEncoding:NSUTF8StringEncoding]]; 
     [myData appendData:[[NSString stringWithFormat:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; 
     [myData appendData:myValue]; 
    } // eof if() 

    [myData appendData:[[NSString stringWithString:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; 
} // eof for() 
[myData appendData:[[NSString stringWithFormat:@"--%@--\r\n", aBoundary] dataUsingEncoding:NSUTF8StringEncoding]]; 

return myData; } // eof dataForPOSTWithDictionary:boundary: 

謝謝你,對不起我的英語。

回答

3

一個最有趣的問題!有料體數據的兩種方式爲NSURLConnection/Request

  • NSData
  • NSInputStream

不幸的是,你想要做什麼現成的,因爲你要上傳的文件+某種形式數據。理想情況下,您可以繼承NSInputStream以提供根據需要格式化的數據。但是,我上次檢查時,NSURLConnection無法處理這樣的子類。相反,請執行以下操作:

  1. 使用CFStreamCreateBoundPair()創建一對流。這將返回一個CFWriteStreamCFReadStream,這是免費電話橋接NSOutputStreamNSInputStream,分別爲
  2. 爲自己設定的輸出流的委託
  3. -setHTTPBodyStream:與輸入流
  4. 啓動連接
  5. URL請求

輸出流的代表,現在應該定期調用,請求數據。您需要輸入POST數據,然後輸入大量的文件數據。因此,整個文件不會一次完全在內存中。

+0

謝謝!你給了我一個提振,所以我再次開始查找,經過一個小時的搜索,我發現ASIHTTPRequest具有我想要的:具有問題的每個人都應該使用ASIFormDataRequests,如下所示:http:// allseeing-i.com/ASIHTTPRequest/How-to-use#streaming它們使用CFReadStreamCreateForStreamedHTTPRequest創建請求,基本上就是你所說的。 – Sylter