Приложение iOS аварийно завершает работу при выборе нескольких видео из библиотеки фотографий — предупреждение о памяти

Мое приложение аварийно завершает работу, когда я выбираю несколько видео (1+ минут каждое) из библиотеки фотографий из-за предупреждения о памяти. Я пытаюсь сжать видео, но все равно та же проблема, хотя код сжатия работает правильно. Я хочу, чтобы мое приложение выбирало 5 видео одновременно и отправляло их в чат. Whatsapp позволяет пользователю выбрать 30 видео и отправить их в чат, но мое приложение падает из-за проблем с памятью только после 3 видео. Я использую библиотеку AssetsPickerViewController для выбора нескольких изображений/видео.

func assetsPicker(controller: AssetsPickerViewController, selected assets: [PHAsset]) {
    self.dismiss(animated: true, completion: nil)
    
    var isImages = false
    var mediaData: [Data] = []
    let imageManager = PHCachingImageManager.default()
    DispatchQueue.main.async {
        self.appDelegate.helper.showHUD(withMessage: "Preparing media", withObject: self)
    }
    autoreleasepool {
        for selectedAsset in assets {
            if selectedAsset.mediaType == .image {
                isImages = true
                let option = PHImageRequestOptions()
                option.isSynchronous = true
                option.isNetworkAccessAllowed = true
                
                imageManager.requestImageData(for: selectedAsset, options: option) { (assetData, assetDataUTI, assetOrientation, assetInfo) in
                    if let data = assetData {
                        if let image = UIImage(data: data)?.upOrientation(), let finalData = image.jpegData(compressionQuality: 0.5) {
                            if let newData = ImageHelper.removeExifData(data: finalData as NSData) {
                                mediaData.append(newData as Data)
                                self.checkFileStatus(mediaCount: mediaData.count, assetsCount: assets.count, data: mediaData, isImages: isImages)
                            } else {
                                mediaData.append(finalData)
                                self.checkFileStatus(mediaCount: mediaData.count, assetsCount: assets.count, data: mediaData, isImages: isImages)
                            }
                        } else {
                            mediaData.append(data)
                            self.checkFileStatus(mediaCount: mediaData.count, assetsCount: assets.count, data: mediaData, isImages: isImages)
                        }
                    }
                }
            } else if selectedAsset.mediaType == .video {
                let options: PHVideoRequestOptions = PHVideoRequestOptions()
                options.isNetworkAccessAllowed = true
                options.deliveryMode = .fastFormat
                self.convertVideo(phAsset: selectedAsset) { (data) in
                    if let finalData = data {
                        mediaData.append(finalData)
                        self.checkFileStatus(mediaCount: mediaData.count, assetsCount: assets.count, data: mediaData, isImages: isImages)
                    } else {
                        
                    }
                    
                }
            }
        }
    }
}

func compressVideo(inputURL: URL, outputURL: URL, handler:@escaping (_ exportSession: AVAssetExportSession?)-> Void) {
   let urlAsset = AVURLAsset(url: inputURL, options: nil)
   guard let exportSession = AVAssetExportSession(asset: urlAsset, presetName: AVAssetExportPresetMediumQuality) else {
       handler(nil)

       return
   }
   exportSession.outputURL = outputURL
   exportSession.outputFileType = AVFileType.mp4
   exportSession.shouldOptimizeForNetworkUse = true
   exportSession.exportAsynchronously { () -> Void in
       handler(exportSession)
   }

}


person Priyanka    schedule 21.12.2020    source источник
comment
отредактируйте свой вопрос и опубликуйте свой код   -  person Leo Dabus    schedule 21.12.2020
comment
@LeoDabus Отредактированный вопрос   -  person Priyanka    schedule 21.12.2020
comment
переместите свой autoreleasepool { внутри вашего цикла. Поэтому измените autoreleasepool { for selectedAsset in assets { на for selectedAsset in assets { autoreleasepool {   -  person Leo Dabus    schedule 21.12.2020
comment
@LeoDabus Я пытался, но все та же проблема. Я хочу, чтобы мое приложение выбирало максимум 5 видео. Я могу выбрать 5 видео, только если их продолжительность меньше 1 минуты. В противном случае мое приложение аварийно завершает работу из-за проблем с памятью.   -  person Priyanka    schedule 21.12.2020
comment
это происходит, если вы выбираете одно видео?   -  person Leo Dabus    schedule 21.12.2020
comment
@LeoDabus Нет, даже если я выберу 5 видео, оно не вылетит, если видео длится 30-45 секунд каждое. Он вылетает, если я выбираю 5 видео по 1+ минуте каждое. Для видео продолжительностью более 1 минуты оно не падает до 3 видео.   -  person Priyanka    schedule 21.12.2020
comment
Обратите внимание, что вы должны выполнять синхронные запросы только из фонового потока.   -  person Leo Dabus    schedule 21.12.2020
comment
Кстати, ИМО, ваша проблема здесь mediaData.append(finalData). Вместо того, чтобы загружать все ваши видеоданные в память, вы должны создать для них временные файлы.   -  person Leo Dabus    schedule 21.12.2020
comment
@LeoDabus Пожалуйста, предложите, как мне это сделать. Не могли бы вы опубликовать код или отредактировать мой код.   -  person Priyanka    schedule 21.12.2020
comment
Вы не знаете, как записать данные на диск?   -  person Leo Dabus    schedule 21.12.2020
comment
@LeoDabus Когда я сжимаю видео, оно уже сохраняется во временном хранилище после него.   -  person Priyanka    schedule 21.12.2020
comment
Зачем вам массив данных? Как я уже упоминал, вы не должны загружать все свои видео в память.   -  person Leo Dabus    schedule 21.12.2020
comment
@LeoDabus Мне нужно отправить их на другой контроллер представления, где пользователь пишет подпись к видео и отправляет на сервер.   -  person Priyanka    schedule 21.12.2020
comment
Просто создайте каталог в каталоге поддержки вашего приложения или используйте каталог кеша, запишите туда свои данные и передайте URL-адреса.   -  person Leo Dabus    schedule 21.12.2020
comment
Вы также можете просто загрузить содержимое каталога на другой контроллер представления.   -  person Leo Dabus    schedule 21.12.2020
comment
@LeoDabus Я пытался прокомментировать эту строку mediaData.append(finalData), чтобы проверить, работает ли только выбор видео, но проблема с памятью все та же.   -  person Priyanka    schedule 21.12.2020
comment
Убедитесь, что ваш обработчик завершения обращается к массиву mediaData синхронизированным образом. Поскольку не гарантируется, что обработчики завершения будут вызываться в той же очереди, у вас могут возникнуть также проблемы с гонкой данных. То, как вы это делаете, то есть получение видео в виде объекта данных и сохранение их в массив, не рекомендуется, поскольку для этого требуется выделить огромный объем памяти. Вам лучше использовать файловые потоки и, следовательно, гораздо более сложный подход.   -  person CouchDeveloper    schedule 21.12.2020