I have designed a tableview cell with a textfield for pickerview. AndI have loaded 2 of those cells in my tableview. In order to show data from the pickerview this is what I did in cellForRowAt...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: sellTableViewCell = tableView.dequeueReusableCell(withIdentifier: "sellProductIdentifier") as! sellTableViewCell
cell.delegate = self
let pickerView = UIPickerView()
pickerView.delegate = self
cell.pickerField.inputView = pickerView
cell.pickerField.text = myData[0]//myData is an array with values from 1-10
myCell = cell //The issue seems to be here.
return cell
}
And the picker view methods I have given like this...
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return myData.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return myData[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
myCell.pickerField.text = myData[row]
}
The issue is if I click on the 2nd pickerview the value I select is assigned to the textfield. But when I select a value from the 1st field that value is shown in the 2nd field instead of 1st.
EDIT: This is my code in cellForRowAt
...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: sellTableViewCell = tableView.dequeueReusableCell(withIdentifier: "sellProductIdentifier") as! sellTableViewCell
cell.delegate = self
let pickerView = MyPickerView()
pickerView.cell = cell
pickerView.delegate = self
cell.qtyPickerField.inputView = pickerView
return cell
}
This is the picker view methods...
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return myData.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return myData[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerView is MyPickerView {
if let cell = (pickerView as! MyPickerView).cell {
let indexpath = self.tableview.indexPath(for: cell)
if let index = indexpath {
(pickerView as! MyPickerView).cell?.qtyPickerField?.text = myData[index.row]
}
}
}
}
EDIT 2 . code of pickerview didSelectRow
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerView is MyPickerView {
if let cell = (pickerView as! MyPickerView).cell {
cell.qtyPickerField.text = myData[row]
let indexPath = self.tableview.indexPath(for: cell)
if let index = indexPath {
(pickerView as! MyPickerView).cell?.qtyPickerField?.text = myData[index.row]
}
}
}
}
Problem :
As somebody mentioned in answer above
myCell = cell
//The issue seems to be here.
is the culprit. Because every time cellForRowAtIndexPath
finishes your myCell will have reference to the last cell returned and not to the cell which is responsible for showing the pickerView
.
First delete myCell = cell
from cellForRowAtIndexPath
Solution :
Now all that you have to do is to figure out which cell which holds the textField which is responsible for presenting the pickerView.
Now there can be multiple solutions. Here is one
step 1: Create a subclass of PickerView
class MyPickerView : UIPickerView {
weak var cell : MyTableViewCell? = nil
}
Use this pickerView in your code than UIPickerView
.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: sellTableViewCell = tableView.dequeueReusableCell(withIdentifier: "sellProductIdentifier") as! sellTableViewCell
cell.delegate = self
let pickerView = MyPickerView()
pickerView.cell = cell //pass cells reference
pickerView.delegate = self
cell.pickerField.inputView = pickerView
//other code
}
Finally
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerView is MyPickerView {
if let cell = (pickerView as! MyPickerView).cell {
cell.textField?.text = myData[row]
let indexPath = self.tableView.indexPath(for: cell)
if let index = indexPath {
//now go ahead and update your data
}
}
}
}
Edit:
There can be multiple variants to this solution. Some will agree that passing a cell reference to picker view is fine because cell will anyway hold a strong ref to picker and picker only holds weak ref to cell.
I personally feel passing indexPath as a param to picker makes more sense. Finally when user picks something you will use the indexPath passed to picker to get the reference to cell and finally update the cell's textField.
O/P:
EDIT 2:
As OP is still confused I decided to modify his edit 2 and add it as part of answer
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerView is MyPickerView {
if let cell = (pickerView as! MyPickerView).cell {
cell.qtyPickerField.text = myData[row]
let indexPath = self.tableview.indexPath(for: cell)
if let index = indexPath {
//this is only to show you how you can access indexPath
//and in future if you need to update your data source you can use it
//for now ignore this :)
}
}
}
}
Should be good enough :) Hope it helps :)