I have a table with several sections and lines in each section.
When selecting, I want each item in the table to have its own view controller. I have a given each identifiers.
The following code always opens the same new view controllers, ignoring my if function to make the segue dependent on which cell the user selects. At the moment I am testing with only two but once it works i will add more.
Does anyone know why this happens?
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath == 1 {
self.performSegueWithIdentifier("Belgium", sender: self)
}
else {
self.performSegueWithIdentifier("France", sender: self)
}
The if statement isn't being executed because you are comparing indexPath to 1. This will not happen at any point of time.
Objective-C throws a warning saying incompatible pointer NSIndexPath to int comparisons whereas swift executes silently.
The code should be
if indexPath.row == 1 { // Or it can be indexPath.section == 1
//Do Something
}
Related
I'm currently developing my first iOS app for a college. When you start the app, there is a grouped table view which should represent a menu. This works fine so far, but I'm unable to connect the segues properly. As far as I know I should connect the cell itself with the navigation controller it should lead to. Although every cell should lead to another navigation controller. It's a menu, so that point should be clear. Unfortunately I'm unable to connect a single cell with multiple navigation controllers and when I add multiple prototype cells, I have the problem that every cell should have it's own identifier.
The first screen you see in my app looks basically like the mail app. There are two groups and each cell leads to another navigation controller.
I managed to implement the navigation in some weird way, but get a lot of bugs like "nested push results in corrupted nav bar".
I'm absolutely frustrated right now, I spent a lot of hours on this single problem already and I'm unable to find any solution.
edit:
one of the biggest problems currently is that if I navigate to a point and then head back the the view before, the grouped view is first displayed too close to the top and when the animation is complete the whole view jumps back down where it belongs.
this is how it should look like (and looks like when it jumps back): https://dl.dropboxusercontent.com/u/34140308/uploads/2016-04-25%2010.28.48.png
this is how it looks like during the animation: https://dl.dropboxusercontent.com/u/34140308/uploads/2016-04-25%2010.28.48%202.png
edit2: I connected the view controller itself (not the cells) with the respective view controller. Then I call the segues programmatically like this:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
if indexPath.section == 0 {
if indexPath.row == 0 {
self.performSegueWithIdentifier("showSpeiseplan", sender: self)
} else if indexPath.row == 1 {
self.performSegueWithIdentifier("showStudiersaal", sender: self)
} else if indexPath.row == 2 {
self.performSegueWithIdentifier("showErzieher", sender: self)
} else if indexPath.row == 3 {
self.performSegueWithIdentifier("showHausordnung", sender: self)
} else if indexPath.row == 4 {
self.performSegueWithIdentifier("showNews", sender: self)
}
} else if indexPath.section == 1 {
if indexPath.row == 0 {
self.performSegueWithIdentifier("showZugewieseneStunden", sender: self)
}
}
}
The other major problem right now is that if you press a single cell multiple times before it's loaded, the view gets opened multiple times as well.
The way I usually do segue's from a tableView is by connecting the segue from the viewController rather than the tableviewCells. This way you can call performSegueWithIdentifier in didSelectRowAtIndexPath.
Eg
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
tableView.userInteractionEnabled = false
switch indexPath.section {
case 0:
switch indexPath.row {
case 0: performSegueWithIdentifier("showSpeiseplan", sender: self)
case 1: performSegueWithIdentifier("showStudiersaal", sender self)
case 2: performSegueWithIdentifier("showErzieher", sender self)
case 3: performSegueWithIdentifier("showHausordnung", sender self)
case 4: performSegueWithIdentifier("showNews", sender self)
default: tableView.userInteractionEnabled = true
}
case 1:
switch indexPath.row {
case 0: performSegueWithIdentifier("showZugewieseneStunden", sender: self)
default: tableView.userInteractionEnabled = true
}
default: tableView.userInteractionEnabled = true
}
}
and in viewWillDisappear:
override func viewDidDisappear(animated: Bool) {
tableView.userInteractionEnabled = true
}
If your cells are editable or dynamic (they change indexPath) then either use cell.tag in cellForRowAtIndexPath to distinguish them, or add a property to you custom cell class (or make one if you haven't) and add a property that you can use to identify the correct segue.
Edit: To fix the tableView Offset jump on animation, create a variable tableViewContentOffset above viewDidLoad, and then in viewDidLoad add:
tableViewContentOffset = tableView.contentOffset
and in viewWillAppear restore it if it has changed.
if tableView.contentOffset != tableViewContentOffset {
tableView.contentOffset = tableViewContentOffset
}
also, maybe just see what happens when you put this in viewWillAppear:
tableView.contentOffset = CGPointZero
tableView.contentInset = UIEdgeInsetsZero
I know how to send the user to a new cell after they select a cell but what if the order of my cells change because I am retrieving data from Parse so for each new cell, the row number changes.
How do I ensure the user is sent to the correct page when they select a certain cell? This is what I'm currently using but I know there's got to be a better solution than hardcoding every possible option..
Any advice?
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.section == 0 && indexPath.row == 1 {
self.performSegueWithIdentifier("toSettingsPage", sender: self)
}
}
For my understanding of your questions, I suggest you use a NSMutableDictionary to store all the user info data, and on the didSelectRowAtIndexPath function, you will use the indexPath to find the correct user info.
Your input:
A table view
An index path (section, row) ordered pair
Your output:
A string that identifies a segue
An ideal data structure for this is a dictionary.
First, notice that the table view input is always the same (you only seem to care about one table view - the protocol for data source is written to handle as many table views as you like, but most people use one for one).
Second, think about your keys and values: your key is the index path. And in fact, the index path breaks down into just an Integer because it is always the same section, which is analogous to the situation with table view described above.
So your dictionary is going to be of type: Dictionary<Integer, String>.
Now, instead of using the dictionary directly, let's make a function to wrap it and call the function segueForIndexPathInDefaultTableView:
private let seguesForIndexPaths:[Integer:String] = [0:"segue0",1:"segue1",2:"segue2"]
private func segueForIndexPathInDefaultTableView(indexPath: NSIndexPath) {
return self.seguesForIndexPaths[indexPath.row]
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier(self.segueForIndexPathInDefaultTableView(indexPath: indexPath), sender:self)
}
I have an NSManagedObject that is being used in my main view.
in this view I have two containers, each with their own static TableViews going on.
In my NSManagedObject I have an array I'd like to loop over, and display info on the screen like so:
Customer1 Name
Customer1 Type
Customer1 Address
Customer2 Name
Customer2 Type
Customer2 Address
I have tried to go the route of using a TableView, I have added a container, embedded the tableview in it, set a custom cell and tried to populate the custom cell with some test data. When I run it though the TableView just shows the four empty rows. (I'm probably missing something to do with the amount of rows which is why my test data isn't showing):
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return 0
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tblPartyDetails.dequeueReusableCellWithIdentifier(
"JobViewPartyCell", forIndexPath: indexPath)
as! JobViewPartyCell
cell.lblPartyName.text = "test name"
cell.lblPartyAddress.text = "test adddress"
cell.lblPartyType.text = "test partyType"
return cell
}
I also have to figure out how to pass my NSManagedObject into this TableView class and it seems like a lot of effort for what is just a repeated block of information...or...is this the only way to do it?
So, am I going about this in the right way? If so, how do I fix it and add my NSManagedObjects details to the TableView. If I'm not going about this correctly, what are the alternatives? I had a look at some other custom 'card' type stuff, like facebook and google cards, but those techniques use custom TableViewCells as well.
edit. PrepareForSegue function:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == jobSegueIdentifier {
if let destination = segue.destinationViewController as? JobViewController {
if let jobIndex = tblJobs.indexPathForSelectedRow() {
let workItem:Work = fetchedResultsController.objectAtIndexPath(jobIndex) as! Work
destination.workItem = workItem
}
}
}
}
First of all you returned 0 in your numberOfRowsInSection and what you should do is putting the number of rows you want to display, if your are testing your tableView put any number.
And if your data is in your mainView you should pass your data to the contained tableView so you can display it and in your number of rows you should return the number of elements in your data array.
First give an identifier to your embed segue in the storyboard and in your main view implement the prepareForSegue function as follows:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "embedSegueIdentifier" {
let distinationVC = segue.destinationViewController as? EmbeddedTableViewController //replace EmbeddedTableViewController with your tableViewControllerClass
distinationVC?.dataArray = yourDataArray //yourDataArray is in your main view and you should define data array in your embedded table view controller
}
}
and in your tableViewController add the following:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataArray.count
}
I hope this helped.
I'm currently working on a project in swift where I have created a ViewController which has a UITableView.
http://prntscr.com/5wft7u
This UITableView you can swipe to delete. I'm wanting to make a 'Deleted items' or 'Recycle bin' section kind of thing on my other view where once the delete button is pressed it deletes from the first tableView and is now inserted into the 'Deleted items' view tableview cell.
*Edit:
I've been thinking, I would make another array for the recycled items. In the UITableViewRowAction handler for deleting items, once you remove something out of your projects array, you add it to your recycled array. Then pass that recycled array over to the other VC in prepareForSegue method, and the other VC will load that array into the table.
I cant get this too work.. can someone please show me the code?
First view code: pastebin.com/dBucJ9w0
View: prntscr.com/5wft7u
The second view code is just a default VC class.
The view for the second class is only a TableView.
Thanks.
Add another array to each of your ViewControllers.
First VC:
Add var deleted: [String] = [] after your projects declaration. Then do this:
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == UITableViewCellEditingStyle.Delete {
deleted.append(projects[indexPath.row])
projects.removeAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
}
}
Finally make a prepareForSegue function to pass the data:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "YourIdentifier" {
let destination = segue.destinationViewController as YourSecondViewControllerClass
destination.arrayThatYouAdded = deleted
}
}
And then just display the arrayThatYouAdded property in your second view controller however you would like in a table view.
I was following this tutorial http://www.raywenderlich.com/76519/add-table-view-search-swift when I ran into an error. I am adding this feature into an app I was already working on. Once I am in the booths table view, I want to be able to navigate out into the main menu with a button on the navigation bar. Here is the section of code that deals with the segues.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("BoothDetail", sender: tableView)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "BoothDetail" {
let BoothDetailViewController = segue.destinationViewController as UIViewController
if sender as UITableView == self.searchDisplayController!.searchResultsTableView {
let indexPath = self.searchDisplayController!.searchResultsTableView.indexPathForSelectedRow()!
let destinationTitle = self.filteredBooths[indexPath.row].name
BoothDetailViewController.title = destinationTitle
} else {
let indexPath = self.tableView.indexPathForSelectedRow()!
let destinationTitle = self.booths[indexPath.row].name
BoothDetailViewController.title = destinationTitle
}
}
}
}
The error is thrown while trying to use the back button on the booths list that is a direct show segue to the main conference menu. The error is on this line.
if sender as UITableView == self.searchDisplayController!.searchResultsTableView {
You have quite a few problems. Some fatal, some just a headache.
the first headache is you are calling the same segue twice. Both functions call the same segue. Both will execute. Now if you want a double animation, okay. But since one passes data and the other does not, you may have an issue. Eliminate the didSelectRowAtIndexPath function.
In your prepareForSegue method it appears you have two different objects connected to the same segue. A searchDisplayController and a tableView. You want two separate segues. Then your if/else makes changes based on which segue was chosen:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "segue1" {
//code set 1
} else if segue.identifier == "segue2" {
//code set 2
}
}
I had similar problem and I just got it solved. When creating your segue in the tableview do not drag it from the cell, create a manual segue called "BoothDetail"
and connect it to BoothDetailViewController, to create a manual segue select the table view controller and click on "show connection inspector" you will see manual under triggered segue .
My problem the sender was a tableviewcell and not the tableview, so the function
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("BoothDetail", sender: tableView)
}
was never called to pass the tableview controller so when you try to cast it you were getting the error.
good luck