Change Text for NavigationController back button with TableView Delegate - ios

I'm trying to change the text that follows the < on the Navigation Controller. I successfully accomplished this in a UIViewController with a TableView that is its own DataSource and Delegate with code like this:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var newVC = NewViewController()
self.title = "HomeVC"
navigationController?.showViewController(newVC, sender: indexPath)
}
When "HomeViewController" is presented, the back button on the Navigation Controller shows "< HomeVC" - the ViewController that we just came from.
Now, I'm trying to accomplish this with another UIViewController that has a TableView, but the DataSource and Delegate are in a separate file. Following the same logic as above, this is what I tried:
class CalendarTableDataSource: NSObject, UITableViewDataSource, UITableViewDelegate {
...
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var newVC = NewViewController()
self.navController?.title = "HomeVC" // ----> did not work
HomeViewController().title = "HomeVC" // ----> did not work
self.navController?.showViewController(newVC, sender: indexPath)
}
}
Ideas, anyone? Assuming that I want to keep the DataSource and Delegate in a separate file.

Related

Updating tableView from another ViewController using segues

I have a viewController with a tableView, and another viewController that contains data that I'm trying to pass to the tableView. To add entries to the tableView I used segues, but the problem with segues is that they don't update the tableView permanently. They merely create an instance of the ViewController and add the entry there, but the original object remains unchanged. Both ViewControllers are part of a tab bar controller. What I want is to update the table permanently. Meaning, I want to be able to navigate to the viewController where the table is defined and see that's an entry has been added. Here's the code for the viewController with the tableView:
import UIKit
class FavoritesViewController: UIViewController {
public var shops = [
"hello world",
"hello world",
"hello world"
]
#IBOutlet weak var table: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
table.delegate = self
table.dataSource = self
table.reloadData()
}
}
extension FavoritesViewController: UITableViewDelegate, UITableViewDataSource{
func add(_ shopName: String) {
print(shopName)
shops.append(shopName)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return shops.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell",for: indexPath)
cell.textLabel?.text = shops[indexPath.row]
return cell
}
// define the action. In this case "delete"
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
return .delete
}
// do the actual deleting
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
tableView.beginUpdates()
shops.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
tableView.endUpdates()
}
}
}
And here's how I'm trying to update (in the case adding an entry) the tableView in the other viewController:
class MainViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate{
public var shopName:String?
// there are also many other vars, but they're irrelevant
public var favoritesDestinationVC = FavoritesViewController()
// prepares the data for the segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToFavs" {
favoritesDestinationVC = segue.destination as! FavoritesViewController
if let newShopName = shopName {
favoritesDestinationVC.shops.append(newShopName)
}
}
}
}
However, when I add the entry the to the table, the segue creates an instance of FavoritesViewController, adds that entry there, and then displays it in a popup window like this:
But when I dismiss this window the changes disappear (the tableView remains the same; 3 times "Hello World").
I want the changes to be saved in the tableView after dismissing this window. Any idea on how to do that? On how to make those changes permanent?
By your explanation, it looks like. Segue is defined as presenting FavoritesViewController modally. and this behavior is expected. By your implementation. Since you are not updating the view controller object which is part of the tab bar controller.
To make the changes in the controller in tab bar controller, Either you access that object using tabcontroller.viewcontrollers. Communicate using another way like a delegate or notification.
Edit:
It totally depends on where you want to access FavoritesViewController.
If you want to access from TabBarViewController (based on your view hierarchy it may change. be careful about index and typecasting):
let favVC = self.viewControllers?[1] as! FavoritesViewController
favVC.shops.append(newShopName)
If you want to access from a view controller which is part of same tab bar controller:
var favVC = self.tabBarController?.viewControllers?[1] as! FavoritesViewController
favVC.shops.append(newShopName)
Note: Viewcontrollers's index depends on viewcontroller order in your tab bar controller. And type casting depends upon your view hierarchy.

How can I pass data from "didSelectRowAt" to another VC without presenting it or a segue?

What I basically want is I want to press on a row in my TableViewController which then takes, for example, the text that the row has and passes it to a ViewController that is currently not present. Like when you click on a song in the Spotify app and it plays it without presenting anything but the song details are shown in the mini-player.
Does anyone have a clue how to do that?
Well you can do that but you need to initialize your View Controller first for you to access its properties like:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "DestinationVc") as? DestinationVc
vc?.text = "TextToBePassed"
}
And there it is without presenting it but I don't get it why you don't want to present or show it but that's how it is done based on your question. Thanks :)
If you have created the UI via XIB or programatically then follow this approach:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let nextVC = NextViewController()
nextVC.text = model?[indexPath.row].text // If you are using model or if you have stored the data in the array then nextVC.text = yourArray[indexPath.row]["text"]
self.navigationController?.pushViewController(nextVC,animated: true)
}
Also, in the NextViewController, you have to add text. Like this:
class NextViewController: UIViewController {
var text = String()
//MARK:- View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
print(text) //This will print the text passed from previous VC
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = NextViewController()
vc.title = "\(Title)"
self.navigationController?.pushViewController(vc,animated: true)
}
Using this method can help you in passing the data to another Controller without using segue.
Assuming this is for iOS as the question doesn't specify.
In the tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) method in your UITableViewDelegate, you can grab the cell's text with
let cell = tableView.cellForRow(at: indexPath)?.textLabel?.text // cell: String?
You can then assign this to a global variable if you wish, or if you maintain a reference to the non-present view controller, you can give it a property to store this text and assign it before you call performSegue(withIdentifier identifier: String, sender: Any?).

How can you use TableView items to access View Controllers in Swift 2?

I'm attempting to create my first iOS app that I plan to publish into the App Store. It's a tabbed application with TableView embedded into each View Controller. Here's the code for one of my tabbed View Controllers:
import Foundation
import UIKit
class AU: UITableViewController {
var textArray = ["001", "002", "003", "004", "005", "006", "007", "008", "009", "010", "011", "012", "013", "014", "015", "016", "017", "018", "019", "020", "021", "022", "023", "024", "025", "026", "027", "028", "029", "030", "031", "032", "033", "034", "035", "036", "037", "038", "039", "040", "041", "042" ]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("AUCell") as UITableViewCell!
cell.textLabel?.text = textArray[indexPath.row]
return cell
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return textArray.count
}
}
So, basically, when the user taps on one of the items in the textArray, I want to switch to a different View Controller. I'm currently writing this in Swift 2.
Every UIViewController embedded in a UITabBarController has a reference back to the UITabBarController with its tabBarController property. To change the selected view controller of the tab bar, set the tab bar's selectedViewController:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if (indexPath.row == 0) { // check the row that was selected
self.tabBarController?.selectedIndex = 0 // select a new tab on the tab bar, changing the selected view controller
}
}
First of all create a few ViewControllers in your main storyboard and give them storyboard ids
Create list of names :
let viewControllersNames = ["ViewController_1","ViewController_2","ViewController_3"]
and in the method :
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let vc = self.storyboard?.instantiateViewControllerWithIdentifier(self.viewControllersNames[indexPath.row])
self.navigationController?.pushViewController(vc!, animated: true)
}
Good luck !

Why is my variable is changing in printLn but not in the tableview Swift

I've spent ages trying to solve this but with no resolve.
I've finally got to a point where I am pulling my data from one one controller and moving it to the destination controller when I unwind segue, however, when the variable is only reloading in the println but not in the tableview.
I'll try to explain this a bit better with my code as it sounds complicated.
I have a label on one controller which when pressed, presents a UISearchController modally. when you select a cell, it dismisses the view with an unwind segue and passes the data from the cell back to the previous controller to change the label of the button.
I set the label.text in a variable at the top of the initial controller like so
var selectedStation = "Search Stations"
here is my shoddy named function which is used to println the variable to see if it works which it does:
func updateStuff() {
println("you selected \(selectedStation)")
tableView.reloadData()
}
and i declare the label text in my cellForRowAtIndexPath like so:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("searchFieldCell", forIndexPath: indexPath) as! searchFieldTableViewCell
cell.backgroundView = UIImageView(image: UIImage(named: "red-full"))
cell.destinationLabel.text = selectedStation
}
then in my UISearchController i have the following to pass that variable back
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
println(stationArray[indexPath.row])
selectedStation = stationArray[indexPath.row]
self.performSegueWithIdentifier("unwindToSet", sender: self)
}
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.destinationViewController .isKindOfClass(SetAlertController) {
var VC = segue.destinationViewController as! SetAlertController
VC.selectedStation = self.selectedStation
VC.updateStuff()
}
}
essentially my controller retrieves the updated variable but doesn't update it in the tableview, it only updates it in the println.
i set up a quick demo project with the following viewcontrollers:
class MainViewController: UIViewController {
#IBOutlet weak var label: UILabel!
#IBAction func unwind(segue: UIStoryboardSegue) {
println("unwinding")
if let sourceViewController = segue.sourceViewController as? ModalViewController {
label.text = sourceViewController.selectedText
}
}
}
tapping on the label results in the modalviewcontroller to show. i set this up in storyboard.
class ModalViewController: UITableViewController {
var selectedText: String?
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath)!
selectedText = cell.textLabel?.text
performSegueWithIdentifier("unwindToSet", sender: self)
}
}
everything works as expected! feel free to ask if anything is unclear...
you can find the demo project here: https://www.dropbox.com/sh/u2blzmo3ztaaini/AADq8hOMMS71wvBH1eH4Bz_4a?dl=0

How to change view when tapping button in a custom UITableViewCell

Usually, I change view like this:
var goBackToMainView:MainViewController = self.storyboard?.instantiateViewControllerWithIdentifier("navigation2") as MainViewController
self.presentViewController(goBackToMainView, animated: true, completion: nil)
But if I try to do this in my custom UITableViewCell when the user tap a button, it gives me errors like customTableViewCell does not have a member named 'storyboard' and 'presentViewController'
How can I change views in my TableViewCell ?
Have you tried adding as a subview?
Example:
var tableViewCell = UITableViewCell(frame: aFrame)
tableViewCell.addSubview(aView)
Why do it in the UITableViewCell subclass? You should be doing your view management in the ViewController.
In your view controller:
import UIKit
// Take note of UITableViewDelegate, you'll need it to be able to use
// tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
class MyTableViewController: UITableViewController, UITableViewDelegate {
// Assuming that you have a storyboard variable in AppDelegate
let appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
// .. more code here like viewDidLoad, etc.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var viewController = appDelegate.storyboard.instantiateViewControllerWithIdentifier("MainViewController") as MainViewController
// This will probably appear as a modal
self.presentViewController(viewController, animated: true, completion: nil)
}
}
Note: I just did a quick playground for the code above so you may need to unwrap optionals.
If you have your view controller embedded in a navigation controller, you might want to use Unwind Segues. More information about that here: What are Unwind segues for and how do you use them?
Cheers!

Resources