if let editItemVC = segue.destination as? ItemDetailViewController {} doesn't work - swift

i have two segues in this tableViewController, but the downcasting in prepare(for: segue) doesn't work.
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
print("into segue")
super.prepare(for: segue, sender: sender)
switch segue.identifier {
case "addItem":
print("addItem Segue")
if let addItemVC = segue.destination as? ItemDetailViewController {
print("if let done")
addItemVC.container = container
} else {
print("WTF")
}
case "editItem":
print("editItem Segue")
if let editItemVC = segue.destination as? ItemDetailViewController {
guard let selectedItemCell = sender as? PriorityListTVCell else {
fatalError("Unexpected sender: \(String(describing: sender))")
}
guard let indexPath = tableView.indexPath(for: selectedItemCell) else {
fatalError("The selected cell is not being displayed by the table")
}
editItemVC.editedInfo = list[indexPath.row]
print("passed indexPath.row: \(indexPath.row)")
editItemVC.container = container
}
default:
break
}
}
if i click "add" button, in the console it'll print out
into segue
addItem Segue
WTF
not sure why the downcasting doesn't work, does it have anything to do with segue types of destination?
Thanks for help!

This
if let addItemVC = segue.destination as? ItemDetailViewController {
won't work if the destination vc isn't of type ItemDetailViewController meaning you need to assign the class name in IB , for help you can do
print(type(of:segue.destination))
For navigation do
if let nav = segue.destination as? UINavigationController ,
let addItemVC = nav.viewControllers?.first as? ItemDetailViewController {}

Related

Cannot find `ViewController` in prepare for segue

I´m trying to pass data from one ViewController to another. But when I try to set the destinationVC Xcode doesn't recognize the ViewController. I get no autocomplete for the DataRecieverViewController I get autocomplete for the other ViewCOntrollers When I write it in manually, I get no errors, but no data is passed.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == passDataSegue {
let destination = segue.destination as! DataRecieverViewController //Xcode doesn't recognize this VC. I get no autocomplete.
destination.data1 = data1
}
}
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "identfiername")
{
let destination = segue.destination as! DataRecieverViewController
destination.data1 = data1
}
}
for you the identifier name is passDataSegue, When you work with segues please cross check the seguename and viewcontroller name once more to avoid erorrs.
About autocomplete try to save the file DataRecieverViewController and build your project it is a common bug of Xcode.
About data pass
Are you sure you are getting to the right instance of DataRecieverViewController, not the general class?
Is it embedded in a NavigationController ot UITabBarController ?
if Yes you have to get the right instance.
If embedded in UITabBarController
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == passDataSegue)
{
let tabBar = segue.destination as! UITabBarController
let controller = tabBar.viewControllers?.first(where: { $0 is DataRecieverViewController }) as? DataRecieverViewController
controller.data1 = data1
}
In case of UINavigationController
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == passDataSegue)
{
let NavBar = segue.destination as! UINavigationController
let NavC = NavBar.viewControllers?.first(where: { $0 is DataRecieverViewController }) as? DataRecieverViewController
let controller = NavC.rootViewController as? DataRecieverViewController
controller.data1 = data1
}

Add two guard let in a prepare for segue function

I'm trying to build my first app with three tableViews which are hierarchical. The middle VC has two guard let in one prepare for segue function.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let destination = segue.destination as? AddMemberViewController else {
return
}
destination.club = club
guard let Destination = segue.destination as? TransactionViewController, let selectedRow = self.tableViewMember.indexPathForSelectedRow?.row else {
return
}
Destination.member = members[selectedRow]
}
That's how it looks like. Can I fix this, that both func get used by my app, because it just uses the one on the top.
The problem is if you want to segue to TransactionViewController the function already returns because segue.destination is not AddMemberViewController.
Instead you should give your segues different identifiers and ask for them in prepareForSegue. Something like this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "AddMemberVCSegue" {
guard let destination = segue.destination as? AddMemberViewController else {
return
}
destination.club = club
}
if segue.identifier == "TransactionVCSegue" {
guard let Destination = segue.destination as? TransactionViewController, let selectedRow = self.tableViewMember.indexPathForSelectedRow?.row else {
return
}
Destination.member = members[selectedRow]
}
}
Just replace guards with if lets:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? AddMemberViewController {
destination.club = club
} else if let destination = segue.destination as? TransactionViewController, let selectedRow = self.tableViewMember.indexPathForSelectedRow?.row {
destination.member = members[selectedRow]
}
}
prepare(for is called for one specific segue, so executing both guard let after another is unnecessarily expensive.
Usually you are checking the identifier of the segue with a switch statement, replace the literal identifiers with your real values
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch segue.identifier {
case "memberSegue":
let destination = segue.destination as! AddMemberViewController
destination.club = club
case "transactionSegue":
guard let selectedRow = self.tableViewMember.indexPathForSelectedRow?.row else { return }
let destination = segue.destination as! TransactionViewController
destination.member = members[selectedRow]
default: break
}
}

unexpected segue error found nil

I get this error when pressing the home button: Thread 1: Fatal error: Unexpected Segue Identifier; nil
This is my code:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
switch(segue.identifier ?? "")
{
case "AddItem":
os_log("Adding a new day.", log: OSLog.default, type: .debug)
case "ShowDetail":
guard let newDayDetailController = segue.destination as? newDayController else {
fatalError("Unexpected destination: \(segue.destination)")
}
guard let selectednewDayCell = sender as? newDayTableViewCell else {
fatalError("Unexpected sender: \(String(describing: sender))")
}
guard let indexPath = tableView.indexPath(for: selectednewDayCell) else {
fatalError("The selected cell is not being displayed by the table")
}
let selectedDay = days[indexPath.row]
newDayDetailController.day = selectedDay
case "toMenu":
os_log("Back to main menu", log: OSLog.default, type: .debug)
if segue.identifier == "sendData"
{
let VC = segue.destination as! HomeViewController
VC.data = totalDays!
}
default:
fatalError("Unexpected Segue Identifier; \(String(describing: segue.identifier))")
}
}
//MARK: Actions
#IBAction func menuButton(_ sender: Any) {
performSegue(withIdentifier: "sendData", sender: self)
}
Someone please help me out?
Make sure to set the segue identifier in the Attributes Inspector in your storyboard
Apparently your switch statement goes to the default case.

Swift Firebase UISearchController Index Out Of Range

I have a tableview that lists all of my "places" from firebase. I have a UISearchController to obviously search through these "places". The problem is when I just tap on the UISearchController but don't type anything and select a "place" I get a index out of range error. If I am typing or do not activated the UISearchController, it segues fine. Just when it is active and don't type is when I get the error. It throws the error on "let user = filteredUsers[indexPath.row]"
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if segue.identifier == "BusinessProfiles" {
// gotta check if we're currently searching
if self.searchController.isActive {
if let indexPath = tableView.indexPathForSelectedRow {
let user = filteredUsers[indexPath.row]
let controller = segue.destination as? BusinessProfilesViewController
controller?.otherUser = user
}
} else {
if let indexPath = tableView.indexPathForSelectedRow {
let user = usersArray[indexPath.row]
let controller = segue.destination as? BusinessProfilesViewController
controller?.otherUser = user
}
}
}
}
As you say, you did not perform any search and select a place, right? If so, you call empty filteredUsers[indexPath.row] with indexPath.row of selected row, which have an positive index. As so, you must first check if search was perform, and only then call filteredUsers[indexPath.row] like this:
if !filteredUsers.isEmpty {
if self.searchController.isActive {
if let indexPath = tableView.indexPathForSelectedRow {
let user = filteredUsers[indexPath.row]
Just added this "&& searchController.searchBar.text != ""
" to correct my problem
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if segue.identifier == "BusinessProfiles" {
// gotta check if we're currently searching
if self.searchController.isActive && searchController.searchBar.text != "" {
if let indexPath = tableView.indexPathForSelectedRow {
let user = filteredUsers[indexPath.row]
let controller = segue.destination as? BusinessProfilesViewController
controller?.otherUser = user
}
} else {
if let indexPath = tableView.indexPathForSelectedRow {
let user = usersArray[indexPath.row]
let controller = segue.destination as? BusinessProfilesViewController
controller?.otherUser = user
}
}
}
}

Bad Exception on swipe action cell Swift

I'm making an app that is sending information about text inside of cells to a WebViewController using swipe actions. The swipe action is:
let sendToWebsite = UITableViewRowAction(style: .Default, title: "Website")
{ (action, indexPath) in
self.performSegueWithIdentifier("yourSegueIdentifier", sender: nil)
}
sendToWebsite.backgroundColor = UIColor.blueColor()
return [sendToWebsite]
}
This works fine but I also have two segues coming from the same View Controller, to two other VC's. The first segue(recipeDetail) is when you tap directly on the cell and works fine, but the second segue(yourSegueIdentifier) is a button that appears when you activate the slide action on the cell and does't work.
the segues:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "recipeDetail") {
let indexPath = self.tableView!.indexPathForSelectedRow
let destinationViewController: DetailViewController = segue.destinationViewController as! DetailViewController
destinationViewController.recipe = recipes[indexPath!.row]
}
else if segue.identifier == "yourSegueIdentifier"
{
let indexPath = self.tableView!.indexPathForSelectedRow
let nextVC: WebViewController = segue.destinationViewController as! WebViewController
nextVC.recipe = recipes[indexPath!.row]
}
}
On the line
nextVC.recipe = recipes[indexPath!.row]
indexPath is coming out as nil and giving the following error message
Well it looks like on the swipe action, the tableView doesn't register the "indexPathForSelectedRow" method.
What you could alternatively do is setup a global swipeIndex variable
class ViewController: UIViewController{
var swipeIndex : Int!
//Code, code, code...
and then set it once the swipe action is called.
let sendToWebsite = UITableViewRowAction(style: .Default, title: "Website")
{ (action, indexPath) in
self.swipeIndex = indexPath.row
self.performSegueWithIdentifier("yourSegueIdentifier", sender: nil)
}
sendToWebsite.backgroundColor = UIColor.blueColor()
return [sendToWebsite]
}
and then:
else if segue.identifier == "yourSegueIdentifier"
{
let indexPath = self.tableView!.indexPathForSelectedRow
let nextVC: WebViewController = segue.destinationViewController as! WebViewController
nextVC.recipe = recipies[self.swipeIndex]
}
}