prepareForSegue - CollectionView/TableView - ios

How can I use indexPathForSelectedRow in CollectionView?
CollectionView/TableView:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("levelCell", forIndexPath: indexPath) as! CollectionViewCell
guard levelListen != nil else {
return cell
}
let levelListe = levelListen[indexPath.row]
cell.levelLabel?.text = levelListe.name
return cell
}
TableView - prepareForSegue (work):
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "zumLevel" {
let dstCtl = segue.destinationViewController as! InLevelViewController
let indexPath = tableView.indexPathForSelectedRow!
dstCtl.levelList = levelListen[indexPath.row]
}
}
CollectionView - prepareForSegue (not work):
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "zumLevel" {
let dstCtl = segue.destinationViewController as! InLevelViewController
// like TableView?
let indexPath = collectionView.indexPathsForSelectedItems()!
dstCtl.levelList = levelListen[indexPath.row] // <--- .row doesn't work, should I use .count ?
}
}
When I try .count it says: "unexpectedly found nil while unwrapping an Optional value"

collectionView.indexPathsForSelectedItems() returns multiple IndexPath's because you can select multiple cells. This function returns an array of IndexPaths, e.g [NSIndexPath].
It should work if you'd do something like:
let indexPath = collectionView.indexPathsForSelectedItems()
if let lastRowSelected = indexPath?.last?.row {
dstCtl.levelList = levelListen[lastRowSelected]
}

Related

Segue from CollectionViewCell to Another View Controller Passing IndexPath

I'm trying to pass the indexPath of a cell tapped in a UICollectionView to another view controller. I can't seem to get the indexPath of what was selected and segue it to the next view controller
I get this error: "Could not cast value of type Post to PostCell"
View Controller #1:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let post = posts[indexPath.row]
if let cell = collectionView.dequeueReusableCellWithReuseIdentifier("PostCell", forIndexPath: indexPath) as? PostCell {
cell.configureCell(post)
}
return cell
}
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let selectedPost: Post!
selectedPost = posts[indexPath.row]
performSegueWithIdentifier("PostDetailVC", sender: selectedPost)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "PostDetailVC" {
//Error here: Could not cast value of Post to PostCell
if let selectedIndex = self.collection.indexPathForCell(sender as! PostCell){
print(selectedIndex)
}
if let detailsVC = segue.destinationViewController as? PostDetailVC {
if let selectedPost = sender as? Post {
print(selectedIndex)
detailsVC.post = selectedPost
detailsVC.myId = self.myId!
detailsVC.indexNum = selectedIndex
}
}
}
}
View Controller #2:
var indexNum: NSIndexPath!
override func viewDidLoad() {
super.viewDidLoad()
print(indexNum)
}
You are passing a Post instance which doesn't match the expected PostCell instance.
I recommend to pass the index path
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("PostDetailVC", sender: indexPath)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "PostDetailVC" {
guard let selectedIndexPath = sender as? NSIndexPath,
detailsVC = segue.destinationViewController as? PostDetailVC else { return }
print(selectedIndexPath)
let selectedPost = posts[selectedIndexPath.row]
detailsVC.post = selectedPost
detailsVC.myId = self.myId!
detailsVC.indexNum = selectedIndexPath
}
}
You are passing a Post and not a PostCell as sender. You don't need that anyway, as the collectionView keeps track of selected items.
Try this:
if let selectedIndex = self.collection.indexPathsForSelectedItems()?.first {
print(selectedIndex)
}
It's because you are giving argument which has type of Post and you are trying to cast it as PostCell. Which will not work.

prepareForSegue returns nil at first

I'm getting fatal error: unexpectedly found nil while unwrapping an Optional value when I segue from the cell.
Here's the code:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.section == 1 {
let listIngredients = recipeItem.ingredients[indexPath.row]
selectedIngredient = listIngredients.ingredient
}
tableView.deselectRowAtIndexPath(indexPath, animated: false)
performSegueWithIdentifier("showIngredientInRecipe", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showIngredientInRecipe" {
let svc = segue.destinationViewController as! UINavigationController
let destination = svc.topViewController as! IngredientDetailViewController
destination.ingredientItem = selectedIngredient
print("selectedIngredient \n \(selectedIngredient)")
}
}
Here's what I get from the debugger:
selectedIngredient
nil
selectedIngredient
Optional(Ingredient {
name = Rye Whiskey;
inStock = 1;
type = IngredientType {
name = Spirit;
};
})
fatal error: unexpectedly found nil while unwrapping an Optional value
As you can see, the selectedIngredient prints twice. First as nil, second time with the expected content. If i replace destination.ingredientItem = selectedIngredient with destination.ingredientItem = recipeItem.ingredients[0].ingredient the segue runs fine with no errors.
You're checking if indexPath's section is 1 and if it's not it will still perform segue. Make sure your selectable cells are in section 1 (or section 0?) and move your performSegueWithIdentifier("showIngredientInRecipe", sender: self) call to if statement to make it more safe.
Fixed:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showIngredientInRecipe" {
if let selectedIndexPath = self.tableView.indexPathForSelectedRow {
if selectedIndexPath.section == 1 {
let listIngredients = recipeItem.ingredients[selectedIndexPath.row]
selectedIngredient = listIngredients.ingredient
let svc = segue.destinationViewController as! UINavigationController
let destination = svc.topViewController as! IngredientDetailViewController
destination.ingredientItem = selectedIngredient
print("selectedIngredient \n \(selectedIngredient)")
}
}
}
}
Your code is error prone because you can perform segue regardless of
the section
A better way to get the selected item, is to call indexPathForSelectedRow() method inside of the delegate
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.section == 1 {
performSegueWithIdentifier("showIngredientInRecipe", sender: self)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showIngredientInRecipe" {
//get selected item
let indexPath = self.tableView.indexPathForSelectedRow() {
let selectedIngredient = recipeItem.ingredients[indexPath.row]
print("selectedIngredient \n \(selectedIngredient)")
//segue
let svc = segue.destinationViewController as! UINavigationController
let destination = svc.topViewController as! IngredientDetailViewController
destination.ingredientItem = selectedIngredient
}
}
}

UIImage not appearing

When I segue my UIImageView from my NewsTableViewController.swift, the image does not appear in my NewsDetailTableViewController.swift.
Here is an image of my simulator:
Here is an image of my Main.storyboard:
Here is my prepareForSegue() method code:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?){
if segue.identifier == "showDetail" {
if let indexPath = tableView.indexPathForSelectedRow {
let destinationController = segue.destinationViewController as! NewsDetailTableViewController
destinationController.item = items[indexPath.row]
let newsImage = UIImageView(image: UIImage(named: detailImages[indexPath.row]))
destinationController.image = newsImage
}
}
}
It is also worth mentioning that my image in my NewsTableViewController.swift is set to 0x0, and in my NewsDetailTableViewController.swift, it is set to 600x216. I don't know if this would matter or not. If you desire any code, please do feel free to ask.
FYI, I use Swift.
In prepareForSegue the IBOutlets of your destinationController have not been initialized yet. Just pass detailImages to another array property on NewsDetailTableViewController. Change your prepareForSegue to:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?){
if segue.identifier == "showDetail" {
if let indexPath = tableView.indexPathForSelectedRow {
let destinationController = segue.destinationViewController as! NewsDetailTableViewController
destinationController.item = items[indexPath.row]
destinationController.imageNames = detailImages
}
}
}
Then in NewsTableViewController add the following code:
var imageNames:[String]?
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//replace with whatever identifier you're using
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as UITableViewCell
cell.imageView?.image = self.imageNames[indexPath.row]?
return cell
}

Swift didSelectRowAtIndexPath and prepareForSegue

I need to add a value to the selected row than in prepareForSegue that it does its action.But my prepareForSegue is doing the action before it.When i try to place the "performSegueWithIdentifier" it crashes,also i have added the id to the segue idenfifier in the storyboard.Im working with sqlite.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedRow = indexPath.row
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "editSegue")
{
let viewController : WorkoutView = segue.destinationViewController as! WorkoutView
viewController.workoutInfoData = marrStudentData.objectAtIndex(selectedRow) as! WorkoutInfo
navigationItem.title = ""
}
}
You can fetch the selected indexPaths from tableView in your prepare for segue
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "editSegue")
{
if let indexPath = tableView.indexPathForSelectedRow{
let viewController : WorkoutView = segue.destinationViewController as! WorkoutView
viewController.workoutInfoData = marrStudentData.objectAtIndex(indexPath.row) as! WorkoutInfo
navigationItem.title = ""
}
}
}

How to get custom cell label when segue?

I'm trying to get the name of the selected row in the custom cell. How I can do that in Swift?
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var selectedCell = CustomCell()
selectedCell = tableView(tbl, cellForRowAtIndexPath: <#NSIndexPath#>)
if(segue.identifier == "next") {
var next = (segue.destinationViewController as! EngineViewController)
next.titleSub = selectedCell.cell.lblBrand.text
}
}
I believe if you are just selecting a cell, the cell should be the sender. Try this
if let selectedCell = sender as? CustomCell {
if(segue.identifier == "next") {
var next = (segue.destinationViewController as! EngineViewController)
next.titleSub = selectedCell.cell.lblBrand.text
}
}
You could attempt to override didSelectRowAtIndexPath to get your cell.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.dequeueReusableCellWithIdentifier("CellIdentifier", forIndexPath: indexPath) as! CustomCell
cell.yourLabel.textYouWant
let yourViewController = storyboard?.instantiateViewControllerWithIdentifier("ViewController") as! ViewController
navigationController?.pushViewController(yourViewController, animated: true)
}

Resources