title: When saving recorded video that is too long, app crashes
body: <p><strong>The problem:</strong></p>
  
  <p>When saving a video that is recorded in my app, if the video size/duration is too big/long, my app crashes without a log/exception. </p>
  
  <p><strong>My Setup:</strong></p>
  
  <p>In my App I use a UIImagePickerController to record videos. Now I have noticed that if I make my videos very long in length (for example 30minutes with UIImagePickerControllerQualityTypeMedium, or more than a minute with UIImagePickerControllerQualityTypeIFrame1280x720), when saving the video, the app crashes. Sometimes with and sometimes without a warning. Now I started to debug and noticed it had something to do with memory (malloc_error). </p>
  
  <p>I used the profiler to check allocations live, and noticed that when it was going to save the video, the allocation suddenly became very big (I guess something to do with temporary memory usage for the video?) before it ultimately crashed. Here is a screenshot from the profiler:
  <img src="https://i.stack.imgur.com/c2Be7.png" alt="Allocations screenshot"></p>
  
  <p>The app must be able to record video with a maximum duration of 1 hour (in any quality specified). </p>
  
  <p><strong>What I have tried:</strong></p>
  
  <ul>
  <li>Setting the picker.videoMaximumDuration shorter/longer</li>
  <li>Debug with profiler/instruments</li>
  <li>Check for leaks</li>
  <li>Closed all open apps &amp; deleted app on device (for storage cleaning) to get more memory </li>
  </ul>
  
  <p><strong>Code:</strong></p>
  
  <pre><code>- (void)openCamera:(id)sender context:(NSManagedObjectContext*)context {
      self.context = context;
      //Set self as delegate (UIImagePickerControllerDelegate)
      [self.picker setDelegate:self];
      //If the device has a camera
      if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
          self.picker.sourceType = UIImagePickerControllerSourceTypeCamera;
          self.picker.allowsEditing = YES;
          self.picker.videoQuality = [Settings videoQualitySetting];
          //If the camera can record video 
          NSString *desired = (NSString *)kUTTypeMovie;
          if ([[UIImagePickerController availableMediaTypesForSourceType:self.picker.sourceType] containsObject:desired]) {
              //Let the user record video
              self.picker.mediaTypes = [NSArray arrayWithObject:desired];
              self.picker.videoMaximumDuration = MaxDuration;
          }
          else {
              NSLog(@"Can't take videos with this device"); //debug
          }
          //Present the picker fullscreen/in popover
          if ([Settings shouldDisplayFullScreenCamera]){
              [self presentModalViewController:self.picker animated:YES];
              [self.masterPopoverController dismissPopoverAnimated:YES];
          }
          else {
              if (!_popover){
                  _popover = [[UIPopoverController alloc] initWithContentViewController:self.picker];
              }
              [_popover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
          }
      }
      else {
          NSLog(@"Does not have a camera"); //debug
      }    
  }
  </code></pre>
  
  <p>And code when the image is picked:</p>
  
  <pre><code>- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
      {
      NSString *mediaType = [info objectForKey: UIImagePickerControllerMediaType];
  
      // Save the video, and close the overlay
      if (CFStringCompare ((__bridge CFStringRef) mediaType, kUTTypeMovie, 0)
          == kCFCompareEqualTo) {
  
          self.tempVideoPath = [[info objectForKey:
                                  UIImagePickerControllerMediaURL] path];
          [LocalVideoStorage saveVideo:[NSData dataWithContentsOfPath:self.tempVideoPath name:self.videoName];
          [_picker dismissModalViewControllerAnimated: YES];
          [[_picker parentViewController] dismissModalViewControllerAnimated:YES];
          [_popover dismissPopoverAnimated:YES];  
      }
  }
  </code></pre>
  
  <p>And finally, when it is saved:</p>
  
  <pre><code>+ (NSString*)saveVideo:(NSData*)video:(NSString*)videoName {
      NSFileManager *fileManager = [NSFileManager defaultManager];//create instance of NSFileManager
  
      NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //create an array and store result of our search for the documents directory in it
  
      NSString *documentsDirectory = [paths objectAtIndex:0]; //create NSString object, that holds our exact path to the documents directory
  
      NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.MOV", videoName]]; //add our video to the path
  
      [fileManager createFileAtPath:fullPath contents:video attributes:nil]; //finally save the path (video)
  
      NSLog(@"Video saved!");
      return fullPath;
  
  }
  </code></pre>
  
  <p>I am using ARC with iOS 5.1.1</p>
  
  <p><strong>Update:</strong>
  I have put a breakpoint on malloc_error_break, and in instruments I can see it is called from:</p>
  
  <pre><code>#   Address Category    Timestamp   Live    Size    Responsible Library Responsible Caller
  0   0x10900000  Malloc 473,29 MB    02:08.951.332   •   496283648   Foundation  -[NSData(NSData) initWithContentsOfFile:]
  </code></pre>
  
  <p><strong>Solution:</strong>
  As lawicko &amp; john.k.doe said, I tried to load the video from it's path into an NSData variable. This caused the whole video to be loaded into memory. Instead of doing that, I now just move the file (&amp; rename) <strong>copyItemAtPath</strong></p>
  
  <pre><code>NSError *error = nil;
  if (![fileManager copyItemAtPath:path toPath:fullPath error:&amp;error])
      NSLog(@"Error: %@", error);
  </code></pre>