I am very new to Swift (less than one week) I create a table view where I have more cells , each cell gets create from a .xib file, and the fields get populated because I create an array of objects that are used in order to populate the cells.
I have a file called: MenuWeekViewControoler.swift where I have the tableView.
I have a file called FoodTableViewCell.swift which is connected with the .xib file
Inside the FoodTableViewCell I have the uipickerview and in the MenuWeekViewControoler I visualise the pickerview and interact with it.
My wish is to get the value of the picker view for each separate cell and I don't really know how to do it.
I will attach the code of the 3 files in order for the code to make sense:
MenuWeekViewControoler :
import UIKit
class MenuWeekViewController : UIViewController, UITableViewDelegate, UITableViewDataSource {
var menus : [Menu] = [
Menu(nameMenu: "BBQ", priceMenu: 8, pickerDada: ["0","1","2","3","4","5","6","7","8","9","10"]),
Menu(nameMenu: "BBQ2", priceMenu: 8, pickerDada: ["0","1","2","3","4","5","6","7","8","9","10"]),
Menu(nameMenu: "BBQ3", priceMenu: 8, pickerDada: ["0","1","2","3","4","5","6","7","8","9","10"]),
Menu(nameMenu: "BBQ4", priceMenu: 8, pickerDada: ["0","1","2","3","4","5","6","7","8","9","10"]),
Menu(nameMenu: "BBQ4", priceMenu: 8, pickerDada: ["0","1","2","3","4","5","6","7","8","9","10"]),
Menu(nameMenu: "BBQ4", priceMenu: 8, pickerDada: ["0","1","2","3","4","5","6","7","8","9","10"]),
]
var test = FoodTableViewCell()
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var nameSection: UITextField!
#IBOutlet weak var privateGuestsUIPicker: UIPickerView!
#IBOutlet weak var BusinessGuestUIPicker: UIPickerView!
#IBOutlet weak var commentSection: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
tableView.rowHeight = 100
tableView.register(UINib(nibName: "FoodTableViewCell", bundle: nil), forCellReuseIdentifier: "ReusableMenuCell")
}
#IBAction func updateOrders(_ sender: UIButton) {
}
#IBAction func sendOrder(_ sender: UIButton) {
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return menus.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ReusableMenuCell", for: indexPath) as! FoodTableViewCell
cell.menuName?.text = menus[indexPath.row].nameMenu
cell.priceMenu?.text = String("\(menus[indexPath.row].priceMenu) CHF")
return cell
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
print(menus[indexPath.row].nameMenu)
}
}
FoodTableViewCell :
import UIKit
class FoodTableViewCell: UITableViewCell,UIPickerViewDelegate, UIPickerViewDataSource {
var pickerDada = ["0","1","2","3","4","5","6","7","8","9","10"]
#IBOutlet weak var quantityMenu: UIPickerView!
#IBOutlet weak var priceMenu: UILabel!
#IBOutlet weak var menuName: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
quantityMenu.dataSource = self
quantityMenu.delegate = self
quantityMenu.setValue(UIColor.white, forKey: "textColor")
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return 11
}
internal func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return pickerDada[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
{
print(pickerDada[row])
}
}
Menu struct :
import UIKit
struct Menu{
var nameMenu : String
var priceMenu : Int
var pickerDada : [String] = [String]()
}
Thank you to everyone willing to help
in FoodTableViewCell you should define a delegate protocol
and define it as a variable such as:
import UIKit
protocol FoodCellDelegate: AnyObject {
func tapFood(food: YourFoodModel) or // func tapFood(food: pickerDada) or whatever you want pass it
}
class FoodTableViewCell: UITableViewCell,UIPickerViewDelegate, UIPickerViewDataSource {
//define a variable type of delegate
weak var delegate: FoodCellDelegate?
.
.
.
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
{
print(pickerDada[row])
// add this
delegate?.tapFood(food: pickerData[row])
}
}
after that you must delegate it to your MenuWeekViewController:
class MenuWeekViewController : UIViewController, UITableViewDelegate, UITableViewDataSource {
.
.
.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ReusableMenuCell", for: indexPath) as! FoodTableViewCell
cell.menuName?.text = menus[indexPath.row].nameMenu
cell.priceMenu?.text = String("\(menus[indexPath.row].priceMenu) CHF")
// add this
cell.delegate = self
return cell
}
.
.
.
}
extension MenuWeekViewController: FoodCellDelegate {
func tapFood(food: YourFoodModel) {
print it
}
}
i made a simple apps for practice. I'm a beginner in programming.
First of all I will explained in detail what I did and what I want to do.
Create a File a Swift file for data :
class done {
var meal: [String] = ["tomato","banana","potato","peanuts"]
}
ViewController Setup I have a Textfield and a Button to go to the next page this will add the data of the textfield that the person enter and will add to my meal data list:
import UIKit
class ViewController: UIViewController {
var data = done()
#IBOutlet weak var textField: UITextField!
#IBOutlet weak var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
print("Data now : \(data.meal)")
}
#IBAction func buttonaction(_ sender: UIButton) {
var newitem = textField.text ?? ""
if textField.text == "" {
newitem = "empty"
}
data.meal.append(newitem)
performSegue(withIdentifier: "toView", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toView" {
let successVCG = segue.destination as! TableViewController
successVCG.data = self.data
}
}
}
I have a second ViewController that will display in a TableView with a TableViewcell and Inside I have a Pickerview in each row..
import UIKit
class TableViewController: UIViewController{
#IBOutlet weak var table: UITableView!
var data = done()
override func viewDidLoad() {
super.viewDidLoad()
print("Transfert Data OK : \(data.meal)")
table.delegate = self
table.dataSource = self
}
#IBAction func `return`(_ sender: Any) {
print(data.meal)
}
#IBAction func update(_ sender: Any) {
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toViewa" {
let successVCG = segue.destination as! ViewController
successVCG.data = self.data
}
}
}
extension TableViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 300
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "cellule") as? TableViewCell {
return cell
}
let cell2 = UITableViewCell(style: .subtitle, reuseIdentifier: nil)
return cell2
}
}
And it's the configuration of the TableViewCell
import UIKit
class TableViewCell: UITableViewCell {
#IBOutlet weak var picker: UIPickerView!
var data = done()
override func awakeFromNib() {
super.awakeFromNib()
picker.delegate = self
picker.dataSource = self
}
}
extension TableViewCell: UIPickerViewDataSource, UIPickerViewDelegate {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return data.meal.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return data.meal[row]
}
}
The Picker view is display the data.meal correctly but never Updater while I add new stuff in the variable.
In my print. I see the new data update In the ViewController and the TableViewController but I try everything I could with my learning. Can't update the PickerView. I can't send the new value in the TableViewCell...mPlease help. Thank you very Much. Love to code!
This is because you don't implement the pickerView(_:didSelectRow:inComponent:) picker view's delegate method in your table view cell. So even if the user selects a new row from your picker view, the changes simply won't get reflected in your data variable. You could implement this method and change your data model accordingly from within this method.
An other thing I noticed is that you're not passing your data from the parent view to your table view cell, so the data variable in your table view cell never gets the latest data. You could simply pass the data to your cell in the cellForRow(at:) method of your table view.
Also I would recommend you to name your data model something different than done. This name is kind of confusing (because it would usually refer to an action), and the capitalization is misleading because for example when in your code you write var done = done() it feels like you're calling a function or a closure, while, from my understanding, you're actually initializing your data model.
This is because in Swift you would name by convention all your methods, functions and variables using lower camel case (for example let myVariable: Double = 0), and types such as structs, enums and classes in upper camel case (for example myData = MyDataModel()).
I try to keep a separate custom cell class, but somehow the datepicker I dragged into it from storyboard refuses to show up after I ran it.
import UIKit
class eventViewController: UIViewController,UITextViewDelegate,UIScrollViewDelegate,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var timeTableView: UITableView!
#IBOutlet weak var eventText: UITextView!
#IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.eventText.delegate = self
self.scrollView.delegate = self
self.timeTableView.delegate = self
self.timeTableView.dataSource = self
self.timeTableView.register(startDateCell.self, forCellReuseIdentifier: "startDateCell")
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "startDateCell", for: indexPath) as! startDateCell
//cell.startDatePicker.date = Date()
//cell.text = "anything"
return cell
}
}
class startDateCell: UITableViewCell {
#IBOutlet weak var startDatePicker: UIDatePicker!
}
I have the outlet connected to my datePicker in the custom cell and I also defined my custom cell class to be startDateCell in inspector, and I registered my custom cell in my view controller. It will throw a runtime error saying the datepicker is nil.
Can somebody explain why it isn't showing up?
Can you remove the following code from viewDidLoad() and ensure you have set reuse identifier of custom tableviewcell as "startDateCell" in storyboard and try again?
self.timeTableView.register(startDateCell.self,
forCellReuseIdentifier: "startDateCell")
I am trying to create PickerView inside tableViewCell. I made my custom cell conform UIPickerViewDelegate and UIPickerViewDataSource protocols. I send data array to cell from the controller (I think this doesn't conform to MVC pattern, may be you also can suggest me how to fix that?). But when tableview calls dequeueReusableCellWithIdentifier the cell calls pickerView function. However, pickerView function uses pickerData which is not initialized yet. How do I fix that?
Below is my code for the cell:
class PickerTableViewCell: UITableViewCell, UIPickerViewDelegate, UIPickerViewDataSource {
#IBOutlet weak var picker: UIPickerView!
#IBOutlet weak var title: UILabel!
var pickerData: Array<String>!
override func awakeFromNib() {
self.picker.delegate = self;
self.picker.dataSource = self;
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return pickerData.count // I get fatal error here due to pickerData is nil
}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return pickerData[row]
}
}
And here is the code for the cell's initialization:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("picker", forIndexPath: indexPath) as! PickerTableViewCell
cell.title.text = fieldModel.editFieldArray[indexPath.row].title
cell.pickerData = (fieldModel.editFieldArray[indexPath.row] as! PickerEditField).pickerData
return cell
}
Thanks a lot for any help!
Your issue is that you have reload the components of PickerView so make one small change in your cellForRowAtIndexPath and just reload the components of PickerView after setting the pickerData Array.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("picker", forIndexPath: indexPath) as! PickerTableViewCell
cell.title.text = fieldModel.editFieldArray[indexPath.row].title
cell.pickerData = (fieldModel.editFieldArray[indexPath.row] as! PickerEditField).pickerData
cell.picker.reloadAllComponents();
return cell
}
Also in awakeFromNib initialize your pickerData object
override func awakeFromNib() {
self.pickerData = Array<String>()
self.picker.delegate = self;
self.picker.dataSource = self;
super.awakeFromNib()
}
My ViewController is getting way too big because of all the methods needed for UITableViewDelegate and UITableViewDataSource, so I refactored my code to a different file, but now the data doesn't show up anymore...
Here's my current implementation:
In MyViewController.swift
class SomeView: UIViewController {
#IBOutlet weak var myTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
myDataSourceClass(tableView: myTableView)
}
}
In MyNewDataSourceClass.swift
class myDataSourceClass: UITableViewDelegate, UITableViewDataSource {
let stuff = [1, 2, 3]
init(tableView: UITableView) {
super.init()
tableView.delegate = self
tableView.dataSource = self
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell")
cell?.textLabel?.text = "please show up"
return cell!
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.stuff.count
}
}
Any help would be very appreciated. Thank you!
// you need to reload table after setting delegate and datasource
class SomeView: UIViewController {
#IBOutlet weak var myTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
myDataSourceClass(tableView: myTableView)
myTableView.reloadData()
}
}