How do I pass indexPathForSelectedRow into a UITabView via a UITabBarController? - ios

I'm trying to segue from a UITableView to a specific tab within a UITabBarController. While googling, I found two sets of info that seem to indicate how to do, but neither were using a UITableView as the source.
The first source is this wonderfully written answer I found here on StackOverflow: How to make a segue to second item of tab bar?
The second source was this site: http://www.codingexplorer.com/segue-uitableviewcell-taps-swift/
I have been attempting to combine the two for my app. Below is a truncated version of my originating UIViewController (I can post the full one if needed, just most the code isn't related to this segue, I don't think):
class BonusListViewController: UITableViewController {
// MARK: - Table View Configuration
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isFiltering() {
print("Showing \(filteredBonuses.count) Filtered Results")
return filteredBonuses.count
}
print("Found \(bonuses.count) rows in section.")
return bonuses.count
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRow(at: indexPath as IndexPath, animated: true)
let row = indexPath.row
}
private var nextViewNumber = Int()
#IBAction func secondView(_ sender: UITapGestureRecognizer) {
self.nextViewNumber = 2
self.performSegue(withIdentifier: "tabBar", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "tabBar" {
let destination = segue.destination as! TabBarViewController
switch (nextViewNumber) {
case 1:
destination.selectedIndex = 0
case 2:
destination.selectedIndex = 1
if self.isFiltering() {
destination.bonus = filteredBonuses[(tableView.indexPathForSelectedRow?.row)!]
} else {
destination.bonus = bonuses[(tableView.indexPathForSelectedRow?.row)!]
}
default:
break
}
}
}
}
My issue resolves around trying to pass the tableView.indexPathForSelectedRow?.row over to the UITabViewController. In the prepare(for segue) near the end of the above code snippet I'm getting a compile error for the destination.bonus = lines that says,
Value of type 'TabBarViewController' has no member 'bonus'
This is technically true as I'm just trying to pass through the TabBarViewController to the second tab it controls.
How can I fix the above to let me tap on a cell, and then pass the selected row over to the target UITabView?
EDIT: In case it helps, here is a picture of the storyboard.

Value of type 'TabBarViewController' has no member 'bonus'
Because 'TabBarViewController' has no property named bonus
You can subclass TabBarViewController add property bonus
and set it from segue like
guard let destination = segue.destination as? YourTabbarSubClass else {return }
and you can access bonus by destination.bonus
Now when you need that bonus from tabbar controllers you can use it with (self.tabbarController as! YourTabbarSubClass).bonus
EDIT
class TabBarViewController: UITabBarController {
// Add property bonus here
var bouns:BounsStruct?
}
Now From your view controller where you need that
class YourFirstTabVC:UIVIewController {
//where you need that
self.bouns = (self.tabbarController as! TabBarViewController).bouns
self.tableview.reloadData()
}

Related

Swift how to trigger "prepare for segue" before target view load?

I am trying to load data from firestore(google database) and want to show on tableview.
so in the first VC, by prepare function, get data from database, and transfer to second VC(tableview). but There is one problem. I learned that prepare function goes before viewdidload, in my application, prepare function goes after second VC load.
here's my code.
first VC
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let docRef = db.collection("Posting").getDocuments(){(querySnapshot, err) in
if let err = err{
print("errror getting documents")
}else{
for document in querySnapshot!.documents{
print("\(document.documentID) => \(document.data())")
self.savePostings.append(document.data())
}
print("\n\n\(self.savePostings)")
}
let vc = segue.destination as! PostingListTableViewController
vc.updatedPostings = self.savePostings
vc.testPrint = "잉 기모찌"
print("배열 전달 확인\n\(vc.updatedPostings)\n\n\(self.savePostings)")
}
}
Second VC (Tableview)
class PostingListTableViewController: UITableViewController {
//private var postings: Array<[String:Any]> = []
private var documents: [DocumentSnapshot] = []
var updatedPostings: Array<[String:Any]?> = []
var testPrint:String = ""
override func viewDidLoad() {
super.viewDidLoad()
print("view did load")
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return updatedPostings.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myTableCell", for: indexPath)
cell.textLabel?.text = updatedPostings[indexPath.row]!["text"] as! String
// Configure the cell...
return cell
}
}
as #vadian correctly said, your problem is that you're making an async call.
prepare(for segue is called before viewDidLoad, but you're updating your properties some time after that, when your request finishes, and that's after viewDidLoad.
Instead of that I suggest you the following:
Remove your segue, add identifier to the destination view controller
Inside tableView:didSelectRowAtIndexPath: run your getDocuments(or inside IBAction if this is a button segue)
2.1. you can show some progress indicator so user wold know the reason of delay
In completion create your view controller from storyboard using instantiateViewControllerWithIdentifier and present it manually. You don't need to wait for prepare(for segue to set your properties in this case.
If your segue is calling from the cell, you can add your view controller as a delegate, like this:
then you need to conform your view controller to UITableViewDelegate, and didSelectRowAt method will be called when user press a cell. You can get cell number from indexPath.row
extension PostingListTableViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let docRef = db.collection("Posting").getDocuments(){(querySnapshot, err) in
if let err = err{
print("errror getting documents")
}else{
for document in querySnapshot!.documents{
print("\(document.documentID) => \(document.data())")
self.savePostings.append(document.data())
}
print("\n\n\(self.savePostings)")
}
// not sure if completion of getDocuments is called on main thread, if it does - you don't need this line
DispatchQueue.main.async {
let vc = storyboard!.instantiateViewController(identifier: "storyboard_identifier") as! PostingListTableViewController
vc.updatedPostings = self.savePostings
vc.testPrint = "잉 기모찌"
present(vc, animated: true)
print("배열 전달 확인\n\(vc.updatedPostings)\n\n\(self.savePostings)")
}
}
}
}
If you're performing this segue from a plain button, not from a cell, you can do the same with #IBAction:
#IBAction #objc func push() {
let docRef = db.collection("Posting").getDocuments(){(querySnapshot, err) in
if let err = err{
print("errror getting documents")
}else{
for document in querySnapshot!.documents{
print("\(document.documentID) => \(document.data())")
self.savePostings.append(document.data())
}
print("\n\n\(self.savePostings)")
}
// not sure if completion of getDocuments is called on main thread, if it does - you don't need this line
DispatchQueue.main.async {
let vc = storyboard!.instantiateViewController(identifier: "storyboard_identifier") as! PostingListTableViewController
vc.updatedPostings = self.savePostings
vc.testPrint = "잉 기모찌"
present(vc, animated: true)
print("배열 전달 확인\n\(vc.updatedPostings)\n\n\(self.savePostings)")
}
}
}
What I would do first is to DELETE ❌ the segue you've probably created by drag and drop from the button on VC1 to VC2. Replace it by a regular segue which is not attached to any UI component so that you can trigger it manually in code (from its identifier, don't forget to provide one). It will allow you to first perform some asynchronous code, and only when getting the callback trigger the navigation (if data fetch is successful).
To create such a segue:
click on your VC1 in the storyboard => A small rectangle with icons should be now displayed right above the VC1
Ctrl + drag from the yellow icon (probably at the most left of that rectangle) to the VC2 (on main view, does not rally matter where you drop it as long as it is on VC2)
Provide identifier after having clicked on the newly created segue so that you can trigger it from code
That was for the segue, but now, when to trigger it?
Create an an #IBAction on the button which is suppose to trigger the fetch + navigation (or equivalent, like didSelectRowAtIndexPath)
This IBAction should call another method like the following:
private func fetchPostingAndNavigateIfSuccessful() {
// Should probably first set the activity indicator to `.startAnimating()`
let docRef = db.collection("Posting").getDocuments() { [weak self] querySnapshot, error in
// Should probably set the activity indicator to `.stopAnimating()`
guard error != nil,
let documents = querySnapshot?.documents else {
print("error getting documents") //probably a good place to display an alert
return
}
let postingsData = documents.map { $0.data() }
self?.performSegue(withIdentifier: "NavigateToPostingsSegue", sender: postingsData)
}
}
Your prepare for segue would then look like that:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if let postingListTableViewController = segue.destination as? PostingListTableViewController,
let postingsData = sender as? [[String:Any]] {
postingListTableViewController.updatedPostings = postingsData
}
}

swift, tableView selectedTypes buttons

i need an help, see this class
import UIKit
protocol TypesTableViewControllerDelegate: class {
func typesController(controller: TypesTableViewController, didSelectTypes types: [String])
}
class TypesTableViewController: UITableViewController {
let possibleTypesDictionary = ["bakery":"Bakery", "bar":"Bar", "cafe":"Cafe", "grocery_or_supermarket":"Supermarket", "restaurant":"Restaurant"]
var selectedTypes: [String]!
weak var delegate: TypesTableViewControllerDelegate!
var sortedKeys: [String] {
return possibleTypesDictionary.keys.sort()
}
// MARK: - Actions
#IBAction func donePressed(sender: AnyObject) {
delegate?.typesController(self, didSelectTypes: selectedTypes)
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return possibleTypesDictionary.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TypeCell", forIndexPath: indexPath)
let key = sortedKeys[indexPath.row]
let type = possibleTypesDictionary[key]!
cell.textLabel?.text = type
cell.imageView?.image = UIImage(named: key)
cell.accessoryType = (selectedTypes!).contains(key) ? .Checkmark : .None
return cell
}
// MARK: - Table view delegate
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let key = sortedKeys[indexPath.row]
if (selectedTypes!).contains(key) {
selectedTypes = selectedTypes.filter({$0 != key})
} else {
selectedTypes.append(key)
}
tableView.reloadData()
}
}
here the user can tap a cell of the tableView so that his prefer types are used on the next viewController for a search, now i need to build a class that do the same thing but there is no a tableview rather only 6 buttons in a view that the user can tap (so a viewController with only 6 different buttons to tap). The problem is that i don't know how to pass to the next viewController what buttons have been pressed and what are not, how can i build this class?
here is the function in the other class that need to know what buttons have been pressed
func fetchNearbyPlaces(coordinate: CLLocationCoordinate2D) {
mapView.clear()
dataProvider.fetchPlacesNearCoordinate(coordinate, radius:searchRadius, types: searchedTypes) { places in
for place: GooglePlace in places {
let marker = PlaceMarker(place: place)
marker.map = self.mapView
where is "types: serchedTypes"
What you wanna do is called delegation here is how you do it:
Make a protocol like this one:
protocol TransferProtocol : class
{
func transferData(types:[String])
}
Make the view controller with the buttons conform to that protocol, I like to do it by adding extensions to my classes like so:
extension ButtonsViewController:TransferProtocol{
func transferData(types:[String]){
//Do whatever you want here
}
}
Declare a variable in your Table View Controller class with the protocol you created as its type, this is called a delegate
weak var transferDelegate:TransferProtocol?
Before you segue to the Buttons View Controller you want to set that view controller as the delegate you just created like so:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as? ButtonsViewController
transferDelegate = vc
vc?.transferData(types: selected)
}
If done correctly you should be able to work with the array you built in the Table View Controller(TypesTableViewController)

Prepare for segue lead to "found nil while unwrapping an Optional value"

Im attempting to perform a segue from a table view cell that has one value "the floor number" to another vc which will be used to assign the number of rooms per floor. I have break points throughout the function to verify is the value that is passed is nil. The point is that it is not nil and it has the value "floor number". When i attempt to assign that value to a variable in the next VC i get the unwrapping optional found nil error. Could someone please help me out with this one as I don't see where this is coming from is the debugger shows me that I have a value inside the variable i want to pass. Code listing below. Thank you:
class AssignNumberOfRoomsForFloorsVC: UITableViewController {
//MARK: - Properties
private var managedObjectContext: NSManagedObjectContext!
private var storedFloors = [Floors]()
//MARK: - Actions
override func viewDidLoad() {
super.viewDidLoad()
managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
loadFloorData()
self.tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
private func loadFloorData() {
let request: NSFetchRequest<Floors> = Floors.fetchRequest()
request.returnsObjectsAsFaults = false
do {
storedFloors = try managedObjectContext.fetch(request)
}
catch {
print("could not load data from core \(error.localizedDescription)")
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return storedFloors.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "floor cell", for: indexPath) as! FloorCell
let floorItem = storedFloors[indexPath.row]
cell.floorNumberTxt.text = String(floorItem.floorNumber)
return cell
}
// MARK: - Navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var selectedRow = self.tableView.indexPathForSelectedRow
let floorItem = storedFloors[(selectedRow?.row)!]
let destinationController = segue.destination
if let assignRoomsVC = destinationController as? DeclareRoomsVC {
if let identifier = segue.identifier {
switch identifier {
case "assign number of rooms":
assignRoomsVC.floorNumberTxt.text = String(floorItem.floorNumber) // ERROR HAPPENS ON THIS LINE
assignRoomsVC.selectedFloor = floorItem.floorNumber
default: break
}
}
}
}
}
In the prepare for segue method, the view hasn't loaded yet and thus your storyboard hasn't created any of your views.
It looks like floorNumberTxt is probably a text field or a label. You're trying to assign a property of this view, but that view doesn't exist yet. Thus the "found nil while unwrapping an Optional value” error message.
Try adding let _ = assignRoomsVC.view before assigning any of the view controller's view properties. By accessing the view (assignRoomsVC.view), you'll force the view load and instantiate all its subviews.

Perform a segue over multiple Controller

How is it possible to perform a segue from a UITabBarController Child ViewController to a DetailView of an UITableViewController with UINavigationController in between?
There is a TabBarController with two childs, FirstView(Most Viewed Symbol) and NavigationController(Contacts Symbol).
The FirstView has a button, which should perform a segue to Show Profile VC.
The NavCont has a TableView with subclass All ProfilesTVC with a prototype cell as child.
AllProfilesTVC has an array with three names which are displayed by the reused cell.
Which viewcontroller do I have to instantiate and prepare at the function prepareForSegue in FirstView (HomeVC) and where should the segue, which I create in storyboard, direct to? So that I'm at "John's" DetailView.
And is it possible that when I performed a segue to ShowProfileVC, that I can push the Back Button to return to the All ProfilesTVC?
There is a github repo for those who want to try at github repo
FirstView / HomeVC.swift
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// what do we do here ???
}
AllItemsTVC
class AllItemsTVC: UITableViewController {
let profiles = ["Joe", "John", "Ken"]
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return profiles.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UITableViewCell
let profile = profiles[indexPath.row] as String
cell.textLabel?.text = profile
return cell
}
#IBAction func cancelFromShowProfile(segue: UIStoryboardSegue) {
}
// MARK: - Navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let identifier = segue.identifier {
switch identifier {
case "ShowProfile":
if let showProfileVC = segue.destinationViewController as? ShowProfileVC {
// pass the data to the destinationVC
let selectedProfile = profiles[tableView.indexPathForSelectedRow()!.row] as String
showProfileVC.name = selectedProfile
}
default: break
}
}
}
ShowProfileVC
class ShowProfileVC: UIViewController {
#IBOutlet weak var textLabel: UILabel! {
didSet {
textLabel.text = name
}
}
var name = "Label"
override func viewDidLoad() {
super.viewDidLoad()
}
}
Thanks for any help.
You cannot do this with a segue, but that's not a problem because you can do it quite simply in code. Just give your view controllers an identifier in storyboard and instantiated them via this identifier with the appropriate UIStoryboard API.
Start by switching to the other tab bar item in code, and then first tell the navigation controller to popToRootViewController, after which you can push all the necessary controllers onto the navigation stack in turn. You can do all the configuration you normally do in prepareForSegue just before pushing the controllers.
The trick is to do it all with animated set to false except the last step.

Push segue from UITableViewCell to ViewController in Swift

I'm encountering problems with my UITableViewCells. I connected my UITableView to a API to populate my cells.
Then I've created a function which grabs the indexPath.row to identify which JSON-object inside the array that should be sent to the RestaurantViewController.
Link to my Xcode Project for easier debugging and problem-solving
Here's how my small snippet looks for setting the "row-clicks" to a global variable.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
i = indexPath.row
}
And here's my prepareForSegue() function that should hook up my push-segue to the RestaurantViewController.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "toRestaurant"{
let navigationController = segue.destinationViewController as UINavigationController
let vc = navigationController.topViewController as RestaurantViewController
vc.data = currentResponse[i] as NSArray
}
}
And here's how I've set up my segue from the UITableViewCell
Here's my result, I've tried to click every single one of these cells but I won't be pushed to another viewController...I also don't get an error. What is wrong here?
Tried solutions that won't work
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "toRestaurant"{
let vc = segue.destinationViewController as RestaurantViewController
//let vc = navigationController.topViewController as RestaurantViewController
vc.data = currentResponse[i] as NSArray
}
}
The problem is that you're not handling your data correctly.
If you look into your currentResponse Array, you'll see that it holds NSDictionaries but in your prepareForSegue you try to cast a NSDictionary to a NSArray, which will make the app crash.
Change the data variable in RestaurantViewController to a NSDictionary and change your prepareForSegue to pass a a NSDictionary
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if let cell = sender as? UITableViewCell {
let i = redditListTableView.indexPathForCell(cell)!.row
if segue.identifier == "toRestaurant" {
let vc = segue.destinationViewController as RestaurantViewController
vc.data = currentResponse[i] as NSDictionary
}
}
}
For Swift 5
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if let cell = sender as? UITableViewCell {
let i = self.tableView.indexPath(for: cell)!.row
if segue.identifier == "toRestaurant" {
let vc = segue.destination as! RestaurantViewController
vc.data = currentResponse[i] as NSDictionary
}
}
}
The following steps should fix your problem. If not, please let me know.
Remove your tableView(tableView, didSelectRowAtIndexPath:) implementation.
Make data on RestaurantViewController have type NSDictionary!
Determine the selected row in prepareForSegue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if let cell = sender as? UITableViewCell {
let i = tableView.indexPathForCell(cell)!.row
if segue.identifier == "toRestaurant" {
let vc = segue.destinationViewController as RestaurantViewController
vc.data = currentResponse[i] as NSDictionary
}
}
}
Dropbox link to stack3 directory
I am having difficulty understanding why your software is much different than a standard 2 level tableview structure. So I coded a short example which you can access from this link. I have also included the sources code below.
The program mimics what you have (as best as I understood it). Table Controller 1 segues to Table Controller 2 from the tableview cell. I had no issues with segue-ing. Notice that I do not have nor need to augment the Storybook to initiate the segue.
I have embedded both the controllers in Navigation Controllers. My experience is that it saves a lot of effort to set up the navigation.
Alternately, I could have control-dragged from the first TableViewController symbol on top of the screen to the second controller and set up the segue.
I used a global variable (selectedRow) although it is not a recommend practice. But you just as easily use the prepareForSegue to set a variable in the RestaurantTableViewController (I show an example)
Finally, I recommend checking the Connections Inspector (for the table view cell in the first controller) to confirm that there is a segue to the second controller. If you control-dragged properly there should be confirmation prompt as well as an entry in the Connections Inspector.
Unfortunately I just cant get the code properly formatter
import UIKit
var selectedRow = -1
class TableViewController: UITableViewController {
var firstArray = ["Item1","Item2","Item3","Item4"]
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return firstArray.count
}
let nameOfCell = "RestaurantCell"
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(nameOfCell, forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.text = firstArray[indexPath.row]
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedRow = indexPath.row
}
// MARK: - Navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let vc = segue.destinationViewController as RestaurantTableViewController
// can write to variables in RestaurantTableViewController if required
vc.someVariable = selectedRow
}
}
import UIKit
class RestaurantTableViewController: UITableViewController {
var secondArray = ["Item 2.1", "Item 2.2", "Item 2.3", "Item 2.4"]
var someVariable = -1
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return secondArray.count
}
let nameOfCell = "RestaurantCell"
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(nameOfCell, forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.text = secondArray[indexPath.row]
if indexPath.row == selectedRow {
cell.textLabel!.text = cell.textLabel!.text! + " SELECTED"
}
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedRow = indexPath.row
}
}
I noticed that in your screenshot of your storyboard, the segue is connecting the first prototype cell to the RestaurantViewController. This prototype cell looks like it's the "Basic" style of cell with a disclosure indicator accessory on the right. But look at the screenshot of your app running. The table is being populated with cells that appear to be the "Subtitle" style of cell without a disclosure indicator accessory on the right.
The reason that your segue is never firing no matter what you do is that the segue is only configured to work for a specific prototype cell, but that prototype cell is never being used when you populate the table. Whatever you're doing in tableView:cellForRowAtIndexPath:, you're not using the prototype cell that you want.
#Starscream has the right idea dequeueing the right cell with the right identifier and matching it with the identifier of the prototype cell in Interface Builder. The crash that you're getting even after doing that might be because of the previous problem mentioned in the comments above. Your segue in the storyboard is clearly pointing to a UITableViewController. Your code in prepareForSegue:sender: should be let vc = segue.destinationViewController as RestaurantViewController, as long as RestaurantViewController is a subclass of UITableViewController. You'll crash if you try to cast it as a UINavigationController. Also make sure that the class for the destination UITableViewController in the storyboard is listed as RestaurantController in the Identity Inspector pane. You'll crash if your program compiles thinking that the storyboard just contains a generic UITableViewController there.
Getting back to the original problem more, I don't know how you've implemented tableView:cellForRowAtIndexPath:, which might be crucial. Maybe it's not so simple. Maybe you plan on handling many prototype cells or generate custom cells at runtime. In this case, one way to make this simple for you is to programmatically perform the segue when the user taps on a cell. Instead of using a specific prototype cell, make the segue a connection originating from the "Restauranger nära mig" UITableViewController going to the RestaurantViewController. (Connect in Interface Builder by control-click dragging from the Table View Controller icon at the top of the first one over to the body of the second). You must give this segue an identifier in the Attributes Inspector pane to make this useful. Let's say it's "toRestaurant". Then at the end of your tableView:didSelectRowAtIndexPath: method, put this line of code: self.performSegueWithIdentifier("toRestaurant", sender: self). Now no matter what cell is selected in the table, this segue will always fire for you.
Try creating cells like this in your cellForRow method:
let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("MyTestCell", forIndexPath: indexPath)
Im going out on a whim here since I am just getting into swift right now but the way I do it in my prepareForSegue() is something like this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "toRestaurant"{
let navigationController = segue.destinationViewController as UINavigationController
let vc = navigationController.topViewController as RestaurantViewController
//notice I changed [i] to [index!.row]
vc.data = currentResponse[index!.row] as NSArray
}
}
What it looks like to me is that you are calling the i variable which is kind of like a private variable inside a method of your class. You can do something like #Syed Tariq did with the selectRow variable and set it above your class SomeController: UIViewController /*, maybe some more here? */ { and then sign the variable inside your
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedRow = indexPath.row
}
method like above but both ways should work rather well.
I had the same problem and I found the solution to be:
performSegueWithIdentifier("toViewDetails", sender: self)
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var cellnumber = procMgr.processos[indexPath.row].numero
println("You selected cell #\(indexPath.row)")
println(cellnumber)
performSegueWithIdentifier("toViewDetails", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "toViewDetails" {
let DestViewController : ViewDetails = segue.destinationViewController as! ViewDetails
}
}
You may need to get the selected cell index of the UItableview. Below code used the selected cell index (UItableview.indexPathForSelectedRow) to get a correct element of the array.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "seguaVisitCardDetial" {
let viewController = segue.destinationViewController as! VCVisitCardDetial
viewController.dataThisCard = self.listOfVisitCards[(tblCardList.indexPathForSelectedRow?.row)!]
}
}
I had this problem, too; the segue from UITableViewCell did not call.
After some searching, I found it is because I had chosen "No Selection" for "Selection" field.

Resources