0

This is a follow-up from this question. Thanks so much to @rmaddy and @LeoDabus for your help thus far!

The Good: my addImage button gets me the correct image in collectionView the first time I pick an image.

The Bad: the second time I select an image, it changes both cells to the 2nd image. By the third/fourth/etc times I try to addImage, the image is always the same across each cell no matter what image I choose (i.e. 1st try: image1, 2nd try: image 2, image 2, 3rd try: image 2, image 2, image 2).

My question: How do I make the image chosen populate the incremental cells correctly?

Here is my code:

Get the number of cells in the collectionView from count

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

    let fileManager = FileManager.default
    let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
    let dirContents = try? fileManager.contentsOfDirectory(atPath: documentsPath)
    let count = dirContents?.count
    return count!
        }

Populate the views

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

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! myCell
    let fileManager = FileManager.default
    let documentDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
    let directoryContents = try! fileManager.contentsOfDirectory(at: documentDirectory, includingPropertiesForKeys: nil)

    for imageURL in directoryContents where imageURL.pathExtension == "jpeg" {
        if let image = UIImage(contentsOfFile: imageURL.path) {
            cell.myImageView.image = image //[indexPath.row] **need "image" to be an array so can assign to indexPath.row
        } else {
            fatalError("Can't create image from file \(imageURL)")
        }
    }
    return cell
}

addMyImage button opens the imagePicker

@IBAction func addMyImage(_ sender: UIButton) {

//imagePickerController stuff
}

Save the imageURL in File Manager

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

if let imageURL = info[UIImagePickerControllerImageURL] as? URL {

    let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    do {
        try FileManager.default.moveItem(at: imageURL.standardizedFileURL, to: documentDirectory.appendingPathComponent(imageURL.lastPathComponent))
        collectionView.reloadData()
    } catch {
        print(error)
    }
}

After lots of googling, I think the problem is I haven't assigned [indexPath.row] to an array in my cellForItemAt IndexPath, so while the documentDirectory gets updated with the URL, each new cell is not being pointed to the correct URL. Unfortunately, I'm calling a specific URL in that function

for imageURL in directoryContents where imageURL.pathExtension == "jpeg" 

so I am not sure how to assign the indexPath.row...

Would appreciate any help!

1
  • Instead of looping in cellForItemAt, use indexPath.item to index into the directoryContents array to select the imageURL. So use let imageURL = directoryContents[indexPath.item]. Note: indexPath.item is the same as indexPath.row but the first is for UICollectionViews and the second is for UITableViews. Commented Jan 9, 2018 at 8:50

1 Answer 1

3

You are iterating the directoryContents

for imageURL in directoryContents where imageURL.pathExtension == "jpeg" {
    if let image = UIImage(contentsOfFile: imageURL.path) {
        cell.myImageView.image = image //[indexPath.row] **need "image" to be an array so can assign to indexPath.row
    } else {
        fatalError("Can't create image from file \(imageURL)")
    }
}

that's why you only get the last image on all the cells.

What you should do is fetch the directory contents and store it in an array variable (e.g. directoryContentsArray = self.fetchDirectoryContents())

make a function similar to this, and call it on viewDidLoad: this will populate your array.

func fetchDirectoryContents() {
    let fileManager = FileManager.default
    let documentDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
    let directoryContents = try! fileManager.contentsOfDirectory(at: documentDirectory, includingPropertiesForKeys: nil)

    self.directoryContentsArray = directoryContents
    self.tableView.reloadData() 
}

Then use the array count for numberOfRows and for the datasource as well. your current design is actually bad right now since you're always calling for FileManager in all your tableView methods

Now, after adding an image successfully and saving it, you will repopulate your array (or you can actually just append it to your existing array)

EDIT: So in your cellForItem

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

    if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as? myCell {
       let imageFile = self.directoryContentsArray[indexPath.item]
       if let imageURL = imageFile.path, 
          imageFile.pathExtension == "jpeg",
          let image = UIImage(contentsOfFile: imageURL) {
          cell.imageView.image = image
       } else {
          fatalError("Can't create image from file \(imageFile)")
       }
    return cell
    }
return UICollectionViewCell()
}
Sign up to request clarification or add additional context in comments.

14 Comments

This is good advice. Add information to your answer about how to use indexPath.item in cellForItemAt to get the proper image.
Really appreciate the comments vacawama and @AceRivera. I get your point that I can create a func fetchDirectoryContents() that gets an array of URLs from the documentsDirectory. I'm not sure how to then use this array to populate the cells correctly... do you mind trying to explain a bit more for me?
create a local variable "directoryContentsArray" save the directoryContents there you are fetching with fileManager.
oh and btw, make sure you're only adding images with jpeg to that specific directory.
A professional touch would be to insert a row to the collectionView instead of calling reloadData and reloading all of the images again just because you added one.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.