iosuicollectionviewuikitdidselectrowatindexpathuicollectionviewdelegate

UICollectionView not selecting UICollectionViewCell


I am creating a app for iMessage only, searching images & populating a UICollectionView, the problem is that I cannot select the items. I need to be able to tap/select an item so it can be passed as the message layout & then send it but that part seems to be not working.

class MessagesViewController: MSMessagesAppViewController, UISearchBarDelegate {
    
    var images_results: [Result] = []
    
    let searchbar = UISearchBar()
    
    private var collectionView: UICollectionView?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        searchbar.delegate = self
        collectionView?.delegate = self
        
        view.addSubview(searchbar)
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .vertical
        layout.minimumLineSpacing = 6
        layout.minimumInteritemSpacing = 2
        let itemSize = view.frame.size.width/3.5
        layout.itemSize = CGSize(width: itemSize, height: itemSize)
        
        
        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        
        collectionView.register(ImageCollectionViewCell.self, forCellWithReuseIdentifier: ImageCollectionViewCell.identifier)
        collectionView.allowsSelection = true
        collectionView.dataSource = self
        view.addSubview(collectionView)
        collectionView.backgroundColor = .systemBackground
        self.collectionView = collectionView
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        searchbar.frame = CGRect(x: 10, y: view.safeAreaInsets.top, width: view.frame.size.width-20, height: 50)
        collectionView?.frame = CGRect(x: 7, y: view.safeAreaInsets.top+55, width: view.frame.size.width-15, height: view.frame.size.height-55)
        searchbar.placeholder = "Search Images"
    }
    
    func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
        requestPresentationStyle(.expanded)
        return true
    }
    
    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
        searchbar.resignFirstResponder()
        if let text = searchbar.text {
            images_results = []
            collectionView?.reloadData()
            fetchPhotos(query: text)
        }
    }
    
    
    func fetchPhotos(query: String) {
        let urlString = "https://api.url.com"
        guard let url = URL(string: urlString) else { return }
        let task = URLSession.shared.dataTask(with: url) { [weak self] data, _, error in
            guard let data = data, error == nil else { return }
            
            do {
                let jsonResult = try JSONDecoder().decode(APIResponse.self, from: data)
                print("GOT DATA")
                DispatchQueue.main.async {
                    self?.images_results = jsonResult.results
                    self?.collectionView?.reloadData()
                }
            } catch {
                print("WE GOT AN ERROR: \(error)")
            }
        }
        task.resume()
    }

    
    // MARK: - Conversation Handling
    
    override func willBecomeActive(with conversation: MSConversation) {
        fetchPhotos(query: ["animals", "fruits", "cars", "memes", "houses", "ocean"].randomElement()!)
        // Called when the extension is about to move from the inactive to active state.
        // This will happen when the extension is about to present UI.
        
        // Use this method to configure the extension and restore previously stored state.
    }
    
    override func didTransition(to presentationStyle: MSMessagesAppPresentationStyle) {
        if presentationStyle == .expanded {
            searchbar.becomeFirstResponder()
        }
        // Called after the extension transitions to a new presentation style.
    
        // Use this method to finalize any behaviors associated with the change in presentation style.
    }

}

extension MessagesViewController: UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        print(indexPath.item)
    }
}

extension MessagesViewController: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return images_results.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
        let imageURLString = images_results[indexPath.row].urls.thumb
        
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ImageCollectionViewCell.identifier, for: indexPath) as? ImageCollectionViewCell else {
            return UICollectionViewCell()
        }
        cell.configure(with: imageURLString)
        
        return cell
    }
}




//Custom Cell

class ImageCollectionViewCell: UICollectionViewCell {
    static let identifier = "ImageCollectionViewCell"
    private let imageView: UIImageView = {
        let imageView = UIImageView()
        imageView.clipsToBounds = true
        imageView.contentMode = .scaleAspectFill
        imageView.layer.cornerRadius = 4
        
        return imageView
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        contentView.addSubview(imageView)
    }
    
    required init? (coder: NSCoder) {
        fatalError ()
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        imageView.frame = contentView.bounds
    }
    
    override func prepareForReuse() {
    super.prepareForReuse()
        imageView.image = nil
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        print("awakefromnib")
        selectedItem()
    }
    
    func configure(with urlString: String) {
        guard let url = URL(string: urlString) else {
            return
        }
        URLSession.shared.dataTask(with: url) { [weak self] data, _, error in
            guard let data = data, error == nil else { return }
            DispatchQueue.main.async {
                let image = UIImage(data: data)
                self?.imageView.image = image
            }
        }.resume()
    }
    
    func selectedItem() {
        self.imageView.alpha = 0.7
    }
}


This is the only part that is not working:

extension MessagesViewController: UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        ...code for preparing image for message, right now I only have a print statement which is doing nothing ...
        
    }
}

I should be able to select an image to add to message but is not working


Solution

  • You are assigning the the delegate before the collection view was initialized.

    Move the collection view initializer to the view top of the viewDidLoad like so:

    override func viewDidLoad() {
        super.viewDidLoad()
        self.collectionView = UICollectiinView(…)
        self.collectionView?.delegate = self
    .
    .
    .
    }