Почему мое приложение падает на iOS 10 при многократном представлении и использовании UIImagePickerControllers?

Приложение, которое мы разработали несколько лет назад, начало сбой с момента появления iOS 10. Приложение повторно представляет UIImagePickerControllers, чтобы позволить пользователю записывать несколько фотографий объекта. После этого 40 раз, приложение выйдет из строя. Это воспроизводимо на всех устройствах, на которых мы тестировали, но не произошло до внедрения iOS 10. У нас есть файлы NSCameraUsageDescription и NSPhotoLibraryUsageDescription в файле Info.plist.

Я создал минимальное примерное приложение, которое демонстрирует проблему. Здесь код, который в конечном итоге приводит к сбою:

- (IBAction) cameraPressed:(id) sender {
    self.picker = [[UIImagePickerController alloc] init];
    self.picker.sourceType =  UIImagePickerControllerSourceTypeCamera;
    self.picker.delegate = self;
    self.picker.allowsEditing = NO;
    [self presentViewController:self.picker animated:YES completion:nil];
}

Когда пользователь повторно использует кнопку камеры, которая подключена к этому IBAction, она в конечном итоге начинает замедляться (презентация сборщика начинается дольше) и, в конечном счете, сбой (обычно после 50+ использования камеры). Журнал сбоев не создается, хотя, когда он подключен к Xcode, в консоли, ведущей к сбою, выводится такой вывод:

2016-11-04 20:30:11.884984 WLPBeta[2747:275474] [MC] Invalidating cache
2016-11-04 20:30:11.890776 WLPBeta[2747:273019] [MC] Reading from public effective user settings.
2016-11-04 20:30:13.017608 WLPBeta[2747:275091] [MC] Invalidating cache
2016-11-04 20:30:13.018312 WLPBeta[2747:273019] [MC] Reading from public effective user settings.
2016-11-04 20:30:19.271720 WLPBeta[2747:276311] [MC] Invalidating cache
2016-11-04 20:30:19.279462 WLPBeta[2747:273019] [MC] Reading from public effective user settings.
2016-11-04 20:32:08.229294 WLPBeta[2747:278515] [MC] Invalidating cache
2016-11-04 20:32:08.273941 WLPBeta[2747:273019] [MC] Reading from public effective user settings.
2016-11-04 20:32:09.335711 WLPBeta[2747:278514] [MC] Invalidating cache
2016-11-04 20:32:09.342161 WLPBeta[2747:273019] [MC] Reading from public effective user settings.
2016-11-04 20:32:14.193376 WLPBeta[2747:278515] [MC] Invalidating cache
2016-11-04 20:32:14.213902 WLPBeta[2747:273019] [MC] Reading from public effective user settings.
2016-11-04 20:32:47.944657 WLPBeta[2747:275091] [MC] Invalidating cache
2016-11-04 20:32:47.972053 WLPBeta[2747:273019] [MC] Reading from public effective user settings.
2016-11-04 20:32:48.550934 WLPBeta[2747:279485] [MC] Invalidating cache
2016-11-04 20:32:48.575065 WLPBeta[2747:273019] [MC] Reading from public effective user settings.
2016-11-04 20:32:50.855308 WLPBeta[2747:279485] [MC] Invalidating cache
2016-11-04 20:32:50.856329 WLPBeta[2747:273019] [MC] Reading from public effective user settings.
2016-11-04 20:32:52.201535 WLPBeta[2747:275091] [GatekeeperXPC] Connection to assetsd was interrupted or assetsd died

Я также опубликовал отчет об ошибке для Apple и добавил его для открытия радара: http://www.openradar.me/radar?id=4941109843197952

Кто-нибудь столкнулся с этой проблемой? Есть ли исправление, которое позволит нам пройти мимо этого без перекомпиляции приложения с помощью Xcode 8? К сожалению, мы используем сторонние библиотеки, которые еще не готовы для Xcode 8 и iOS 10 SDK, поэтому мы все еще создаем приложение с помощью Xcode 7.3.1.

EDIT: здесь ссылка на репозиторий Github, содержащий пример приложения, которое может быть использовано для демонстрации проблемы.

https://github.com/lolay/ImagePickerTest

РЕДАКТИРОВАТЬ 2: Если я изменю код, чтобы я выделил и инициализировал сборщик в viewDidLoad, он все равно падает после примерно такого же количества использования кнопки камеры.

- (void)viewDidLoad {
    [super viewDidLoad];
    self.picker = [[UIImagePickerController alloc] init];
    self.picker.sourceType =  UIImagePickerControllerSourceTypeCamera;
    self.picker.allowsEditing = NO;
}

- (IBAction) cameraPressed:(id) sender {
    [self presentViewController:self.picker animated:YES completion:nil];
}

Ответ 1

Ваш UIImagePickerController определяется как STRONG.

Пожалуйста, измените его на слабый или убедитесь, что объект равен нулю перед тем, как будет уничтожен вид.

Ответ 2

Попробуйте этот код.

- (IBAction) cameraPressed:(id) sender {
   if (self.picker == nil){
      self.picker = [[UIImagePickerController alloc] init];
   }

    self.picker.sourceType =  UIImagePickerControllerSourceTypeCamera;
    self.picker.delegate = self;
    self.picker.allowsEditing = NO;
    [self presentViewController:self.picker animated:YES completion:nil];
}

Ответ 3

Вы пытались объявить переменную Imagepicker внутри функции cameraPressed()

- (IBAction) cameraPressed:(id) sender {
   UIImagePickerController *picker = [[UIImagePickerController alloc] init];
    picker.sourceType =  UIImagePickerControllerSourceTypeCamera;
    picker.delegate = self;
    picker.allowsEditing = NO;
    [self presentViewController:self.picker animated:YES completion:nil];
}

Ответ 4

Вам нужно явно отклонить UIImagePickerController, хотя это, кажется, делает это автоматически. Вероятно, он сохранит контроллер просмотра, если вы этого не сделаете, что приведет к проблемам с памятью.

Из Документация UIImagePickerControllerDelegate:

Если вы установили, что для выбора изображений отображается свойствоCameraControls для NO и предоставить свои собственные элементы управления, вы можете делать несколько снимков перед увольнением интерфейса выбора изображений. Однако, если вы установите свойство YES, ваш делегат должен отклонить интерфейс выбора изображения после того, как пользователь сделает одно изображение или отменяет операцию.

По умолчанию это свойство равно YES, поэтому вам нужно уволить.

Используйте что-то похожее на следующее:

- (IBAction) cameraPressed:(id) sender {
    UIImagePickerController* picker = [[UIImagePickerController alloc] init];
    picker.sourceType =  UIImagePickerControllerSourceTypeCamera;
    picker.allowsEditing = NO;
    picker.delegate = self;
    [self presentViewController:picker animated:YES completion:nil];
}

- (void) imagePickerController:(UIImagePickerController *)picker
    didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
{
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (void) imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
    [self dismissViewControllerAnimated:YES completion:nil];
}