当我向第1节添加项目并将项目的节从第1节更改为第2节时,我的UICollectionview可以正常工作。但是,如果执行以下操作,则项目开始显示不正确:
以下将其称为“故障场景”。
几天来,我一直在努力理解这个问题的原因。我确信这是基础知识,但以目前的知识水平,我仍然无法弄清楚。我可以用一个部分来实现UICollectionviews,但是我依靠UICollectionViews上的Raywenderlich教程来弄清楚如何实现多个部分,并且我对示例代码并不完全满意。我依赖的教程在此处(尽管我认为是在付费专区后面):(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 []
}
}
这按预期工作。我有几个打印功能,可以检查加载的数据看起来是否正确。
现在,在正常情况下,当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,它很大程度上依赖于RW教程中的dataSource.swift。我复制了下面的所有数据源代码,因为函数调用之间存在很多相互依赖关系。
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
}
}