2016-12-09 6 views
0

Я создаю приложение, которое позволяет пользователям добавлять временную метку к фотографии. Когда выбрано фото из ролика камеры, мое приложение иногда сбой, и Xcode отображает ошибку: «Сообщение от отладчика: завершено из-за проблемы с памятью». Я обнаружил, что он сработает, если я попытаюсь добавить временную метку к очень большому изображению или если я неоднократно на отметке времени на одно и то же изображение.Завершена из-за проблемы с памятью при сохранении измененного изображения в камере.

Ниже приведен код, который, по моему мнению, имеет отношение к проблеме. Кроме того, here - это ссылка на весь проект.

Вот как к метке добавляется метка времени. Я помещаю комментарии, где он падает. Он не всегда сбой в одной строке кода. Я не могу понять, почему мой код приводит к сбою в ошибке памяти.

func textToImage(drawText text: NSString, inImage image: UIImage, atPoint point: CGPoint) -> UIImage { 

    let color = UserDefaults.standard.colorForKey(key: "color")! 
    let font = UserDefaults.standard.value(forKey: "font") as! String 
    let size = UserDefaults.standard.value(forKey: "size") as! Int 
    let fontAndSize = UIFont(name: font, size: CGFloat(size))! 
    let location = Locations(rawValue: UserDefaults.standard.value(forKey: "location") as! String)! 
    let scale = UIScreen.main.scale 


    UIGraphicsBeginImageContextWithOptions(image.size, false, scale) 
    // sometimes terminates here 

    let textFontAttributes = [ 
     NSFontAttributeName: fontAndSize, 
     NSForegroundColorAttributeName: color 
     ] as [String : Any] 
    image.draw(in: CGRect(origin: CGPoint.zero, size: image.size)) 

    let rectSize = text.boundingRect(with: CGSize(width:CGFloat(MAXFLOAT), height: CGFloat(MAXFLOAT)), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: textFontAttributes, context: nil).size 
    // sometimes terminates here 
    if location == .topRight || location == .bottomRight || location == .center || location == .topCenter || location == .bottomCenter { 
     // Calculate the text size 

     if location == .center || location == .topCenter || location == .bottomCenter { 
     // Subtract half the text width from the x origin 
     let rect = CGRect(x:point.x-(rectSize.width/2), y:point.y-(rectSize.height/2), width:rectSize.width, height: rectSize.height) 
     text.draw(in: rect, withAttributes: textFontAttributes) 
     } else { 
     // Subtract the text width from the x origin 
     let rect = CGRect(x:point.x-rectSize.width, y:point.y-(rectSize.height/2), width:rectSize.width, height: rectSize.height) 
     text.draw(in: rect, withAttributes: textFontAttributes) 
     } 
    } else { 
     let rect = CGRect(x:point.x, y:point.y-(rectSize.height/2), width:rectSize.width, height: rectSize.height) 
     text.draw(in: rect, withAttributes: textFontAttributes) 
    } 

    let newImage = UIGraphicsGetImageFromCurrentImageContext() 
    UIGraphicsEndImageContext() 

    return newImage! 
    } 

    func selectPhotoFromCameraRoll(mediaType: String) { 
    imagePicker.sourceType = .photoLibrary 
    if mediaType == "Video" { 
     imagePicker.mediaTypes = [kUTTypeMovie as String] 
    } 
    newMedia = false 
    present(imagePicker, animated: true, completion: nil) 
    } 

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) { 
    if let mediaType = info[UIImagePickerControllerMediaType] as? String { 
     if mediaType.isEqual((kUTTypeImage as String)) { 
     if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage { 
      let width = pickedImage.size.width 
      let height = pickedImage.size.height 
      let location = Locations(rawValue: UserDefaults.standard.value(forKey: "location") as! String)! 
      var point = CGPoint(x: 0, y: 0) 
      switch location { 
      case .topLeft: 
      point = CGPoint(x: 30, y: 50) 
      case .topRight: 
      point = CGPoint(x: width - 30, y: 50) 
      case .bottomLeft: 
      point = CGPoint(x: 30, y: height - 50) 
      case .bottomRight: 
      point = CGPoint(x: width - 30, y: height - 50) 
      case .center: 
      point = CGPoint(x: width/2, y: height/2) 
      case .topCenter: 
      point = CGPoint(x: width/2, y: 50) 
      case .bottomCenter: 
      point = CGPoint(x: width/2, y: height - 50) 
      } 
      let savedFormat = UserDefaults.standard.value(forKey: "format") as! String 
      var date = Date() 
      if !currentDateBool { 
      date = UserDefaults.standard.value(forKey: "selectedDate") as! Date 
      } 
      let timestampText = getFormattedDateFromFormatType(formatType: savedFormat, date: date) as NSString 
      let timestampImage = textToImage(drawText: timestampText, inImage: pickedImage, atPoint: point) 
      if newMedia { 
      UIImageWriteToSavedPhotosAlbum(timestampImage, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil) 
      } else { 
      UIImageWriteToSavedPhotosAlbum(timestampImage, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil) 
      } 
     } 
     } else if mediaType.isEqual((kUTTypeMovie as String)) { 
     if let videoUrl = info[UIImagePickerControllerMediaURL] as? NSURL { 
      if let videoPath = videoUrl.relativePath { 
      if newMedia { 
       UISaveVideoAtPathToSavedPhotosAlbum(videoPath, nil, nil, nil) 
      } 
      } 
     } 
     } 
    } 
    dismiss(animated: true, completion: nil) 
    } 


    func image(_ image: UIImage, didFinishSavingWithError error: NSError?, contextInfo: UnsafeRawPointer) { 
    if let error = error { 
     // we got back an error! 
     let ac = UIAlertController(title: "Save error", message: error.localizedDescription, preferredStyle: .alert) 
     ac.addAction(UIAlertAction(title: "OK", style: .default)) 
     present(ac, animated: true) 
    } else { 
     let ac = UIAlertController(title: "Saved!", message: "Your altered image has been saved to your photos.", preferredStyle: .alert) 
     ac.addAction(UIAlertAction(title: "OK", style: .default)) 
     present(ac, animated: true) 
    } 
    } 

ответ

0

Вы обрабатываете фотографию в рулоне камеры, как если бы это был UIImage. Это не так.

Давайте рассмотрим наихудший сценарий. Предположим, у нас есть 12-мегапиксельная камера. Тогда ваш производный UIImage будет 4032x3024 пикселей. Теперь вы просите сделать графический контекст с масштабированием для разрешения экрана. Предположим, что экран этого устройства имеет 3-кратное разрешение. Затем вы запрашиваете графический контекст 12096x9072, который составляет 109734912. Это баллов. Чтобы сохранить данные о цвете, вы должны умножить это на то, сколько места занимает информация о цвете для каждой точки. Я не знаю, сколько это, но мы, безусловно, собираемся подняться еще на один порядок. В любом случае, как бы вы его не нарезали, это лодка памяти, о которой вы просите.

+0

Благодарим за ответ! У вас есть рекомендация относительно того, как я должен лечить изображение. – chickenparm

+0

Спасибо. Я буду смотреть в рамки фотографий, поскольку у меня нет большого опыта в этом. Можете ли вы указать мне в правильном направлении и сказать мне, если я вообще не буду использовать UIGraphicsBeginImageContextWithOptions? – chickenparm

+0

Извините, если я не согласен с моим вопросом. Пользователь имеет существующую фотографию в своем ролике. Пользователь хотел бы добавить текст даты/времени на фотографию. Единственное, что я хочу изменить, это добавить текст к фотографии. Мой код выше открывает рулон камеры, позволяя пользователю выбрать фотографию, добавить текст к фотографии и сохранить новую версию этой фотографии в рулоне камеры, которая включает в себя текст даты/времени на фотографии. – chickenparm

 Смежные вопросы

  • Нет связанных вопросов^_^