Opening TabbedBarController from TableViewController - swift

This is my tableViewController where I'm calling the tabbedView, however I'm getting an exception on this line let viewController = segue.destination as! EViewController the exception is:
Could not cast value of type 'UITabBarController' (0x7fff897a2cd8) to 'Test.EViewController'
Which is weird, because EViewController is a UIViewController and not a UITabBarController
EviewController is the first ViewController in the TabbedViewController, should I be calling the parent controller? And how would I do that? I want to pass data to the tabbedViewController
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.selectedName = (self.tableView.cellForRow(at: indexPath)?.textLabel?.text)!
performSegue(withIdentifier: “menu”, sender: self)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.names.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = names[indexPath.row]
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == “menu”) {
let viewController = segue.destination as! EViewController
}
}
}

the problem happens with those code
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == “menu”) {
let viewController = segue.destination as! EViewController
}
}
segue.destination should be a UITabBarController instead of EViewController, and you use as! to convert UITabBarController to be EViewController forcibly and it will be error.
in this case, you should take a look about UINavigationController and UITabBarController, the view stack is
|UITabBarController|
viewControllers:
|EViewController|
...
so you should use segue.destination.topViewController to fix this issue.

Related

cast UIButton from cell to run a query and send results to another cell

i'm querying data from a VC and sending the output to another VC that has a TableViewCell. with the results in the cell, i'm trying to run another query to Firebase and display the results in another VC that has a custom prototype cell. i'm able to manually run the queries in both instances, my issue(confusion) is how to call the IBAction button to run the query. I dont know how to cast the cell to run the query and performSegue to the thirdVC
mainVC
#IBAction func getDataPressed(_ sender: Any) {
query......
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "cell1" {
let vc = segue.destination as! secondVC
vc.data = data
self.performSegue(withIdentifier: "cell1", sender: self)
}
}
secondVC
func tableView(_ tableView: UITableView, numberOfRowsInSection section:
Int) -> Int {
return info.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath:
IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier:
"secondVcCell", for: indexPath)
as? secondVcCell {
cell.configureCell(inf: info[indexPath.row])
return cell
}
return UITableViewCell()
CustomCellDelegate
protocol CustomCellDelegate {
func callSegueFromcell(_ sender: Any?)
secondVcCell
var delegate: CustomeCellDelegate?
#IBOutlet weak var cellBtn: UIButton
#IBAction func getDataPressed2(_ sender: Any) {
query ........
}
if(self.delegate !=nil)
self.delegate.callSegueFromcell(Any)
thirdVC
func tableView(_ tableView: UITableView, numberOfRowsInSection section:
Int) -> Int {
return info2.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath:
IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "thirdVcCell",
for: indexPath)
as? ThirdVcCell {
cell.configureCell(inf1: info2[indexPath.row])
return cell
}
return UITableViewCell()
for the query, just call the function for querying in the IBAction button by typing the function within the range.
for the second cast if you are pulling from firebase then you will need to change your code to include firebase DataBase or Firestore, if you are taking it manually then you need to do the same as the first cast but make sure the indexPath is correct

Sending Data to child view controller from parent view controller

I am trying to send data from parent view controller to child view controller, whenever I override the performSegue method, the data loads to the popup view as shown below:
But what I want is show data in something like picture shown below:
I have added the popup view to the main view from didSelectRowAt indexPath method, I used the protocol method, but it didn't load the data.
my code for parent view controller is shown below:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath) as! TableViewCell
cell.customInit(noticeTitle: notificatonData[indexPath.row].notice_title,noticeDiscripetion: notificatonData[indexPath.row].notice_desc)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let popOverVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PopUpViewController")
self.addChildViewController(popOverVC)
popOverVC.view.frame = view.frame
self.view.addSubview(popOverVC.view)
popOverVC.didMove(toParentViewController: self)
performSegue(withIdentifier: "goToPopUpView", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? PopUpViewController{
destination.notificationfianlData = notificatonData[(tableView.indexPathForSelectedRow?.row)!]
}
}
You should either use segue or child
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "goToPopUpView", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? PopUpViewController{
destination.notificationfianlData = notificatonData[(tableView.indexPathForSelectedRow?.row)!]
}
select segue line and
select the main view in the popupVC and make it's background color transparent
Please try with this one. There should be no need of performSegue.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let popOverVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PopUpViewController")
self.view.addSubview(popOverVC.view)
popOverVC.notificationfianlData = notificatonData[indexPath.row]
popOverVC.view.frame = view.bounds
}
FYI. Make PopUpViewController View, background color transparent. It will show like this.

trying to pass cell.profilepic.image I get this error Thread 1: signal SIGABRT (Could not cast value of type 'UIButton' to 'UIImage')

import UIKit
trying to pass cell.profilepic.image from ViewController2 to ViewController3
in runtime when I click on the Botton (func bottone) [my Botton is
in the prototype cell of the tableView in viewController2]
I put the tableView func inside the botton's action cause I want that my pic3 (declared in ViewController3 as UIImage) is the pic I click in the TableView of my ViewController2
class ViewController2: UIViewController, UITableViewDataSource, UITableViewDelegate {
let images = ["image1", "image2", "image3"]
// here are my functions for the my TableViewCell2
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (images.count)
}
// the identifier of my prototype cell in the TableView is cell (and nome is just a label)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell2
cell.nome.text = images [indexPath.row]
cell.profilepic.image = UIImage(named: images[indexPath.row])
return (cell)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/* I put the tableView func inside the botton's action cause I want that my pic3 (declared in
ViewController3 as UIImage) is the pic I click in the TableView of my ViewController2 */
#IBAction func bottone(_ sender: Any) {
func tableView2(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell2
cell.nome.text = images [indexPath.row]
cell.profilepic.image = UIImage(named: images[indexPath.row])
performSegue(withIdentifier: "page3", sender: cell.profilepic.image)
return (cell)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "page3" {
let viewCont: ViewController3 = segue.destination as! ViewController3
viewCont.pic3 = sender as! UIImage
}
}
}

How to create segue from Detail disclosure of static cell from xib file

Have some question that I can't figure out. I have single static cell in xib file and I want to make segue from detail disclosure accessory of that cell to other view controller.
Guess that I have to use this method:
func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
self.performSegue(withIdentifier: "SegueID", sender: self) // #ERROR
}
But I have an error:
Could not cast value of type 'Lists.ListViewController'
(0x104c0e7b8) to 'UITableViewCell' (0x106875bf8).
How can I create this segue correctly?
If you want to access the cell in prepareForSegue you can try like this way.
func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
//Pass the indexPath as sender
self.performSegue(withIdentifier: "SegueID", sender: indexPath)
}
Now access that indexPath in prepareForSegue.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "SegueID" {
let nextVC = segue.destination as! DestinationVC
if let indexPath = sender as? IndexPath,
let cell = self.tableView.cellForRow(at:indexPath) as? CustomCell {
//access your cell here
}
}
}

Get cell index from tableviewcell

Hey I have this tableview controller that list restaurants from my database. what I want to do is if the cell/row is selected it opens a more detail page about the restaurant. for some reason I can't retrieve the index or its not going to the func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) to give me index here is what I have:
class HomeTableViewController: UITableViewController{
var restaurantArray = [Restaurant]()
var resTransfer: Restaurant?
var resName: String?
var dataBaseRef: FIRDatabaseReference! {
return FIRDatabase.database().reference()
}
override func viewDidLoad() {
super.viewDidLoad()
title = "Home"
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Main Menu", style: .plain, target: self, action: #selector(SSASideMenu.presentLeftMenuViewController))
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
fetchRestaurants()
}
func fetchRestaurants(){
FIRDatabase.database().reference().child("AthensRestaurants/Restaurants").observe(.value, with: { (snapshot) in
var results = [Restaurant]()
for res in snapshot.children{
let res = Restaurant(snapshot: res as! FIRDataSnapshot)
results.append(res)
}
self.restaurantArray = results.sorted(by: { (u1, u2) -> Bool in
u1.name < u2.name
})
self.tableView.reloadData()
}) { (error) in
print(error.localizedDescription)
}
}
// MARK: - Table view data source
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return restaurantArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "restaurantsCell", for: indexPath) as! RestaurantsTableViewCell
// Configure the cell...
cell.configureCell(res: restaurantArray[indexPath.row])
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("Row \(indexPath.row)selected")
resTransfer = restaurantArray[indexPath.row]
resName = restaurantArray[indexPath.row].name
print(resName as Any)
performSegue(withIdentifier: "RestaurantDetailView", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "RestaurantDetailView") {
let vc = segue.destination as! RestaurantDetailViewController
vc.resNam = restaurantArray.first?.name //instead of first should be index of cell!
print(vc.resNam! as String)
}
}
}
I am doing it like this, without segue:
func showRestaurantViewControllerWith(_ id: String) {
let storyBoard = UIStoryboard(name: "RestaurantCard", bundle: nil)
let destinationVC = storyBoard.instantiateViewController(withIdentifier: "RestaurantCard") as! RestaurantCardViewController
destinationVC.restaurant.id = id
self.navigationController?.pushViewController(destinationVC, animated: true)
}
and
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.showRestaurantViewControllerWith(self.allRestaurants[indexPath.row].id)
}
You have to use this function to fetch the index
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
print(indexPath.row)
}
It will give you the index.
First of all your code is obviously Swift 3 so the signature of didSelectRowAt is wrong.
Another solution is to pass the indexpath as sender
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Row \(indexPath.row)selected")
performSegue(withIdentifier: "RestaurantDetailView", sender: indexPath)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "RestaurantDetailView" {
let indexPath = sender as! IndexPath
let restaurant = restaurantArray[indexPath.row]
let resName = restaurant.name
print(resName!)
let vc = segue.destination as! RestaurantDetailViewController
vc.resNam = resName
}
}
or still easier to connect the segue to the table view cell. Then you can delete didSelectRow... because prepare(for is called directly and the cell is passed as the sender parameter.
PS: Why is the property name optional? In real life have you ever heard about a restaurant without a name?