Sending Data to child view controller from parent view controller - swift

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.

Related

Opening TabbedBarController from TableViewController

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.

storyboard elements not visible in view controller after segue

I added a view controller (vc2) with some simple form elements to it to my storyboard and made a segue ctrl-dragging from an existing tableviewcontroller (vc1) which is triggered by a trailing swipe button
I can see output from the print function (in the vc2 code below )in the debugger but my form elements aren't visible. And for some reason I had to manually set the background color, which had defaulted to black, not what was set on storyboard. I think this is related to the way I am loading vc2, but my attempts to change the code to a normal performSegueWithIdentifier caused a
'NSInvalidArgumentException', reason: 'Receiver () has no segue with
identifier
Then I deleted and remade the segue with no effect. So I changed the code back to this, which works but doesn't render the storyboard elements.
func clickView(forRowAtIndexPath indexPath: IndexPath) {
let myContents = UnitComponents[indexPath.row]
print("Clicked Report \(self.ProjectID) \(self.ShipListID) \(self.UnitName) \(myContents.sku)")
self.Sku = myContents.sku
let vc = ComponentViewController()
vc.Sku = myContents.sku
navigationController?.pushViewController(vc, animated: true)
}
Here is the vc2 code
import UIKit
class ComponentViewController: UIViewController {
var Sku = ""
var UnitName = ""
var ShipListID = ""
var ProjectID = ""
#IBOutlet var damageDesc: UITextView!
#IBOutlet var repairCost: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
print("Hello World \(Sku) \(UnitName) \(ShipListID) \(ProjectID)");
// Do any additional setup after loading the view.
}
#IBAction func saveReport(_ sender: Any) {
print("damageDesc \(String(describing: damageDesc ?? nil))")
print("repairCost \(String(describing: repairCost ?? nil))")
}
}
How can I fix my code so the storyboard layout etc gets loaded and I can see the form elements in the app?
Is this the wrong way to go to another view controller? I ask because it seems like some SO questions around this topic suggest it isn't calling the storyboard correctly. I'm searching for a swift 5 example of how to do this and only find references to instantiateViewControllerWithIdentifier("ViewController") which doesn't seem to be in swift 5
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = ShippingUnitsTableViewController()
vc.ShipListID = ShipLists[indexPath.row].ListID
vc.ProjectID = ProjectID
navigationController?.pushViewController(vc, animated: true)
}
you need to specify the storyboard in which the viewcontroller is located, and then instantiate the viewcontroller from that storyboard. Replace your func with the below one:-
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "ShippingUnitsTableViewController") as! ShippingUnitsTableViewController
vc.ShipListID = ShipLists[indexPath.row].ListID
vc.ProjectID = ProjectID
navigationController?.pushViewController(vc, animated: true)
}
and make sure (inside the Main.storyboard file) you give ViewController's (which needs to be presented) Storyboard ID to be ShippingUnitsTableViewController in the attributes inspector (see the image below):-
can you try
func clickView(forRowAtIndexPath indexPath: IndexPath)
instead, didSelectRow of tableview delegate methods or view controller's performSegueWithIdentifier ?
Ok the solution to this problem required changing how I moved between view controllers. The didSelectRowAt indexPath method below does not utilize the storyboard, which causes the destination view controller to be sort of an orphan and unaware of the storyboard segues.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = ShippingUnitsTableViewController()
vc.ShipListID = ShipLists[indexPath.row].ListID
vc.ProjectID = ProjectID
navigationController?.pushViewController(vc, animated: true)
}
I changed didSelectRowAt indexPath to this, and added the bits of necessary info to the prepareSegue method as shown below.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.ListID = ShipLists[indexPath.row].ListID
performSegue(withIdentifier: "UnitsVC", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "UnitsVC"{
let nextViewController = segue.destination as? ShippingUnitsTableViewController
nextViewController!.ProjectID = self.ProjectID
nextViewController!.ShipListID = self.ListID
}
}

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?

Passing Data between TableView in Swift

I have two tableView running in my project.I am trying to pass(copy) my first tableViewcell data to second tableView.I using tableView row action method to pass data.My partial code below...
First VC:
var tableView: UITableView!
var DataArray = ["Bus","Helicopter","Truck","Boat","Bicycle","Motorcycle","Plane","Train","Car","S cooter","Caravan"]
var sendSelectedData = NSString()
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let copyAction = UITableViewRowAction(style: UITableViewRowActionStyle.normal, title: "Pass Data") { (UITableViewRowAction, NSIndexPath) -> Void in
print("Button Pressed") // Xcode Console prints **Button Pressed** when swipe action performed.
self.performSegue(withIdentifier: "send", sender: self)
}
return [copyAction]
}
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
self.performSegue(withIdentifier: "send", sender: self)
// segue.destination as! tableController
let indexPath = tableView.indexPathForSelectedRow
let currentCell = tableView.cellForRow(at: indexPath!)!
self.sendSelectedData = (currentCell.textLabel?.text)! as String as NSString
let viewController = segue.destination as! tableController
viewController.labelcell = ([self.sendSelectedData as String])
print(self.sendSelectedData) // no result
}
Second VC:
var labelcell = [String]()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: textCellIdentifier, for: indexPath as IndexPath) as UITableViewCell
cell.textLabel?.text = labelcell[indexPath.row] as? String
tableView.reloadData()
return cell
}
Above code looks like passing data to my second VC(segue).But, I am only getting a empty tableview..
Okay after testing it, it turns out, that you're using an incorrect prepareForSegue function. You are not using "prepareForSegue", you are creating a function called prepareForSegue - since the syntax has changed in Swift 3. This one will get called and you can pass data.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "send" {
let selectedIndex = sender as! NSIndexPath
let currentCell = tableView.cellForRow(at: selectedIndex as IndexPath)! as! Cell
self.sendSelectedData = (currentCell.label?.text)! as String as NSString
print(self.sendSelectedData) // till here it worked for me - it is filled with my label.text
// I don't know what this is "viewController.labelcell", so you have to to know how to go on from here on
viewController.labelcell = ([self.sendSelectedData as String])
}
}
Also you need to pass the indexPath:
self.performSegue(withIdentifier: "send", sender: indexPath)
Exactly like this:
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let copyAction = UITableViewRowAction(style: UITableViewRowActionStyle.normal, title: "Pass Data") { (UITableViewRowAction, NSIndexPath) -> Void in
print("editActionsForRowAt called") // Xcode Console prints **Button Pressed** when swipe action performed.
self.performSegue(withIdentifier: "send", sender: indexPath)
}
return [copyAction]
}
This worked in my testing project.
Also beware: Cell is a custom subclass of UITableViewCell I have created and label is an UIOutlet of a label element for my test project.