Search code examples
iosswiftuiimageviewuicollectionviewuiimagepickercontroller

UIImagePickerController presented from UIImageView inside UICollectionViewCell


I am having trouble loading a selected image from the UIImagePickerController inside a UIImageView. The UIImageView is presented on tap of a button that is inside a collectionViewCell. On tap of that button inside the collectionViewCell the UIImageView animates into view. On tap of that UIImageView the uiimagepicker is presented. The picker dismisses fine when an image is selected, but the image does not load inside the uiimageView on picker dismiss (the placeholder image remains and is not replaced by the selected image). No crashes or errors are occurring in my console. Thanks for any help!

UICollectionViewCell class - LoginCell

class LoginCell: UICollectionViewCell, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

lazy var createUsernameButton: UIButton = {
    let customButton = UIButton(type: .system)
    customButton.setTitle("Create Username", for: .normal)
    customButton.addTarget(self, action: #selector(animateIn), for: .touchUpInside)
    return customButton
}()

func animateIn() {
    addSubview(profileImageView)

    profileImageView.transform = CGAffineTransform.init(scaleX: 1.3, y: 1.3)
    profileImageView.alpha = 0

    UIView.animate(withDuration: 0.2) {
        self.profileImageView.alpha = 1
        self.profileImageView.transform = CGAffineTransform.identity
    }

}

    lazy var profileImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.image = UIImage(named: "avatar-bg-2x")
        imageView.addGestureRecognizer(UITapGestureRecognizer(target:self, action: #selector(handleSelectProfileImage)))
        imageView.isUserInteractionEnabled = true
        return imageView
    }()

    var loginController: LoginController?

    func handleSelectProfileImage() {
        guard let loginController = delegate as? LoginController else {
            return
        }
        loginController.showImagePicker()
    }

//.....
}

loginController class

class LoginController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, LoginControllerDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    weak var loginCollectionView: UICollectionView!
    var loginCell: LoginCell?

    func showImagePicker() {
        let picker = UIImagePickerController()
        picker.delegate = self
        picker.allowsEditing = true
        present(picker, animated: true, completion: nil)
    }

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

        var selectedImageFromImagePicker: UIImage?

        if let editedImage = info["UIImagePickerControllerEditedImage"] as? UIImage {
            selectedImageFromImagePicker = editedImage
        } else if let originalImage = info["UIImagePickerControllerOriginalImage"] as? UIImage {
            selectedImageFromImagePicker = originalImage
        }

        dismiss(animated: true, completion: {
            if let selectedImage = selectedImageFromImagePicker {
                self.loginCell?.profileImageView.image = selectedImage
                print("was dismissed")
            }
        })
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            let loginCell = collectionView.dequeueReusableCell(withReuseIdentifier: loginCellId, for: indexPath) as! LoginCell
            loginCell.delegate = self
            return loginCell
    }
// ...
}

Solution

  • I found the problem, you are not updating the image on the main thread. Try this:

    1. Change your code in the login controller class to match the code below.

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    
        var selectedImageFromImagePicker: UIImage?
    
        if let editedImage = info["UIImagePickerControllerEditedImage"] as? UIImage {
            selectedImageFromImagePicker = editedImage
        } else if let originalImage = info["UIImagePickerControllerOriginalImage"] as? UIImage {
            selectedImageFromImagePicker = originalImage
        }
    
        if let selectedImage = selectedImageFromImagePicker {
            DispatchQueue.main.async {
                self.loginCell?.profileImageView.image = selectedImage
                self.loginCollectionView.reloadData() //EDIT: add this new piece of code
            }
        }
    
        dismiss(animated: true, completion: nil)
    }
    
    var profileImage: UIImage?
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            let loginCell = collectionView.dequeueReusableCell(withReuseIdentifier: loginCellId, for: indexPath) as! LoginCell
            loginCell.delegate = self
            loginCell.profileImageView.image = profileImage != nil ? profileImage : UIImage(named: "avatar-bg-2x")
            return loginCell
    }
    

    2. Change this code in your loginCell class to match the code below.

    lazy var profileImageView: UIImageView = {
        let imageView = UIImageView()
        //removed line here
        imageView.addGestureRecognizer(UITapGestureRecognizer(target:self, action: #selector(handleSelectProfileImage)))
        imageView.isUserInteractionEnabled = true
        return imageView
    }()