UICollectionView неправильно отображает элементы при добавлении элементов в разделы (Swift) - PullRequest
0 голосов
/ 08 декабря 2018

Мой UICollectionview работает нормально, когда я добавляю элементы в Раздел 1, и работает изменение раздела элемента с раздела 1 на раздел 2.Однако элементы начинают отображаться некорректно, если я выполняю следующие действия:

  1. Добавление элементов в раздел 1
  2. Перемещение элемента из раздела 1 в раздел 2
  3. Добавление нового элементав Раздел 1 (<-> здесь данные разбиваются, и представление коллекции начинает отображать один элемент дважды)

Я буду называть это «сценарием разбивки» ниже.

Я уже несколько дней пытаюсь понять причину этой проблемы.Я уверен, что это что-то базовое, но на моем нынешнем уровне знаний я не смог понять это.Я прекрасно реализую UICollectionviews с одним разделом, но я полагался на учебник Raywenderlich по UICollectionViews, чтобы выяснить, как реализовать несколько разделов, и я не чувствую себя полностью как дома с примером кода.Учебник, на который я опирался, находится здесь (хотя я думаю, что за платным доступом): (https://www.raywenderlich.com/6308-beginning-collection-views/lessons/16).

Вот описание того, как UICollectionview работает в моем приложении, и ключевые биты кода.


Когда приложение загружено, функция в datasource.swift запускает функцию, которая заполняет UICollectionview.

Это код:

    private func loadPicturesFromDisk() -> [Picture] {
    sections.removeAll(keepingCapacity: false)

    let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    let archiveURL = documentsDirectory.appendingPathComponent("pictures").appendingPathExtension("plist")
    let propertyListDecoder = PropertyListDecoder()

    if let retrievedPicturesData = try? Data(contentsOf: archiveURL), let decodedPictures = try? propertyListDecoder.decode(Array<Picture>.self, from: retrievedPicturesData) {
        for picture in decodedPictures {
            let pictureName = picture.pictureName
            print("The pictureName in loadPicturesFromDisk = \(pictureName), the pictureCategory is = \(picture.pictureCategory)")
            let pictureCategory = picture.pictureCategory


            if !sections.contains(pictureCategory) {
                sections.append(pictureCategory)
            }

            let newPicture = Picture(picture: pictureName, category: pictureCategory)
            pictures.append(newPicture)

        }

        print("Enumerating through pictures in loadPicturesFromDisk")
        enumerateThroughPictures(pictures: pictures)


        return pictures

    } else {
        return []
    }
}

Работает как задумано. Iтам есть пара функций печати, чтобы проверить, что загруженные данные выглядят правильно.

Теперь, когда UICollectionView вызывает эти данные в cellForItemAt в обычном сценарии, он работает нормально. Однако в сценарии разбивки (как определено выше)) данные не синхронизированы с данными в переменных массива источника данных. Вот пример того, как данные выглядят при загрузке и при вызове cellForItemAt в сценарии разбивки:

Данные при проверке при загрузке

Item(0: 1825 - No Category - indexPath = [0, 0] -      absoluteindexpath = 0
Item(1: 3630 - Filed - indexPath = [1, 0] -   absoluteindexpath = 3
Item(2: 8946 - No Category - indexPath = [0, 1] -   absoluteindexpath = 1
Item(3: 696 - No Category - indexPath = [0, 2] -   absoluteindexpath = 2

Данные при проверке в cellForItemAt: cellForItemAt обрабатывает изображение: 1825 - Нет категории, с indexPath из[0, 0] и absoluteindexpath из 0 cellForItemAt обрабатывает изображение: 3630 - Подано, с indexPath из [0, 1] и absoluteindexpath из 1 cellForItemAt обрабатывает изображение: 8946 - Без категории, с indexPath из [0, 2] и absoluteindexpathиз 2 cellForItemAt обрабатывает изображение: 3630 - заполнено, с indexPath [1, 0] и absoluteindexpath 3

Вот код для cellForItemAt:

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! PicAppCollectionViewCell

    cell.backgroundColor = UIColor.white
    cell.imageView.layer.borderColor = UIColor.black.cgColor
    cell.imageView.layer.borderWidth = 1

    // create a temporary picture object used to populate the view


    if let picture = dataSource.pictureForItemAtIndexPath(indexPath) {
        print("cellForItemAt is processing picture: \(picture.pictureName) - \(picture.pictureCategory), with indexPath of \(indexPath) and absoluteindexpath of \(dataSource.absoluteIndexForIndexPath(indexPath))")
        if debuggingMode == true {
            cell.photoIDLabel.isHidden = false
            cell.photoIDLabel.text = picture.pictureName
        }

        cell.imageView.image = getSavedImage(named: picture.pictureName)
        cell.isEditing = isEditing

    } else {
        print("did not find an image for indexpath: \(indexPath)")
    }

    return cell
}

Я использую UICollectionViewController,который в значительной степени опирается на dataSource.swift, полученный из учебника по RW.Я повторил весь приведенный ниже исходный код данных, поскольку в вызове функции много взаимозависимостей.

class DataSource {
private var pictures = [Picture]()
//private var immutablePictures = [Picture]()
private var sections : [String] = []

private var latestPictureID = 0

var count: Int {
    return pictures.count
}

var numberOfSections: Int {
    return sections.count
}

// MARK:- Public
init() {
    // add init code if needed
    pictures = loadPicturesFromDisk()
}

func newPicture(newPicture: Picture) -> IndexPath {

    for picture in pictures {
        if picture.pictureName == newPicture.pictureName {
            let randomName = Int.random(in: 0 ..< 10000)
            newPicture.pictureName = String(randomName)
        }
    }
    pictures.append(newPicture)
    print("The pictureName of the saved picture = \(newPicture.pictureName)")
    saveToFile(pictures: pictures)
    print("Launching array enumeration from newPicture before sort")
    enumerateThroughPictures(pictures: pictures)
    pictures.sort { $0.pictureCategory < $1.pictureCategory }
    print("Launching array enumeration from newPicture after sort sort")
    enumerateThroughPictures(pictures: pictures)
    return indexPathForPicture(newPicture)

}

func replacePictureAtIndexPath(picture: Picture, indexPath: IndexPath) {

    // make this update the collectionview and maybe it works

    pictures[absoluteIndexForIndexPath(indexPath)] = picture
    let pictureCategory = picture.pictureCategory

    if !sections.contains(pictureCategory) {
        sections.append(pictureCategory)
    }
    saveToFile(pictures: pictures)
    print("Launching array enumeration from replacePictureAtIndexPath")
    enumerateThroughPictures(pictures: pictures)
    //pictures.sort { $0.pictureCategory < $1.pictureCategory }
}

func enumerateThroughPictures(pictures: [Picture]) {
    print("Enumerating through pictures.array:")
    var index = 0
    for picture in pictures {
        print("Item(\(index): \(picture.pictureName) - \(picture.pictureCategory) - indexPath = \(indexPathForPicture(picture)) - absoluteindexpath = \(absoluteIndexForIndexPath(indexPathForPicture(picture)))")
        index += 1
    }
}

func deleteItemsAtIndexPaths(_ indexPaths: [IndexPath]) {
    var indexes = [Int]()
    for indexPath in indexPaths {
        indexes.append(absoluteIndexForIndexPath(indexPath))
    }
    var newPictures = [Picture]()
    for (index, picture) in pictures.enumerated() {
        if !indexes.contains(index) {
            newPictures.append(picture)
        }
    }
    pictures = newPictures
}

func movePictureAtIndexPath(_ indexPath: IndexPath, toIndexPath newIndexPath: IndexPath) {
    if indexPath == newIndexPath {
        print("Returning from movePicture as indexPath and newIndexPath were the same")
        return
    }
    let index = absoluteIndexForIndexPath(indexPath)
    let currentPicture = pictures[index]
    currentPicture.pictureCategory = sections[newIndexPath.section]
    let newIndex = absoluteIndexForIndexPath(newIndexPath)
    print("About to remove picture at : \(index)")

    pictures.remove(at: index)
    print("About to add picture at : \(newIndex)")
    pictures.insert(currentPicture, at: newIndex)
}

func indexPathForPicture(_ picture: Picture) -> IndexPath {
    let section = sections.index(of: picture.pictureCategory)!
    var item = 0
    for (index, currentPicture) in picturesForSection(section).enumerated() {
        if currentPicture === picture {
            item = index
            break
        }
    }
    return IndexPath(item: item, section: section)
}

func numberOfPicturesInSection(_ index: Int) -> Int {
    let currentPictures = picturesForSection(index)
    return currentPictures.count
}

func pictureForItemAtIndexPath(_ indexPath: IndexPath) -> Picture? {
    if indexPath.section > 0 {
        let currentPictures = picturesForSection(indexPath.section)
        return currentPictures[indexPath.item]
    } else {
        return pictures[indexPath.item]
    }
}

func titleForSectionAtIndexPath(_ indexPath: IndexPath) -> String? {
    if indexPath.section < sections.count {
        return sections[indexPath.section]
    }
    return nil
}


// MARK:- Private


private func loadPicturesFromDisk() -> [Picture] {
    sections.removeAll(keepingCapacity: false)

    let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    let archiveURL = documentsDirectory.appendingPathComponent("pictures").appendingPathExtension("plist")
    let propertyListDecoder = PropertyListDecoder()

    if let retrievedPicturesData = try? Data(contentsOf: archiveURL), let decodedPictures = try? propertyListDecoder.decode(Array<Picture>.self, from: retrievedPicturesData) {
        for picture in decodedPictures {
            let pictureName = picture.pictureName
            print("The pictureName in loadPicturesFromDisk = \(pictureName), the pictureCategory is = \(picture.pictureCategory)")
            let pictureCategory = picture.pictureCategory


            if !sections.contains(pictureCategory) {
                sections.append(pictureCategory)
            }

            let newPicture = Picture(picture: pictureName, category: pictureCategory)
            pictures.append(newPicture)

        }

        print("Enumerating through pictures in loadPicturesFromDisk")
        enumerateThroughPictures(pictures: pictures)


        return pictures

    } else {
        return []
    }
}

private func saveToFile(pictures: [Picture]) {
    let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    let archiveURL = documentsDirectory.appendingPathComponent("pictures").appendingPathExtension("plist")
    let propertyListEncoder = PropertyListEncoder()
    let encodedPictures = try? propertyListEncoder.encode(pictures)

    try? encodedPictures?.write(to: archiveURL, options: .noFileProtection)

}

func absoluteIndexForIndexPath(_ indexPath: IndexPath) -> Int {
    var index = 0
    for i in 0..<indexPath.section {
        index += numberOfPicturesInSection(i)
    }
    index += indexPath.item
    return index
}

private func picturesForSection(_ index: Int) -> [Picture] {
    let section = sections[index]
    let picturesInSection = pictures.filter { (picture: Picture) -> Bool in
        return picture.pictureCategory == section
    }
    return picturesInSection
}

}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...