Clint
Clint

Reputation: 387

How to change data based on segmentedControl index

I am trying to change the data of a collectionView based on the index of a segment control. When I run my code I get a crash. Can someone tell me what I did wrong here? I was following different methods I found. The error code I get with the crash is

Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1da72fde0)

The error occurs when I try switching between segment indexes. and happens on the line

cell.trendsLabel.text = maleTrends[indexPath.row]

of

 func handleSegControlTapped(for header: HomeViewHeaderReusableView)


 var header: HomeViewHeaderReusableView?



    func handleSegControlTapped(for header: HomeViewHeaderReusableView) {

        collectionView.reloadItems(at: collectionView.indexPathsForVisibleItems) 

        switch header.segmentedControl?.selectedSegmentIndex {
        case 0:
            print("Display female trends")

            header.segmentedControl?.selectedSegmentIndex = 0

            let indexPath = IndexPath()
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "homeViewCell", for: indexPath) as! CurrentTrendsCell
            cell.trendsLabel.text = femaleTrends[indexPath.row]
            cell.trendsImageView.image = femaleImages[indexPath.row]

        case 1:
            print("Display male trends")
            header.segmentedControl?.selectedSegmentIndex = 1
            let indexPath = IndexPath()

            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "homeViewCell", for: indexPath) as! CurrentTrendsCell
                     cell.trendsLabel.text = maleTrends[indexPath.row]
            cell.trendsImageView.image = maleImages[indexPath.row]

        default:
            break
        }

        collectionView.reloadData()

    }



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

        let segmentedOutlet = header?.segmentedControl

        switch segmentedOutlet?.selectedSegmentIndex {
        case 0: return femaleTrends.count

       case 1: return maleTrends.count

        default: print("opps, cant load data")
        }

        return 0

    }


    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "homeViewCell", for: indexPath) as! CurrentTrendsCell

        let segmentedOutlet = header?.segmentedControl

        switch segmentedOutlet?.selectedSegmentIndex {
        case 0: cell.trendsLabel.text = femaleTrends[indexPath.row]
        cell.trendsImageView.image = femaleImages[indexPath.row]

        case 1: cell.trendsLabel.text = maleTrends[indexPath.row]
        cell.trendsImageView.image = maleImages[indexPath.row]

        default: break

        }
        return cell


    }

  func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "homeViewReuseCell", for: indexPath) as! HomeViewHeaderReusableView

        headerView.delegate = self 
        return headerView
    }


Edit

Here is the code in the header


class HomeViewHeaderReusableView: UICollectionReusableView {

    @IBOutlet weak var segmentedControl: UISegmentedControl?


    var delegate: HomeSegmentedControl?



     // MARK: Handler
    @objc func handleSegTapped() {
        delegate?.handleSegControlTapped(for: self)
    }



    @IBAction func segmentedTapped(_ sender: Any) {
        handleSegTapped()

        // change data based on female / male


    }


 override func awakeFromNib() {
         super.awakeFromNib()

        segmentedControl?.tintColor = .clear
        segmentedControl?.layer.borderColor = UIColor.clear.cgColor
        segmentedControl?.setBackgroundImage(UIImage(), for: .normal, barMetrics: .default)


        segmentedControl?.setTitleTextAttributes([
            NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 11),
            NSAttributedString.Key.foregroundColor: UIColor.lightGray

            ], for: .normal)

        segmentedControl?.setTitleTextAttributes([
            NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 11) ,
            NSAttributedString.Key.foregroundColor: UIColor.white
            ], for: .selected)


        segmentedControl?.selectedSegmentIndex = 0



    }


Upvotes: 0

Views: 531

Answers (2)

vadian
vadian

Reputation: 285072

Never, never ever call dequeueReusableCell outside of cellForRow/ cellForItem. The cell is dequeued but gets deallocated when the method exits. Unlike the collection/table view data source method the cell is not returned anywhere.

Edit:

Replace

var header: HomeViewHeaderReusableView?

with

var selectedSegmentIndex = 0

Then replace the entire method handleSegControlTapped with

func handleSegControlTapped(for header: HomeViewHeaderReusableView) {
    selectedSegmentIndex = header.segmentedControl!.selectedSegmentIndex
    collectionView.reloadData()
}

As the data source methods handle the state of the segmented control simply reloading the collection view is sufficient.

Then change numberOfItemsInSection to

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

    switch selectedSegmentIndex {
    case 0: return femaleTrends.count
    case 1: return maleTrends.count
    default: print("opps, cant load data")
       return 0
    }
}

and change the other data source methods accordingly.

Upvotes: 2

vaibhav
vaibhav

Reputation: 4096

Based on your selection on segment just reload the collectionView only and configure the CollectionViewCell inside the cellForItemAt.

No matter where you have added the segment control just truly react on the action method and update the collection accordingly.

Upvotes: 0

Related Questions