I have the following code:
import UIKit
import Photos
import PhotosUI
private let reuseIdentifier = "Cell"
class CollectionVC: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var imageArray = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
grapPhotos()
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath as IndexPath)
let imageView = cell.viewWithTag(1) as! UIImageView
collectionView.allowsMultipleSelection = true
cell.layer.cornerRadius = 4
imageView.image = imageArray[indexPath.row]
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let cell = collectionView.cellForItem(at: indexPath) {
cell.layer.borderColor = #colorLiteral(red: 0.1411764771, green: 0.3960784376, blue: 0.5647059083, alpha: 1)
cell.layer.borderWidth = 5
}
}
override func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
if let cell = collectionView.cellForItem(at: indexPath) {
cell.layer.borderColor = #colorLiteral(red: 0.1411764771, green: 0.3960784376, blue: 0.5647059083, alpha: 1)
cell.layer.borderWidth = 0
}
}
func grapPhotos() {
let imgManager = PHImageManager.default()
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true
requestOptions.deliveryMode = .highQualityFormat
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
fetchOptions.predicate = NSPredicate(format: "mediaType = %d || mediaType = %d", PHAssetMediaType.image.rawValue, PHAssetMediaType.video.rawValue)
if let fetchResult : PHFetchResult = PHAsset.fetchAssets(with: fetchOptions) {
if fetchResult.count > 0 {
for i in 0..<fetchResult.count {
imgManager.requestImage(for: fetchResult.object(at: i), targetSize: CGSize(width: 200, height: 200), contentMode: .aspectFill, options: requestOptions, resultHandler: {
image, error in
self.imageArray.append(image!)
})
}
}
else {
self.collectionView?.reloadData()
print("No Photos")
}
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = collectionView.frame.width / 3 - 6
return CGSize(width: width, height: width)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 6.0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 6.0
}
}
I apologize it's a lot but I really have no idea where I am going wrong. This is all my code for my CollectionViewController, and then in storyboard I have a collection VC with an image in the one cell with a tag as 1 and then the one cell with an identifier as "Cell"
. The problem I am having is when I run the code on my phone, selecting one image ends up selecting others. For example: I select the first image, then I scroll down and another image is already selected. I did a little test and the first 21 images are almost unique. But then it's as if the image almost have the same id. Like selecting the first image also selects the 22nd image. By the way I am building a custom image picker.
There's more than one issue here, but the main problem you're complaining of is because you're forgetting that cells are reused. You need to configure cells in cellForItem
, not in didSelect
and didDeselect
.
When your didSelect
turns around and talks directly to a physical cell, it's doing totally the wrong thing. Instead, didSelect
and didDeselect
should talk to your data model, setting some property in the model's objects that says, the objects at these index paths should be considered selected, and the objects at these other index paths should not. Then reload the data.
Then, when cellForItem
comes along, it must configure its cell completely, either displaying its selected appearance or its unselected appearance, based on the data model and index path. That way, if a cell was in a previous selected row but is now reused in an unselected row, it has the desired unselected appearance.
In other words, only cellForItem
should think in terms of cells. Everyone else should think solely in terms of index path (or even better, in terms of some unique identifier associated with the data, but that's another story).