Home > Back-end >  Unable to send the data form Collection to Another View Controller
Unable to send the data form Collection to Another View Controller

Time:05-24

I am new to swift . I am trying to send the data from collection view to another view controller when user click the collection view cell. But the problem is when I click the cell it not going to next view controller with label and image properties instated it showing blank screen.

Here is the network Manager code .

    import Foundation
    
    protocol NetworkManagerProtocol{
        func getModel<T: Codable>(_ model: T.Type, from url: String, completion: @escaping (Result<T, NetworkError>) -> Void)
        func getData(from url: String, completion: @escaping (Result<Data, NetworkError>) -> Void)
      
    }
    class NetworkManager:  NetworkManagerProtocol{
        
        func getModel<T: Codable>(_ model: T.Type, from url: String, completion: @escaping (Result<T, NetworkError>) -> Void) {
            
            guard let url = URL(string: url) else {
                completion(.failure(.badURL))
                return
            }
            
            URLSession.shared.dataTask(with: url) { data, response, error in
                if let data = data {
                    do {
                        let response = try JSONDecoder().decode(model, from: data)
                        completion(.success(response))
                    } catch let error {
                        completion(.failure(.other(error)))
                    }
                }
                
                if let error = error {
                    completion(.failure(.other(error)))
                }
            }
            .resume()
            
        }
        
        func getData(from url: String, completion: @escaping (Result<Data, NetworkError>) -> Void) {
            guard let url = URL(string: url) else {
                completion(.failure(.badURL))
                return
            }
            
            URLSession.shared.dataTask(with: url) { data, response, error in
                if let data = data {
                    completion(.success(data))
                }
                
                if let error = error {
                    completion(.failure(.other(error)))
                }
            }
            .resume()
        }

}

Here is the view model .

import Foundation

class PhotoViewModel {
    
    
   private let networkManager: NetworkManagerProtocol
    
   
    var  hits = [Hit]()
    private var cache = [String: Data]()
   // var net  = NetworkManager()
     weak var delegate: PhotoViewable?
    
    
    init(networkManager: NetworkManagerProtocol) {
        self.networkManager = networkManager
       
    }
    
    var rows: Int {
        return hits.count
    }
    
    func fecthPhotoRecord(){
        
        let networkUrl = NetworkURLs.baseURL
        networkManager.getModel(Photo.self, from: networkUrl) { [weak self] result in
            switch result{
            case.success(let photo):
                self?.hits = photo.hits
                self?.delegate?.refreshUI()
            case.failure(let error):
                print(error)
               self?.delegate?.showError()
            }
        
        }
    }
    func downloadImage(row: Int, completion: @escaping (Data) -> Void) {
        
        let hit = hits[row]
        let hitpath = hit.previewURL
        
        if let data = cache[hitpath] {
            completion(data)
            return
        }
        
        networkManager
            .getData(from: hitpath) { result in
                switch result {
                case .success(let data):
                    self.cache[hitpath] = data
                    DispatchQueue.main.async {
                        completion(data)
                    }
                case .failure(let error):
                    print(error)
                }
            }
    }
}

Here is the view controller with collection cell ..

class PhotoViewController: UIViewController {

    var viewModel : PhotoViewModel
    
    init(viewModel : PhotoViewModel) {
        self.viewModel = viewModel
        super.init(nibName: nil, bundle: nil)
    }
    
    private let collectionView: UICollectionView = {
           let viewLayout = UICollectionViewFlowLayout()
           let collectionView = UICollectionView(frame: .zero, collectionViewLayout: viewLayout)
           collectionView.backgroundColor = .white
           return collectionView
       }()
    
    private enum LayoutConstant {
           static let spacing: CGFloat = 16.0
           static let itemHeight: CGFloat = 230.0
       }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private var activityIndicator: UIActivityIndicatorView = {
       let activityIndicator = UIActivityIndicatorView()
       activityIndicator.translatesAutoresizingMaskIntoConstraints = false
       return activityIndicator
   }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        setupViews()
        setupLayouts()
        viewModel.fecthPhotoRecord()
        
        collectionView.delegate = self
        collectionView.dataSource = self
        viewModel.delegate = self
        view.backgroundColor = .lightGray
        collectionView.reloadData()
      

    }
    
    private func setupViews() {
            view.backgroundColor = .white
            view.addSubview(collectionView)

            collectionView.dataSource = self
            collectionView.delegate = self
            collectionView.register(PhotoCollectionViewCell.self, forCellWithReuseIdentifier: PhotoCollectionViewCell.identifier)
        }
    private func setupLayouts() {
           collectionView.translatesAutoresizingMaskIntoConstraints = false

           // Layout constraints for `collectionView`
           NSLayoutConstraint.activate([
               collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
               collectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
               collectionView.leftAnchor.constraint(equalTo: view.leftAnchor),
               collectionView.rightAnchor.constraint(equalTo: view.rightAnchor)
           ])
       }
    
}

extension PhotoViewController: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return viewModel.hits.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PhotoCollectionViewCell.identifier, for: indexPath) as! PhotoCollectionViewCell
        
        let row = indexPath.row
        let hits  = viewModel.hits[indexPath.row]
        cell.configureCell(tagName: hits.tags)
        cell.configureImageCell(row: row, viewModel: viewModel)
        
        return cell
    }
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        collectionView.deselectItem(at: indexPath, animated: false)
        let detailVC = PhtotoDetailsViewController()
        detailVC.rowSelected = indexPath.row
        let navController = UINavigationController(rootViewController: detailVC)
        navController.modalPresentationStyle = .fullScreen
        present(navController, animated: true, completion: nil)
    }
}

extension PhotoViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

        let width = itemWidth(for: view.frame.width, spacing: LayoutConstant.spacing)

        return CGSize(width: width, height: LayoutConstant.itemHeight)
    }

    func itemWidth(for width: CGFloat, spacing: CGFloat) -> CGFloat {
        let itemsInRow: CGFloat = 2

        let totalSpacing: CGFloat = 2 * spacing   (itemsInRow - 1) * spacing
        let finalWidth = (width - totalSpacing) / itemsInRow

        return floor(finalWidth)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets(top: LayoutConstant.spacing, left: LayoutConstant.spacing, bottom: LayoutConstant.spacing, right: LayoutConstant.spacing)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return LayoutConstant.spacing
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return LayoutConstant.spacing
    }
}

Here is the collection view cell .

    protocol ReusableView: AnyObject {
        static var identifier: String { get }
    }
    class PhotoCollectionViewCell: UICollectionViewCell {
        
        private enum Constants {
            // MARK: contentView layout constants
            static let contentViewCornerRadius: CGFloat = 4.0
    
            // MARK: profileImageView layout constants
            static let imageHeight: CGFloat = 180.0
    
            // MARK: Generic layout constants
            static let verticalSpacing: CGFloat = 8.0
            static let horizontalPadding: CGFloat = 16.0
            static let profileDescriptionVerticalPadding: CGFloat = 8.0
        }
        
        private let imageView: UIImageView = {
            let imageView = UIImageView(frame: .zero)
            imageView.contentMode = .scaleAspectFill
            return imageView
        }()
    
       private let tagLabel: UILabel = {
            let label = UILabel(frame: .zero)
            label.textAlignment = .center
            label.numberOfLines = 0
            return label
        }()
        
        
        override init(frame: CGRect) {
            super.init(frame: .zero)
            setupViews()
            setupLayouts()
        }
           
        private func setupViews() {
            contentView.clipsToBounds = true
            contentView.layer.cornerRadius = Constants.contentViewCornerRadius
            contentView.backgroundColor = .white
    
            contentView.addSubview(imageView)
            contentView.addSubview(tagLabel)
            
        }
        
        private func setupLayouts() {
            imageView.translatesAutoresizingMaskIntoConstraints = false
            tagLabel.translatesAutoresizingMaskIntoConstraints = false
           
    
            // Layout constraints for `imageView`
            NSLayoutConstraint.activate([
                imageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
                imageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
                imageView.topAnchor.constraint(equalTo: contentView.topAnchor),
                imageView.heightAnchor.constraint(equalToConstant: Constants.imageHeight)
            ])
    
            // Layout constraints for `tagLabel`
            NSLayoutConstraint.activate([
                tagLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: Constants.horizontalPadding),
                tagLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -Constants.horizontalPadding),
                tagLabel.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: Constants.profileDescriptionVerticalPadding)
            ])
    
        }
        func configureCell(tagName: String) {
            tagLabel.text = tagName
          
            
            }
        func configureImageCell(row: Int, viewModel: PhotoViewModel) {
            
            imageView.image = nil
            
            viewModel
                .downloadImage(row: row) { [weak self] data in
                    let image = UIImage(data: data)
                    self?.imageView.image = image
                }
        }
        
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        
    }
    extension PhotoCollectionViewCell: ReusableView {
        static var identifier: String {
            return String(describing: self)
        }
    }

Here is the code details view controller .

import UIKit

class PhtotoDetailsViewController: UIViewController {

    var viewModel : PhotoDetailsViewModel?
    var photoviewModel : PhotoViewModel?
   
    private let imageView: UIImageView = {
        let imageView = UIImageView(frame: .zero)
        imageView.contentMode = .scaleAspectFill
        imageView.translatesAutoresizingMaskIntoConstraints = false
        return imageView
    }()

   private let tagLabel: UILabel = {
        let label = UILabel(frame: .zero)
        label.textAlignment = .center
        label.numberOfLines = 0
       label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
   
    override func viewDidLoad() {
        super.viewDidLoad()
        
        
        view.addSubview(tagLabel)
        view.addSubview(imageView)
      //  setUpUI()
        setPhoto()
        
    }
    
    private func setUpUI(){
        tagLabel.text = viewModel?.hit.tags
    }
    var rowSelected = 0
    
    private func setPhoto(){
       
        
        photoviewModel?.downloadImage(row: rowSelected) { [weak self] data in
            DispatchQueue.main.async {
                let image = UIImage(data: data)
                self?.imageView.image = image
            }
        }
        
    }
}

Here is the result when I click the cell .

enter image description here

CodePudding user response:

in your func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) add the following line

detailVC.photoviewModel = viewModel

CodePudding user response:

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    collectionView.deselectItem(at: indexPath, animated: false)
    let detailVC = PhtotoDetailsViewController()
    detailVC.rowSelected = indexPath.row
    let navController = UINavigationController(rootViewController: detailVC)
    navController.modalPresentationStyle = .fullScreen
    present(navController, animated: true, completion: nil)
}

You haven't set any viewmodel for PhotoDetailsViewController

  • Related