1

私のアプリでは、マルチパート POST リクエストを実行する必要があります。リクエストでは、デバイスのフォト ライブラリに保存されているファイルを送信する必要があります。アップロードが完了し、返されたデータを受信した後、リクエストにリリース メッセージを送信しますが、Instruments はデータがデバイスのメモリに残っていることを示します。

これは、リクエスト オブジェクトを作成する方法です。

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];

[request setHTTPShouldHandleCookies:YES];
[request setTimeoutInterval:30];
[request setHTTPMethod:@"POST"];
NSString *boundary = @"---------------------------14737809831466499882746641449";

// set Content-Type in HTTP header
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
[request setValue:contentType forHTTPHeaderField: @"Content-Type"];

// post body
NSMutableData *body = [[NSMutableData alloc] init];

// add parts (all parts are strings) `parts` is a NSDictionary object
for(id key in parts) {
    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"%@\r\n", [parts objectForKey:key]] dataUsingEncoding:NSUTF8StringEncoding]];
}

// add files data - `file` is a ALAssetRepresentation object
NSData *fileData;
NSString *filename = [file filename];
Byte *buffer = (Byte*)malloc(file.size);
NSUInteger buffered = [file getBytes:buffer fromOffset:0.0 length:file.size error:nil];
fileData = [[NSData alloc] initWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];




if (fileData) {
    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];

    if ([requestType isEqualToString:PUBLISH_TYPE_VC_MANDA]) {
        [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"attachment\"; filename=\"%@\"\r\n", filename] dataUsingEncoding:NSUTF8StringEncoding]];
        [body appendData:[@"Content-Type: image/jpeg\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    } else {
        [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"file\"; filename=\"%@\"\r\n", filename] dataUsingEncoding:NSUTF8StringEncoding]];
        [body appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    }
    [body appendData:fileData];
    [body appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
}

[fileData release];


[body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];


// setting the body of the post to the reqeust
[request setHTTPBody:body];

[body release];

// set the content-length
NSString *postLength = [NSString stringWithFormat:@"%d", [body length]];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setValue:@"Keep-Alive" forHTTPHeaderField:@"Connection"];

// set URL `adress` is a NSURL object
[request setURL:address];

//set cookie
if (storedCookie) {

    NSDictionary *properties = [NSDictionary dictionaryWithObjectsAndKeys:[storedCookie name], NSHTTPCookieName, myDomain, NSHTTPCookieDomain,@"/",NSHTTPCookiePath, [storedCookie value], NSHTTPCookieValue, nil];

    NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:properties];
    NSArray* cookies = [NSArray arrayWithObjects: cookie, nil];
    NSDictionary * headers = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
    [request setAllHTTPHeaderFields:headers];
}

この後、応答を受け取った後、実行します[request release]が、割り当てられたバイトはメモリに残ります。

割り当てモードで実行Instrumentsしましたが、カテゴリのオブジェクトMalloc 91MB(アップロードしている ALAsset のサイズ) があると主張しています。コール ツリーを見ると、すべてのメモリを占有しているシンボルは、[NSConcreteMutableData appendBytes:length:]上記のメソッド内にあります。

バイトを解放しないのはなぜですか? さらに重要なことに、なぜデータをデバイスのメモリに移動する必要があるのでしょうか? Facebook のようなアプリがメモリの問題なしにギャラリーから非常に大きなビデオをアップロードするのを見てきました。

ご清聴ありがとうございました。

編集:さらに調査したところ[request release]、リクエストオブジェクトを使用すると解放されましたが、本体はそうではありませんでした。かなり怪しい行動…

EDIT2:私は明示的に使用[request.HTTPBody release];し、バイトは解放されました。[request release]それが体を解放していなかったことが今でも信じられません。これはバグでしょうか?

4

2 に答える 2

0

さらに調査した結果、リクエストのプロパティHTTPBodyを手動で解放する必要があったため、メモリは解放されませんでした (私の 2 番目の編集を参照)。

で大量のデータを送信NSRequestする場合、デバイスのメモリを消費しない簡単な方法があります。ファイルをディスクに書き込んでからマップする必要があります。この SO answerで詳しく説明しました。それが誰かを助けることを願っています

于 2013-04-23T16:47:41.047 に答える