Upload large video via NSURLSession causes memory pressure crash

↘锁芯ラ 提交于 2019-12-07 01:42:30

问题


I use the following codes to upload video to server, which requires me to convert the video from video format to NSData. However, when the video is large (e.g. 10 minute video), the App crashes due to memory pressure. How can I resolve this?

- (void)uploadVideo {
    NSDictionary *params = nil;
    NSString *NSURLSessionIdentifier = [NSString stringWithFormat:@"%@%@",@"my.bundle.identifier.",[self getTimeString]];
    NSURLSessionConfiguration *sessionConfig;
    // SessionConfiguration With iOS Version
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
        sessionConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:NSURLSessionIdentifier];
    } else {
        sessionConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:NSURLSessionIdentifier];
    }
    sessionConfig.HTTPMaximumConnectionsPerHost = 1;

    NSURLSession *uploadSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[NSOperationQueue new]];
    OMGMultipartFormData *multipartFormData = [OMGMultipartFormData new];

    NSString *url = @"SOME_UPLOAD_URL";
    // ========= PROBLEMATIC LINE below =========
    self.video_data = [NSData dataWithContentsOfURL:self.video_url];
    // ========= PROBLEMATIC LINE above =========
    [multipartFormData addFile:self.video_data parameterName:@"file" filename:@"file.mp4" contentType:@"video/mp4"];

    NSURLRequest *rq = [OMGHTTPURLRQ POST:url:multipartFormData];
    id path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"upload.NSData"];
    [rq.HTTPBody writeToFile:path atomically:YES];
    [[uploadSession uploadTaskWithRequest:rq fromFile:[NSURL fileURLWithPath:path]] resume];

}

p.s. self.video_url is a file URL given by UIImagePickerController which filters only video to choose. I then choose a 10-minute video.

p.s. I got AFNetworking in same App too, can it help with background transfer?


回答1:


You should be able to this by using a NSMutableURLRequest and utilizing its setHTTPBodyStream setter.

The following are snippets adapted from some code of mine. It handled well for video way over 10 mins. mostly large videos of 60 - 90 minutes.

NSData *movieData = [NSData dataWithContentsOfFile:theMovieSourceString];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

[request setHTTPMethod:@"POST"];
[request setValue:@"video/quicktime" forHTTPHeaderField:@"Content-Type"];
[request setValue:[NSString stringWithFormat:@"attachment; filename=\"%@\"",yourMovieSourceString] forHTTPHeaderField:@"Content-Disposition"];
[request setValue:[NSString stringWithFormat:@"%ld",(unsigned long)[movieData length]] forHTTPHeaderField:@"Content-Length"];
[request setHTTPBodyStream:[NSInputStream inputStreamWithFileAtPath:yourMovieSourceString]];

You can now use this request with your NSURLConnection

NSURLConnection *connection =[[NSURLConnection alloc] initWithRequest:request delegate:self];



回答2:


Issue is obvious - 10 min video file is too big to be stored in a memory what

self.video_data = [NSData dataWithContentsOfURL:self.video_url];

does.

Solution is not to store all request body in a memory. The simplest way is to use NSURLRequest's HTTPBodyStream property. You can create NSInputStream yourself but since you already have AFNetworking it is much easier to use it. In my project I do it this way:

// data.fields is a dictionary with params

NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer]
                                multipartFormRequestWithMethod:@"POST"
                                URLString:[url absoluteString]
                                parameters:nil
                                constructingBodyWithBlock:^(id<AFMultipartFormData> formData)
                                {
                                    [data.fields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
                                        [formData appendPartWithFormData:[obj dataUsingEncoding:NSUTF8StringEncoding] name:key];
                                    }];
                                    [formData appendPartWithFileURL:fileURL name:@"file_0" error:&error2];
                                }
                                error:&error];


来源:https://stackoverflow.com/questions/31181322/upload-large-video-via-nsurlsession-causes-memory-pressure-crash

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!