Swift Firebase UISearchController Index Out Of Range - swift

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
}
}
}
}

Related

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

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 {}

Swift one out of three segue is not passing data

I am trying to pass data to another controller with a segue after clicking on a button.
This is my code:
#IBAction func agilityDogBtnPressed(_ sender: Any) {
if let objs = controller.fetchedObjects, objs.count > 0 {
let course = objs[0]
self.performSegue(withIdentifier: "DogAgilitySegue", sender: course)
}
}
#IBAction func baseEducationBtnPressed(_ sender: Any) {
if let objs = controller.fetchedObjects, objs.count > 0 {
let course = objs[1]
self.performSegue(withIdentifier: "BaseEducationSegue", sender: course)
}
}
#IBAction func puppyBtnPressed(_ sender: Any) {
if let objs = controller.fetchedObjects, objs.count > 0 {
let course = objs[2]
self.performSegue(withIdentifier: "PuppyClassSegue", sender: course)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "DogAgilitySegue" {
if let destination = segue.destination as? ClassDetailsVC {
if let course = sender as? Course {
destination.course = course
}
}
} else if segue.identifier == "PuppyClassSegue" {
if let destination = segue.destination as? ClassDetailsVC {
if let course = sender as? Course {
destination.course = course
}
}
} else if segue.identifier == "BaseEducationSegue" {
if let destination = segue.destination as? ClassDetailsVC {
if let course = sender as? Course {
destination.course = course
}
}
}
My problem is that the first two segues are working perfectly fine.
The third one (PuppyClassSegue) is not passing the data through.
It opens the page but the data are not showing, basically the destination.course is not happening.
Any idea how is that possible?
Thank you!
It appears that course is nil , also you can do this by hooking all buttons to the same action and setting tags for them 0,1,2 respectively
#IBAction func agilityDogBtnPressed(_ sender: UIButton) {
if let objs = controller.fetchedObjects, objs.count > 0 {
let course = objs[sender.tag]
self.performSegue(withIdentifier: "SegueFromCon", sender: course)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? ClassDetailsVC {
if let course = sender as? Course {
print("hit here ",course)
destination.course = course
}
}
}
make 1 segue named say SegueFromCon from the current vc to the detailsVC

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
}
}

Pass image from collectionview to VC

I've tried a lot of methods i couldn't get it to work
ViewController 1 have : Collectionview > Cell > image inside the cell
ViewController 2 want to display the image which in VC 1
When you click on cell it has segue to push you to VC 2
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "popup" {
let viewController: friendpopup = segue.destination as! friendpopup
let indexPath = sender as! NSIndexPath
let nicknamex = self.nicknameArray[indexPath.row]
let usernamex = self.userArray[indexPath.row]
let photox = self.friendsphotos[indexPath.row] // the photos PFFiles i think
viewController.snick = nicknamex
viewController.suser = usernamex
viewController.sphoto = // ????
}
nickname and user works fine only the image i couldn't display it.
I tried when you click on cell it will send the image to var but isn't working
var photovar:UIImage!
didSelectItemAt( self.photovar = cell.profilepic.image)
then in prepareSegue( viewcontroller.sphoto = self.photovar)
isn't woking, Anyone could help me to fix that to display the image? Thanks
Tightening up your code a bit....
First VC
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "popup" {
if let vc = segue.destination as? friendpopup {
let indexPath = sender as! NSIndexPath
vc.snick = self.nicknameArray[indexPath.row]
vc.suser = self.userArray[indexPath.row]
vc.sphoto = self.friendsphotos[indexPath.row]
}
}
}
Second VC:
// making assumptions on variable types
var snick:String!
var suser:String!
var sphoto:UIImage!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// do work here
if sphoto != nil {
imageView.image = sPhoto
} else {
// set a default image here
}
}
Most of this is similar to your code, but one last note - if the first 2 properties are coming across correctly, check in the first VC that you are pulling the image out properly.

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]
}
}