0

I am using UISegmentControl to display objective type questions in table view. But, if I select one segment in any one of cell, then if I scroll, some segment values are changed. I dont know how to solve that. Kindly guide me.

Cell size : 160px

Segment tint color : blue color

Coding

//UIViewController
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = segTblVw.dequeueReusableCellWithIdentifier("segment", forIndexPath: indexPath) as! segmentTblCell

        return cell
    }

//UITableViewCell CLASS
class segmentTblCell: UITableViewCell {



    @IBOutlet weak var segMent: UISegmentedControl!


    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}

Screen shot below:

enter image description here

McDonal_11
  • 3,935
  • 6
  • 24
  • 55
  • could you please explain more where is your segment ? inside a table cell ? – Bobj-C Sep 02 '15 at 11:46
  • yes.. inside UITableView. Havin 10 Rows. – McDonal_11 Sep 02 '15 at 11:53
  • 2
    We need some of your code. However it looks like the segmented control is inside the cell. In that case, when tableView:cellForRowAtIndexPath is called and you dequeue a cell, you must initialize all components inside the cell. Since cells are reused, you would end up with some components showing the values of other cells instead of the one you want. – ncerezo Sep 02 '15 at 11:53
  • I ll update my full code. Sry.... – McDonal_11 Sep 02 '15 at 11:56
  • I updated. Kindly help me. – McDonal_11 Sep 02 '15 at 12:04
  • @McDonal_11 did u create xib for your custom cell? – Shebin Koshy Sep 02 '15 at 12:19
  • In addition to the the sage advice from @ncerezo, you'll probably have to save the state of the segmented control when the value is changed. The table won't be able to keep track of that state by itself if the user is scrolling the table and cells are being dequeued. – Stewart Macdonald Sep 02 '15 at 12:20
  • yes!! Cn any one explain me through coding? – McDonal_11 Sep 02 '15 at 12:23
  • Take a look at this: http://stackoverflow.com/questions/30980433/how-to-save-text-field-value-in-uicollectionviewcell/30983980#30983980 the principle is the same: you need to store your information somewhere, as @smacdonald says – ncerezo Sep 02 '15 at 12:24

5 Answers5

2

You're having this problem because of how dequeueReusableCellWithIdentifier: works. Each time a cell get scrolled out of screen, it enters a cache area where it will be reused.

Let's say you have 100 cells. All their segmentedControl objects are set to first. You tap on one to change it's value. As the cell moves out of view, it enters the cache, where it will be dequeued if you scroll down further.

It's important to understand this, because the segmentedControl object is not actually changing. It looks like it's changing because of the dequeue behaviour.

To solve this problem, you will need to implement a dataSource that stores the segmentedControl object's value so you can reinitialize it correctly every time a cell is dequeued.

Kelvin Lau
  • 6,373
  • 6
  • 34
  • 57
  • for starters, set up a variable in the scope of the tableViewController that holds the `segmentedControl` object's values. This will be your `dataSource`. When you tap on the `segmentedControl` make sure you update the value in the variable. You'll also want to configure the cell based on the `dataSource` - i.e the variable. You need to read up on the MVC pattern – Kelvin Lau Sep 02 '15 at 12:32
1

Method 1: Prevent reusability of cells by, Holding all cell objects in an array

var arraysCells : NSMutableArray = []//globally declare this

in viewDidLoad()

for num in yourQuestionArray//this loop is to create all cells at beginning 
{
     var nib:Array = NSBundle.mainBundle().loadNibNamed("SegmentTableViewCell", owner: self, options: nil)
     var cell = nib[0] as? SegmentTableViewCell
     arraysCells.addObject(cell!);
}

in tableViewDelegate,

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    return arraysCells.objectAtIndex(indexPath.row) as! UITableViewCell
}

you can find the selected segment values (answer) by iterating arraysCells

NOTE: Method 1 will be slow, if you have big number of cells

Method 2: Reuse the cell as normal, but save the states(enterd values) Using Delegate and arrays.

in custom UITableViewCell

@objc protocol SegmentTableViewCellDelegate {
func controller(controller: SegmentTableViewCell, selectedSegmentIndex:Int, indexPath : NSIndexPath)
}

class SegmentTableViewCell: UITableViewCell {

var delegate: AnyObject?
var indexPath : NSIndexPath?

@IBOutlet weak var segment: UISegmentedControl! //outlet of segmented Control

@IBAction func onSegmentValueChanged(sender: UISegmentedControl/*if the parameter type is AnyObject changed it as  UISegmentedControl*/)//action for Segment
{
    self.delegate?.controller(self, selectedSegmentIndex: sender.selectedSegmentIndex, indexPath: indexPath!)
}

in viewController

class MasterViewController: SegmentTableViewCellDelegate{
var selectedAnswerIndex : NSMutableArray = []  //globally declare this
var selectedSegmentsIndexPath : NSMutableArray = [] //globally declare this


func controller(controller: SegmentTableViewCell, selectedSegmentIndex:Int, indexPath : NSIndexPath)
{
    if(selectedSegmentsIndexPath.containsObject(indexPath))
    {
        selectedAnswerIndex.removeObjectAtIndex(selectedSegmentsIndexPath.indexOfObject(indexPath))
        selectedSegmentsIndexPath.removeObject(indexPath)
    }
    selectedAnswerIndex.addObject(selectedSegmentIndex)
    selectedSegmentsIndexPath.addObject(indexPath)
}

in cellForRowAtIndexPath (tableView Delegate)

if(selectedSegmentsIndexPath.containsObject(indexPath))
{
 cell?.segment.selectedSegmentIndex = selectedAnswerIndex.objectAtIndex(selectedSegmentsIndexPath.indexOfObject(indexPath)) as! Int
}
cell?.delegate = self
cell?.indexPath = indexPath

you can get the result by

for index in selectedSegmentsIndexPath
{
  var  cellIndexPath = index as! NSIndexPath
  var answer : Int = selectedAnswerIndex.objectAtIndex(selectedSegmentsIndexPath.indexOfObject(cellIndexPath)) as! Int
  NSLog("You have enterd answer \(answer) for question number \(cellIndexPath.row)")
}
Shebin Koshy
  • 1,182
  • 8
  • 22
  • I think it is not a good idea specially if you have a big number of cells – Bobj-C Sep 02 '15 at 12:36
  • @McDonal_11 for method 1.. you will get the answer by` var index : Int = 0 for cell in arraysCells { var cell:SegmentTableViewCell? = arraysCells .objectAtIndex(index) as? SegmentTableViewCell cell?.segment.selectedSegmentIndex cell?.switchAnswer.selected NSLog("answer for question number \(index) is \(cell?.segment.selectedSegmentIndex) or \(cell?.switchAnswer.selected) ") index++ }` – Shebin Koshy Sep 03 '15 at 15:09
0

@KelvinLau's is perfect

you can do that by using var segmentedTracker : [NSIndexPath:Int] = [:]

on segmentedValueChanged set the value of the selectedIndex ie: segmentedTracker[indexPath] = valueOf the selected index

then in cellForRowAtIndexPath check for the value let selected = [segmentedTracker]

cell.yourSegmentedControlReference.selectedIndex = selected

please note this is a pseudocode I don't remember the properties name. From here you can figure it out by urself

Bobj-C
  • 5,276
  • 9
  • 47
  • 83
0

I think to use UISegmentControl in UITableViewCell may be wrong.

https://developer.apple.com/library/ios/documentation/UIKit/Reference/UISegmentedControl_Class/

I have never seen the kind of that in iOS application.

The problem is that UITableViewCell is reused by dequeueReusableCellWithIdentifier method. So some UISegmentControl values are changed when scrolling.

Although it is not best solution, you can use Static Cells. What you need to do is that only switch Static cells. And If so, you don't write code of UITableViewCell.

enter image description here

pixyzehn
  • 762
  • 6
  • 15
0

Year 2018: Updated Answer

Find my easiest answer in this UISegement inside UITableViewCell

=======================================================

Year 2015

I have tested in my own way. My coding is below. Kindly guide me, whether it is right way or wrong way? My problem get solved. This code stops reusable cell.

My Coding Below:

//UIViewController
var globalCell = segmentTblCell()  //CUSTOM UITableViewCell Class

func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 10
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = segTblVw.dequeueReusableCellWithIdentifier("segment", forIndexPath: indexPath) as! segmentTblCell

    globalCell  = segTblVw.dequeueReusableCellWithIdentifier("segment", forIndexPath: indexPath) as! segmentTblCell  //THIS LINE - STOPS REUSABLE TABLE.

    return cell
}
McDonal_11
  • 3,935
  • 6
  • 24
  • 55
  • to my knowledge, that line will not stop reusable Cells – Shebin Koshy Sep 03 '15 at 08:06
  • Thanks @ShebinKoshy . I am using this. if I select one segment in any one of cell, then if I scroll, no changes in rest of the cell. – McDonal_11 Sep 03 '15 at 08:49
  • are u using story board? – Shebin Koshy Sep 03 '15 at 08:54
  • I tested ur code, it reusing cells, but the values in segment not changing, I DONT KNOW WHY !!.. but, if you add a textField to the cell you will know what is happening.. In my opinion, don't do this. because your app will use more memory (YOU CAN check it by scroll down and scroll up the tableView 10 times continuously) – Shebin Koshy Sep 03 '15 at 12:23
  • Yes.. I checked with UItextView,, . Some issues happening. – McDonal_11 Sep 03 '15 at 12:32
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/88702/discussion-between-mcdonal-11-and-shebin-koshy). – McDonal_11 Sep 03 '15 at 12:57