Сообщение от отладчика: прекращено из-за проблемы с памятью в массиве Xcode 10.1 ... image? - PullRequest
2 голосов
/ 25 марта 2019

Я новый разработчик, и мое приложение имеет вид коллекции (с горизонтальной прокруткой) с 32 изображениями.Я создал массивы для изображений, меток и текста.Когда я попадаю в конец списка, приложение вылетает.Независимо от размера моих изображений я получаю «Сообщение от отладчика: прекращено из-за проблемы с памятью».Я использовал инструмент Instruments, который, кажется, указывает на то, что изображения не выпускаются.

Я пытался изменить размеры изображений, но безуспешно.Я также попытался использовать autoreleasepool, который я мог использовать неправильно.

Мой массив изображений настроен так с изображениями 1-32.

let imageArray = [UIImage (named: "1"), UIImage (named: "2"), etc.]

Вот мой collectionView:

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return self.imageArray.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MainCollectionViewCell", for: indexPath) as! MainCollectionViewCell

    cell.imgImage.image = imageArray [indexPath.row]
    cell.lblImageName.text = nameArray [indexPath.row]

    return cell
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

    let mainStoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
    let desVC = mainStoryboard.instantiateViewController(withIdentifier: "DetailViewController") as! DetailViewController


    desVC.image = imageArray[indexPath.row]!
    desVC.name = nameArray[indexPath.row]
    desVC.text = textArray[indexPath.row]

    self.navigationController?.pushViewController(desVC, animated: true)
}

Ответы [ 2 ]

3 голосов
/ 25 марта 2019

Несколько замечаний:

  1. Не загружайте изображения заранее. Загружайте их по мере необходимости.

    Таким образом, вместо imageArray, который является массивом UIImage, сохраните массив имен изображений, например,

    let imageNames = ["1", "2", ...]
    

    Затем, в cellForItemAt, вы можете создать экземпляр UIImage для этой конкретной ячейки, например,

    cell.imgImage.image = UIImage(named: imageNames[indexPath.row])
    
  2. Помните, что изображения занимают много памяти. Независимо от размера JPG или PNG, когда они используются в пользовательском интерфейсе, они обычно используют 4 байта на пиксель. Итак, рассмотрим изображение размером 2000 × 2000 пикселей, размер JPG которого может составлять только 100 КБ: даже при использовании в крошечном изображении размером 100 × 100 все изображение будет сжато и в этом случае будет занимать 16 МБ! Поэтому убедитесь, что ваши изображения имеют размеры, соответствующие вашему интерфейсу. Например. если ваше изображение имеет вид 100 × 100, то у вас может быть три варианта изображения: одно для 100 × 100, для устройств без сетчатки, одно для 200 × 200 для устройств с сетчаткой @ 2x и для 300 ×. 300 для @ 3х устройств.

  3. Относительно памяти, которая не освобождается, три пункта:

    • Исключите использование массива UIImage, и это не позволит приложению удерживать все изображения в памяти, даже если они могут и не понадобиться в любой момент времени (см. Пункт 1 выше). ,

    • Убедитесь, что у вас нет сильного эталонного цикла. Поэтому отклоните рассматриваемый контроллер представления, а затем используйте «График отладочной памяти» и убедитесь, что контроллер представления фактически был отклонен.

    • Когда вы используете UIImage(named:), изображения будут кэшироваться, и память не будет освобождена, пока не возникнет нехватка памяти (например, предупреждение о памяти). Обычно UIImage(named:) кэширование работает (когда вы исправляете вышеуказанные проблемы), но если это не так, используйте UIImage(contentsOfFile:). Поскольку документация UIImage(named:) предупреждает нас:

      Этот метод ищет в системных кэшах объект изображения с указанным именем и возвращает тот вариант изображения, который лучше всего подходит для основного экрана. Если соответствующий объект изображения еще не находится в кэше, этот метод находит и загружает данные изображения с диска или из доступного каталога активов, а затем возвращает полученный объект.

      Система может очищать кэшированные данные изображения в любое время, чтобы освободить память. Очистка происходит только для изображений, которые находятся в кэше, но в настоящее время не используются ...

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

2 голосов
/ 25 марта 2019

Сохранить имена изображений в массиве, а в источнике данных получить имя изображения из массива и построить изображение.

let imageArray = ["1", "2"]

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MainCollectionViewCell", for: indexPath) as! MainCollectionViewCell

    cell.imgImage.image = UIImage (named: imageArray [indexPath.row])
    cell.lblImageName.text = nameArray [indexPath.row]

    return cell
}

Примечание. Если проблема с памятью не устранена, возможно, она загружается разрешение изображений, лучше изменить их размер в фоновом потоке и назначить к изображению в главной теме.

...