I've populated a UITableView with names of restaurants using Google Places API. Now, I am trying to perform a segue to a different view while knowing which cell was clicked with IndexPath. I've tried using the didSelectAtIndexRowPath function but it's not recognizing the tap/click. It should print out the number to the console. What am I doing wrong?
import UIKit
class ViewController: UIViewController, UITableViewDataSource {
var myIndex = 0
#IBOutlet var restuarantsTable: UITableView!
var restaurantsList = [NSDictionary]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
restuarantsTable.dataSource = self
let url = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=26.2034071,-98.23001239999996&radius=500&type=restaurant&keyword=tacos&key=AIzaSyBRQZV4SOpcJ-icCe9BuZlI48MzONwH5Dw"
downloadRestaurants(urlString: url) { (array) -> () in
self.restaurantsList = array as! [NSDictionary]
// print(self.restaurantsList.count)
self.restuarantsTable.reloadData()
}
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return restaurantsList.count
}
#available(iOS 2.0, *)
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let RCell = tableView.dequeueReusableCell(withIdentifier: "RCell", for: indexPath)
// let imgURL = NSURL(string: imgURLArray[indexPath.row])
// let imageView = RCell.viewWithTag(350) as! UIImageView
RCell.textLabel!.text = restaurantsList[indexPath.row]["name"] as? String
// RCell.imageView?.image = restaurantsList[indexPath.row]["photos"] as? UIImage
return RCell
}
private func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) {
self.performSegue(withIdentifier: "detailSegue", sender: indexPath)
print(restaurantsList[indexPath.row])
}
}
You would have to conform to UITableViewDelegate like you did for UITableViewDataSource, didSelectRowAtIndexPath is a UITableViewDelegate method
Add these lines
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
And in viewDidLoad
restuarantsTable.delegate = self
I think you would have to set delegate in storyboard as well
Go to this tab and ctrl+Drag to the viewcontroller to set it as delegate
Swift 3
Error1:
You have to add UITableViewDelegate protocol for using UITableView delegate methods.
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate{}
In viewDidLoad():
override func viewDidLoad() {
super.viewDidLoad()
restuarantsTable.dataSource = self
restuarantsTable.delegate = self
}
Error 2:
The protocol must be confirm with public. You declared as private
change
private func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath){}
to
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {}
or (below swift 3)
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath){}
Modify two things in your code set restuarantsTable.delegate = self and then reload your table on main thread as you are making network call which will handle in background thread. So also modify below code.
DispatchQueue.main.async({
self.restuarantsTable.reloadData()
})
Related
i'm set tableview datasource but it doesn't recognize with his erorr
Type 'ViewController' does not conform to protocol 'UITableViewDataSource'
import UIKit
class ViewController: UIViewController ,UITableViewDataSource,UITableViewDelegate{
override func viewDidLoad() {
super.viewDidLoad()
var contact : [pedped]=[]
let asghar = pedped()
asghar.nmae="asghar "
asghar.lname="ghasemi"
asghar.image="asghar"
let akbar = pedped()
akbar.nmae="akbar "
akbar.lname="askj"
akbar.image="asgkajsjkashar"
contact.append(asghar)
contact.append(akbar)
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contact.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell=tableView.dequeueReusableCell(withIdentifier: "id", for: indexPath)as!custom
let contacts = contact[indexPath.row]
cell.lablename.text = contacts.nmae
cell.lastnamelable.text = contacts.lname
return cell
}
}
}
Although ViewController conforms to UITableViewDataSource, you are implementing the methods in wrong place. You have to remove them outside viewDidLoad.
Also, make sure that the table view data source/delegate is connected to the view controller itself, whether from the interface build or from the code:
// create an IBOutlet for the table view then:
tableView.dataSource = self
tableView.delegate = self
This probably won't work 100% but it at least shows you a better way to organize your code
import UIKit
class ViewController: UIViewController {
var contact = [pedped]() // Int
override func viewDidLoad() {
super.viewDidLoad()
let asghar = pedped()
asghar.nmae="asghar "
asghar.lname="ghasemi"
asghar.image="asghar"
let akbar = pedped()
akbar.nmae="akbar "
akbar.lname="askj"
akbar.image="asgkajsjkashar"
contact.append(asghar)
contact.append(akbar)
}
}
extension ViewController: UITableViewDataSource
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contact.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell=tableView.dequeueReusableCell(withIdentifier: "id", for: indexPath)as!custom
let contacts = contact[indexPath.row]
cell.lablename.text = contacts.nmae
cell.lastnamelable.text = contacts.lname
return cell
}
}
extension ViewController: UITableViewDelegate {
// Put any UITableViewDelegate functions here
}
I am using two view Controllers i.e. StateListVC and PlayVC. In StateListVC, I am using container view with 3 VCs. After tapping on 3rd View Controller, I am going to PlayVC with delegate method. I don't know how to do that. Please help me to resolve this issue.
StateListVC
class StateListVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
if isMoveToAnotherVC
{
let vc = self.storyboard?.instantiateViewController(withIdentifier: "PlaceVC") as! PlaceVC
vc.delegate = self
}
}
}
extension StateListVC: MoveToAnotherVC {
func moving(string: String) {
print(string)
}
}
ThirdVC
protocol MoveToAnotherVC {
func moving(string: String)
}
class PlaceVC: UIViewController {
#IBOutlet weak var tableViewPlace: UITableView!
var delegate: MoveToAnotherVC? = nil
var arrPlace = ["Place1", "Place2"]
override func viewDidLoad() {
super.viewDidLoad()
}
extension PlaceVC: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrPlace.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = arrPlace[indexPath.row]
return cell
}
}
extension PlaceVC: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
isMoveToAnotherVC = true
print(delegate)
guard let delegate = self.delegate else{
print("Delegate not set")
return
}
delegate.moving(string: "test")
}
}
This is hooked up fine:
protocol MoveToAnotherVC: AnyObject {
func moving(string: String)
}
class StateListVC: UIViewController, MoveToAnotherVC {
override func viewDidLoad() {
super.viewDidLoad()
let vc = self.storyboard?.instantiateViewController(withIdentifier: "PlaceVC") as! PlaceVC
vc.delegate = self
}
func moving(string: String) {
print(string)
}
}
class PlaceVC: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableViewPlace: UITableView!
weak var delegate: MoveToAnotherVC?
var arrPlace = ["Place1", "Place2"]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrPlace.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = arrPlace[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
delegate?.moving(string: "test")
}
}
I made the protocol a class protocol, moved the view controller instantiation into viewDidLoad, removed some (what I consider) extraneous unwrapping, and stripped your protocol/delegate pattern down to the basics. This works. I would plug this into your project and add what you need piece by piece until it breaks because your problem is outside of this. I suspect it may have to do with something you didn't include in your question but this answers your question about how to set up a protocol/delegate pattern.
I have this code:
class UserProfilViewController: UIViewController {
// Outlets
#IBOutlet weak var userProfileTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tabBarController?.navigationItem.title = "Profil"
}
}
// MARK: - Table View Data Source
extension UserProfilViewController {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "UserProfilCell", for: indexPath)
return cell
}
}
My project in bitbucket: https://bitbucket.org/trifek/karta-nauka/src/master/
I placed one tableviewcell cell on the tableview (UserProfil.storyboard). I have a form on it that I would like to display in this cell. The problem is the cell does not display. Does anyone know how to fix it?
As per the code you have shared, Please change your code to following.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "UserProfilCell", for: indexPath) as! UserProfilTableViewCell
return cell
}
Let me know in case of any queries.
IMHO, first try to clear your requirements. If you want to display fix number of cells then you can simply use static cells. If your cells are dynamic i.e their number depends on some calculation or other logic, then you can use dynamic cell. While using dynamic cell, verify if you have registered it or not (if you are using xib for cell) and also verify for the cell identifier.
#Lukasz
Please use the below code for this.
class UserProfileViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setUIComponents()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
private func setUIComponents(){
registerNibs()
}
}
extension UserProfileViewController: UITableViewDelegate, UITableViewDataSource{
internal func registerNibs(){
tableView.register(UINib(nibName: String(describing: UserProfileTableCell.self), bundle: Bundle.main), forCellReuseIdentifier: kUserProfileCellReuseId)
}
//MARK: TableView Methods -
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let sessionCell: UserProfileTableCell.self = tableView.dequeueReusableCell(withIdentifier: kUserProfileCellReuseId, for: indexPath) as! UserProfileTableCell.self
cell.titleLabel.text = “TEST”
return sessionCell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
}
class UserProfileTableCell: UITableViewCell {
//Set the "kUserProfileCellReuseId" in nib to register identifier.
let kUserProfileCellReuseId = "kUserProfileCellReuseId"
//MARK: - Override Methods
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
setUIComponents()
}
private func setUIComponents(){
}
}
You never declare that your view controller conforms to the UITableViewDataSource or UITableViewDelegate protocols. Given that you don't do that, you would not be able to set your view controller as the data source or delegate of your table view.
This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 6 years ago.
I'm new to Swift. I have two table view controllers, one with static cells and one with dynamic ones. I basically want to let a user select his marital status on the second table view controller and send his choice back to the first table view controller (and display his selection on the cell "Marital Status"). Here is a screenshot of my storyboard:
Storyboard
Current code on second table view controller:
import UIKit
class SecondTableViewController: UITableViewController {
let maritalStatusArray: [String] = ["Single", "Married"]
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return maritalStatusArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MaritalStatusCell", for: indexPath)
cell.textLabel?.text = maritalStatusArray[indexPath.row]
return cell
}
}
My guess is that I have to add a segue from the dynamic cell of the second view controller back to the first one. Is that right ?
Supposing this is the way to do it, I have afterwards to update the text of the static label to include the choice made by the user. Any ideas ?
There few ways by which you can implement the callback functionality to pass data.
Delegate
Using Block CallBack
Post Notification
But I would suggest to use delegate which is best way, Post Notification is also a way but I do not want to prefer.
You can use custom delegate to do this:
ViewController.swift:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, SecondViewControllerProtocol {
#IBOutlet weak var userInfoTableView: UITableView!
var userInfoArray: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
userInfoArray = ["Marital Status","Canton","Commune","Religion"]
self.userInfoTableView?.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let userInfoCell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
userInfoCell.textLabel?.text = userInfoArray[indexPath.row]
if indexPath.row == 0{
userInfoCell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator
}
return userInfoCell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0{
let secondVC = storyboard?.instantiateViewController(withIdentifier: "SecondViewControllerIdentifier") as! SecondViewController
secondVC.statusDelegate = self
self.navigationController?.present(secondVC, animated: true, completion: nil)
}
}
func changeMaritalStatus(type: String){
let maritalStatusCell = userInfoTableView.cellForRow(at: IndexPath(row:0 , section:0))
maritalStatusCell?.textLabel?.text = String("Marital Status: \(type)")
}
}
SecondViewController.swift:
import UIKit
protocol SecondViewControllerProtocol {
func changeMaritalStatus(type: String)
}
class SecondViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var maritalStatusTableView: UITableView!
var maritalStatusArray: [String] = []
var statusDelegate : SecondViewControllerProtocol? = nil
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
maritalStatusArray = ["Single","Married","Divorced"]
self.maritalStatusTableView.register(UITableViewCell.self, forCellReuseIdentifier: "maritalStatuscell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let maritalStatusInfoCell = tableView.dequeueReusableCell(withIdentifier: "maritalStatuscell", for: indexPath)
let infoLabel: UILabel = UILabel.init(frame: CGRect(x: 10, y: 5, width: 250, height: 50))
infoLabel.text = maritalStatusArray[indexPath.row]
maritalStatusInfoCell.addSubview(infoLabel)
return maritalStatusInfoCell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
statusDelegate?.changeMaritalStatus(type: maritalStatusArray[indexPath.row])
self.dismiss(animated: true, completion: nil)
}
}
GitHub link:
https://github.com/k-sathireddy/CustomDelegatesSwift
Output:-
I have an array: var initialArray. That appends every time the screen is tapped. This is done on ViewController 3
I have a table which displays the array in another view controller: ViewController2.
However the issue is: use of unresolved identifier: initialArray.
How can I get ViewController2 to recall variables from ViewController3?
class ViewController2: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tableView.delegate = self
tableView.dataSource = self
}
//How many rows
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return initialArray
//////use of unresolved identifier: initialArray
}
//What goes in each cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
print(indexPath.row)
cell.textLabel?.text = initialArray[indexPath.row]
//////use of unresolved identifier: initialArray
return cell
}