4

I am attempting to upload audio files, around 50MB but no larger than 100MB, from the users device to a PHP server. As long as the files are small there's no issue, but these larger files cause the app to crash due to the error: "Terminated due to memory issue". Would implementation of a framework such as AlamoFire be necessary to solve this issue or is there something I missed in the documentation?

Thanks, Here is my code:

- (void)initWithWebRequests:(NSMutableURLRequest *)URLRequest inBlock:(ResponseBlock)resBlock 
{
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        __block id responseObjects = nil;

        NSLog(@"URL Request:%@",URLRequest);

        NSURLSession *session = [NSURLSession sharedSession];
        NSURLSessionDataTask *task = [session dataTaskWithRequest:URLRequest
                                                completionHandler:
                                      ^(NSData *data, NSURLResponse *response, NSError *error) {
                                          NSString *responseString = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
                                          if (data.length > 0)
                                          {
                                              id allValues = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
                                              if([(NSDictionary *)allValues count] <= 0)
                                                  responseString = @"Not Available";
                                              responseObjects = allValues;
                                          }
                                          else if(error != nil)
                                          {
                                              responseString = @"Fail";
                                          }
                                          else if(data.length == 0)
                                          {
                                              responseString = @"Not Available";
                                          }
                                          dispatch_sync(dispatch_get_main_queue(), ^{
                                              [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                                                  if (error) {
                                                      resBlock(error, responseObjects, responseString);
                                                  }
                                                  else {
                                                      resBlock(error, responseObjects, responseString);
                                                  }
                                              }];
                                          });
                                      }];

        [task resume];

    });
}];

[operation setQueuePriority:NSOperationQueuePriorityNormal];
[self.operationQueue addOperation:operation];
}
  • By the way, what is the intent of the operation-based approach? Are you aware that this operation won't wait for the upload to finish? Hey, if you're building operations for the construction of the request, that's fine, but if your intent was to have an operation that wrapped not only the construction of the request, but performing it, too, the above will not achieve what you want. Besides, if you're really uploading 100mb file, you probably eventually want to use background sessions, which are antithetical to operation queue approaches. – Rob May 15 '17 at 21:19
  • Wow, this is a great thought. I figured my code is pretty rudimentry. As a new developer, I'm still learning the different ways of approach, but I definitely appreciate the feedback. – AaronBeReal May 17 '17 at 15:52

2 Answers2

4

Use uploadTaskWithRequest:fromFile:completionHandler: instead of dataTaskWithRequest and supply the body of the request in the fromFile parameter rather than adding it to the request. That prevents loading the whole file into memory at the same time.

Theoretically, you could do a streaming-based upload to avoid the memory impact, too, but given the file sizes that you're talking about, I assume you eventually want to considering using background NSURLSession. And for background upload requests, you really want to use file-based uploads, not streaming-based approaches.

In answer to your framework question, libraries like Alamofire (or, more appropriate given that you're using Objective-C, AFNetworking, an Objective-C networking library from the same author) help create complicated requests, so you might consider that, but it has nothing to do with the memory issue you have here.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Thanks for the thorough response, still trying to learn my way around development challenges like this one. I had a feeling that loading the whole file into memory was the problem, I'll try implementing this and report back! – AaronBeReal May 17 '17 at 15:57
0

Try this AFNetworking code import #import "AFHTTPSessionManager.h" this file

[SVProgressHUD showWithStatus:@"Loading..."];
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:URL parameters:postParams constructingBodyWithBlock:^(id<AFMultipartFormData> formData)
{
     [formData appendPartWithFileData:imageData name:@"Key" fileName:@"image" mimeType:@"image/jpeg"];
} error:nil];


AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];

NSURLSessionUploadTask *uploadTask;

uploadTask = [manager
              uploadTaskWithStreamedRequest:request
              progress:^(NSProgress * _Nonnull uploadProgress)
              {
                  NSLog(@"%@",uploadProgress);
              }
              completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error)
              {
                  if (error)
                  {
                      [SVProgressHUD dismiss];

                  }
                  else
                  {
                      [SVProgressHUD dismiss];

                  }
              }];
[uploadTask resume];
Jignesh Mayani
  • 6,937
  • 1
  • 20
  • 36