Segue from CollectionViewCell to Another View Controller Passing IndexPath - ios

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.

Related

How to parse data from a UIViewController having 2 CollectionViews with swift

How do I parse data from a UIViewController having 2 different UICollectionViews?
I have 2 UICollectionViews in on UIViewController I have been able to pull the data from the server to the views and its displayed but i'm having trouble parsing it to the next screens.
I have tired this using didSelectItemAt and performSegue but it can't parse the data to the other screen
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if collectionView == self.categoryView {
let categoryViewController = self.storyboard?.instantiateViewController(withIdentifier: "CategoryListViewController") as! CategoryListViewController
categoryViewController.self.selectedC = self.category[indexPath.row]
self.navigationController?.pushViewController(categoryViewController, animated: true)
} else if collectionView == self.featuredView {
self.selectedPro = self.property[indexPath.row]
self.performSegue(withIdentifier: "showDet", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showCat"{
let categoryController = segue.destination as! CategoryListViewController
categoryController.selectedC = self.selectedC
}
else {
let detailViewController = segue.destination as! DetailsViewController
detailViewController.selectedPro = self.selectedPro
}
}
I'm expected to parse data to the second screen
Why are you using two different collection views? Why don't you just create two different cells? That way you can easily do an if let in the didSelect which type of cell has been tapped and pass the data on?
This Is the Solution
#IBOutlet weak var categoryView: UICollectionView!
let collectionViewAIdentifier = "catCell"
var category = [Category]()
#IBOutlet weak var featuredView: UICollectionView!
let collectionViewBIdentifier = "feaCell"
var property = [Property]()
override func viewDidLoad() {
super.viewDidLoad()
SVProgressHUD.show(withStatus: "Loading...")
categoryView.delegate = self
categoryView.dataSource = self
self.view.addSubview(categoryView)
featuredView.delegate = self
featuredView.dataSource = self
self.view.addSubview(featuredView)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
var count:Int?
// Category Collection View
if collectionView == self.categoryView {count = category.count}
//Property Collection View
if collectionView == self.featuredView {count = property.count}
return count!
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// Category Collection View
if collectionView == self.categoryView {
let cellA = collectionView.dequeueReusableCell(withReuseIdentifier: collectionViewAIdentifier, for: indexPath) as! HomeCollectionViewCell
let cat: Category
cat = category[indexPath.row]
cellA.homId.text = cat.idd
cellA.homName.text = cat.name
//idCat = cat.idd!
return cellA
}
//Property Collection View
else {
let cellB = collectionView.dequeueReusableCell(withReuseIdentifier: collectionViewBIdentifier, for: indexPath) as! FeaturedCollectionViewCell
let pro: Property
pro = property[indexPath.row]
cellB.proId.text = pro.idd
cellB.proName.text = pro.name
return cellB
}
}
//Parsing data to next screen
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Category Collection View parsing data
if segue.identifier == "showCat" {
let categoryDetailVC = segue.destination as! CategoryListViewController
let cell = sender as! UICollectionViewCell
let indexPath = self.categoryView.indexPath(for: cell)
let categoryId = category[(indexPath?.row)!].idd
categoryDetailVC.idString = categoryId
}
//Property Collection View parsing data
else if segue.identifier == "showDet" {
let detailVC = segue.destination as! DetailsViewController
let cell = sender as! UICollectionViewCell
let indexPath = self.featuredView.indexPath(for: cell)
let detailId = property[(indexPath?.row)!].idd
detailVC.idProString = detailId
}
}

prepareForSegue - CollectionView/TableView

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

UICollectionView prepareForSegue indexPathForCell is nil iOS 9

The problem is this line return nil:
if let indexPath = self.collectionView?.indexPathForCell(sender as! UICollectionViewCell)
For that reason I can't pass any information, The identifier is set and the delegate is set.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "DetalleSegueIdentifier" {
if let indexPath = self.collectionView?.indexPathForCell(sender as! UICollectionViewCell) {
let detailVC = segue.destinationViewController as! DetalleNoticiaViewController
detailVC.contact = self.noticia[indexPath.row]
}
}
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("DetalleSegueIdentifier", sender: collectionView.cellForItemAtIndexPath(indexPath))
}
Any help?
The problem is how to try to get the cell back. You must pass the cell in the performSegueWithIdentifier and then recover it in prepareForSegue.
Here is the code:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("DetalleSegueIdentifier", sender: collectionView.cellForItemAtIndexPath(indexPath))
}
And then
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "DetalleSegueIdentifier" {
if let cell = sender as? UICollectionViewCell{
let indexPath = self.collectionView!.indexPathForCell(cell)
let detailVC = segue.destinationViewController as! DetalleNoticiaViewController
detailVC.contact = self.noticia[indexPath.row]
}
}
}
Hope it helps!
Try Like this..
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("DetalleSegueIdentifier", sender: indexPath)
}
and get your indexpath like this...
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "DetalleSegueIdentifier" {
let aIndPath = sender as! NSIndexPath
let detailVC = segue.destinationViewController as! DetalleNoticiaViewController
detailVC.contact = self.noticia[aIndPath.item]
}
}
The problem is the var collectionView is not reference in my ViewController for that reason always return nil. My mistake thanks you for your answers.
#IBOutlet weak var collectionView: UICollectionView!

How to pass data from UITableViewCell to ViewController?

I have followed multiple tutorials, and have tried many answers on here, but I cannot seem to figure out what the problem is.
Here is my code:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
println("You selected cell #\(indexPath.row)!")
let indexPath = homeTimelineTableView.indexPathForSelectedRow()
let currentCell = homeTimelineTableView.cellForRowAtIndexPath(indexPath!) as! ProductTableViewCell
productTitle = currentCell.productCellTitleLabel!.text
println("The product title is \(productTitle)")
self.performSegueWithIdentifier("timelineDetail", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var titleLables: String!
if (segue.identifier == "timelineDetail") {
println("it works thus far!")
let viewController = segue.destinationViewController as! ProductDetailViewController
let selectedRow = homeTimelineTableView.indexPathForSelectedRow()!.row
viewController.titleLabel?.text = productTitle
}else {
println("wtf is wrong with your code?!")
}
}
I do not receive any errors. However, when I go to run my app, my product title still refuses to pass to the viewcontroller.
Any suggestions? Thanks.
At this stage viewController.titleLabel is nil (you are using ?, that's why there is no error)
The correct approach should be:
add var productTitle: String! in ProductDetailViewController
pass productTitle not to UILabel, but to viewController.productTitle
in viewDidLoad of ProductDetailViewController set viewController.titleLabel?.text = self.productTitle
The productTitle variable must be assigned from the currently selected cell in the prepareForSegue method.
Check the code below.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var titleLables: String!
if (segue.identifier == "timelineDetail") {
println("it works thus far!")
let viewController = segue.destinationViewController as! ProductDetailViewController
let selectedRow = homeTimelineTableView.indexPathForSelectedRow()!.row
let currentCell = homeTimelineTableView.cellForRowAtIndexPath(indexPath!) as! ProductTableViewCell
productTitle = currentCell.productCellTitleLabel!.text
viewController.titleLabel?.text = productTitle
} else {
println("wtf is wrong with your code?!")
}
}
The problem is most lilely in these two lines:
let indexPath = homeTimelineTableView.indexPathForSelectedRow()
let currentCell = homeTimelineTableView.cellForRowAtIndexPath(indexPath!) as! ProductTableViewCell
First, func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) provides already the selected indexPath. There is no need for let indexPath = ....
Second, don't load the cell's value (which returns nil, if the cell is visible and tableView.visibleCells() brings other issues), but use your data source to get the item at the selected indexPath.
In total it might look like:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// `indexPath` comes from the function parameters
let item = model.itemAtIndexPath(indexPath)
// the 'model'-part should be the same like in `cellForRow:indexPath`
// your mission is only to get the item at the path, not the cell
productTitle = item.title
self.performSegueWithIdentifier("timelineDetail", sender: self)
}

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