2011-10-17 1 views
1

안녕하십니까, 일부 파일을 업로드하는 응용 프로그램을 개발 중입니다. 실제 문제는 없지만 단지 하나의 큰 문제가 있습니다. 1GB의 파일을 업로드하려고하면 1GB의 메모리가 할당되며 이는 좋은 일이 아니라는 것을 이해할 수 있습니다.NSMutableURLRequest 및 메모리 문제

내 코드는 다음과 같습니다. 데이터를 NSData로 할당 한 다음 NSMutableURLRequest + NSURLConnection을 사용하여 업로드합니다. 내 질문은 : 전체 메모리를 할당하지 않고이 작업을 수행 할 수있는 방법이 있습니까? 나는 밖으로 찾았지만 아무 것도 찾지 못했습니다 ...

_uploadDataFile은 이전에 할당 된 NSData 하위 클래스 인스턴스입니다.

- (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: 

내 영어에 대한 당신과 죄송합니다 감사합니다 경계 : nomeFile이 : 같은 방법은 같습니다 (을 NSData *) dataForPOSTWithDictionary가 - 어떻게

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]; 

여기입니다.

답변

3

가장 흥미로운 문제! 본문 데이터를 공급하는 두 가지 방법이 NSURLConnection/Request에 있습니다

  • NSData
  • NSInputStream

불행하게도, 어느 쪽도없는 당신이 파일 + 어떤 형태의 업로드 원하기 때문에 당신이 상자 밖으로 원하는 것을 데이터. 이상적으로, 필요한대로 포맷 된 데이터를 제공하기 위해 서브 클래스 NSInputStream을 사용할 수 있습니다. 그러나 마지막으로 확인한 경우 NSURLConnection은 이러한 하위 클래스를 처리 할 수 ​​없습니다. 대신 다음과 같이하십시오.

  1. CFStreamCreateBoundPair()을 사용하여 스트림 쌍을 만듭니다. 이는 각각 무료 NSOutputStreamNSInputStream에 브리지됩니다 CFWriteStreamCFReadStream, 반환
  2. 입력 스트림
  3. 시작 연결
  4. 로 URL 요청에 출력 스트림의 대표
  5. -setHTTPBodyStream:로 자신을 설정

이제 출력 스트림의 대리자가 주기적으로 호출되어 데이터를 요청해야합니다. POST 데이터를 공급하고 파일 데이터 청크를 공급해야합니다. 따라서 전체 파일이 한번에 전체적으로 메모리에 저장되는 것은 아닙니다.

+0

감사합니다. 당신은 나에게 부탁을 해줬고 다시 조회를 시작했고 1 시간 동안 검색 한 후에 ASIHTTPRequest에 내가 원하는 것을 발견했습니다. 내 문제가있는 모든 사람은 여기에 표시된대로 ASIFormDataRequests를 사용해야합니다. http : // allseeing-i.com/ASIHTTPRequest/How-to-use#streaming 그들은 CFReadStreamCreateForStreamedHTTPRequest로 요청을 만듭니다. – Sylter