From collectionView to Detail - swift

Im passing data from one CollectionViewController to a detail ViewController. Everything seems to be working, but the "prepareForSegue is happening before the "didSelectItemAtIndexPath" so it's passing the data of the item I selected the last time not the one I'm selecting right now.
This is my wrong code for the collectionViewController
var cellSelected : Int = 0
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
cellSelected = indexPath.row
println("Did select!")
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "identifierName" {
var secondScene = segue.destinationViewController as detailVC
secondScene.authorDetail = data[cellSelected].userOfImg
secondScene.likesDetail = data[cellSelected].likesInImg
secondScene.imageDetail = data[cellSelected].imgPath
println("Prepare for segue")
}
}
The result in the debug area is:
Prepare for segue
Did select!

I've found a solution for this. It's to use shouldSelectItemAtIndexPath instead of didSelectItemAtIndexPath. Doing this the shouldSelectItemAtIndexPath will be executed before the prepareForSegue and will fix the problem of sending the data of the item you are selecting and not the one selected the last time.

Right solution
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "identifierName" {
var secondScene = segue.destinationViewController as detailVC
let cell = sender as UICollectionViewCell
let indexPath = collectionView.indexPathForCell(cell)
secondScene.authorDetail = data[indexPath.row].userOfImg
secondScene.likesDetail = data[indexPath.row].likesInImg
secondScene.imageDetail = data[indexPath.row].imgPath
println("Prepare for segue")
}
}

Related

The second item that I add to a list deletes the first item

In my Swift 5 code, I have a list named qname and username:
var qname = ["myFirstItem", "SecondItem", "Third Item"]
var username = ["Bob", "Joe", "Jill"]
I put it in a tableview with
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return qname.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = QuestionTableView.dequeueReusableCell(withIdentifier: "question")
cell?.textLabel?.text = qname[indexPath.row]
cell?.detailTextLabel?.text = "\(username[indexPath.row])"
return cell!
}
In my other view controller, when the person presses 'post question', I run this code:
#IBAction func postQuestion(_ sender: UIButton) {
newName = questionName.text!
newDescription = questionDescription.text!
newUsername = username.text!
performSegue(withIdentifier: "madequestion", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "madequestion" {
let vc = segue.destination as! MainPage
vc.qname.append(newName)
vc.username.append(newUsername)
}
}
I also have questionName, questionDescription, and username as IBOutlet, just I didn't put it in this code. MainPage is where my tableview is. And the variables I put them in: newName, newDescription, and newUsername were also pre-defined as "".
Now here is the problem. With this code, the vc.qname.append(newName) vc.username.append(newUsername)is running well the first time I run it, so it adds a question to my tableview. The second time I click post question with different details as newName and newUsername, it overrides the first new question I made and puts the second question.
I would love a pretty simple code explanation since I don't know a lot about coding, if that is possible!
Thank you in advance!
Swaraag
Your problem is simple, every time you click "postQuestion" you create a new ViewController which contains your "qname" and "username" array, meaning you insatiate them with your predefine values so every other value you appended gets deleted.
in your case i would probably move your arrays to the ViewController which contains "postQuestion" and every time you click "postQuestion" update the arrays of the "postQuestion" ViewController and then send them to your ViewController which contains the TableView.
it will look something like that:
var qname = ["myFirstItem", "SecondItem", "Third Item"]
var username = ["Bob", "Joe", "Jill"]
#IBAction func postQuestion(_ sender: UIButton) {
newName = questionName.text!
newDescription = questionDescription.text!
newUsername = username.text!
self.qname.append(newName)
self.username.append(newUsername)
performSegue(withIdentifier: "madequestion", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "madequestion" {
let vc = segue.destination as! MainPage
vc.qname = self.qname
vc.username = self.username
vc.tableView.reloadData()
}
}
and in your tableViewController the initial values will be as follows:
var qname = [String]()
var username = [String]()

Passing parameter on Perform Segue returns nil [duplicate]

I'm trying to push data from one viewController to another. I've connected a viewController to another ViewController's navigationController and then set the identifier to "showItemSegue". I get an error in these two lines:
var detailController = segue.destinationViewController as ShowItemViewController
detailController.currentId = nextId!
Image illustration:
The code:
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
nextId = itemArray?.objectAtIndex(indexPath.row).objectForKey("objectId") as? NSString
self.performSegueWithIdentifier("showItemSegue", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "showItemSegue") {
var detailController = segue.destinationViewController as ShowItemViewController
detailController.currentId = nextId!
}
}
The destination view controller of the segue is the UINavigationController. You need to ask it for its top view controller to get to the real destination view controller:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showItemSegue" {
let navController = segue.destination as! UINavigationController
let detailController = navController.topViewController as! ShowItemViewController
detailController.currentId = nextId!
}
}

Swift prepare for segue - Send data from one view controller to another

I want to move from one view controller to another and send userId:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("chosenPerson", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "chosenPerson" {
let chosenPerson = segue.destinationViewController as? chosenPersonViewController
let indexPaths = self.collectionView!.indexPathsForSelectedItems()!
let indexPath = indexPaths[0] as NSIndexPath
chosenPerson!.userID = self.usersArray[indexPath.row].userId
}
by clicking I get: "fatal error: unexpectedly found nil while unwrapping an Optional value"
what I do wrong?
If you have given segue in StoryBoard DON'T Call this self.performSegueWithIdentifier("chosenPerson", sender: self) method in didSelectItem
If you have given segue in storyboard override func prepareForSegue - this method calls first after that didSelectItem calls
Please refer storyBoard once (below Image for Sample)
I think problem is in self.usersArray[indexPath.row].userId May this returns nil
Swift2:
self.performSegueWithIdentifier("chosenPerson", sender: self)
Swift3:
self.performSegue(withIdentifier: "chosenPerson", sender: self)
Swift2:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "chosenPerson" {
let chosenPerson = segue.destinationViewController as? chosenPersonViewController
let indexPaths = self.collectionView!.indexPathsForSelectedItems()!
let indexPath = indexPaths[0] as NSIndexPath
chosenPerson!.userID = self.usersArray[indexPath.row].userId //May it found nil please re - check array values
}
Swift3:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "chosenPerson" {
let chosenPerson = segue.destination as! chosenPersonViewController
if let indexPath = collectionView.indexPathForSelectedItem {
chosenPerson!.userID = self.usersArray[indexPath.row].userId //May it found nil please re - check array values
}
}
}
When performing the segue, pass the indexPath as the sender and try using this switch statement. If you see "unknown segue" printed out when you select a cell, the destination controller is not of type chosenPersonViewController.
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("chosenPerson", sender: indexPath)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
switch (segue.destinationViewController, sender) {
case (let controller as chosenPersonViewController, let indexPath as NSIndexPath):
controller.userID = usersArray[indexPath.row].userId
default:
print("unknown segue")
break
}
}
One possible issue could be that in your storyboard you have not set the identifier for your segue to be "chosenPerson". To fix this first make sure you have a segue between your first and second view controllers, which can be created by control dragging one from one view controller to another.
Then make sure the segue has an identifier, specifically: "chosenPerson". To do this: click on the segue between the first two view controllers, then navigate to the attributes tab, and then set the identifier box to be "chosenPerson". Save the storyboard with your changes and now you should be able to call prepareForSegue with that identifier and not experience a fatal error.

Segue is being executed twice

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.selectedClubState = stateNamesForDisplay[indexPath.row]
self.performSegueWithIdentifier ("Cities", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var clubsToPassToCitiesViewController = [clubObject]()
if segue.identifier == "Cities" {
for club in clubsForTable{
if club.clubState == self.selectedClubState{
clubsToPassToCitiesViewController.append(club)
}
}
let citiesView = segue.destinationViewController as? citiesViewController
citiesView?.clubsForChosenCity = clubsToPassToCitiesViewController
}
}
Segue is being executed twice leading to the next VC. How can I prevent this from happening?
Delete the current segue in storyboard. Then CTRL-drag from the viewController (not the cell) to the next view controller and name it "Cities". Now, when you select a cell, the didSelectRowAtIndexPath() will fire first and will call performSegueWithIdentifier()
However, if all you're looking to do in the didSelectRowAtIndexPath() is get the row that performed the segue, you can maintain your original setup of having the cell segue from the storyboard, remove didSelectRowAtIndexPath() and in prepareForSegue() do:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let indexPath = self.tableView.indexPathForSelectedRow {
self.selectedClubState = stateNamesForDisplay[indexPath.row]
}
var clubsToPassToCitiesViewController = [clubObject]()
if segue.identifier == "Cities" {
for club in clubsForTable{
if club.clubState == self.selectedClubState{
clubsToPassToCitiesViewController.append(club)
}
}
let citiesView = segue.destinationViewController as? citiesViewController
citiesView?.clubsForChosenCity = clubsToPassToCitiesViewController
}
}
You are the one executing the segue twice — once automatically in the storyboard (because your segue emanates as an Action Segue from the cell prototype), and once in code when you say self.performSegueWithIdentifier. If you don't want the segue executed twice, remove one of those.
Personally, my recommendation is that you delete didSelectRow entirely and move your self.selectedClubState assignment into prepareForSegue.

how to handle two collection view with push segues

I'm having two UICollectionView
#IBOutlet weak var collectionView1: UICollectionView!
#IBOutlet weak var collectionview2: UICollectionView!
i'm getting indexPath for each collection view separately with functions.
func getIndexPathForSelectedCell() -> NSIndexPath?
{
var indexPath:NSIndexPath?
if collectionview1.indexPathsForSelectedItems()!.count > 0 {
indexPath = collectionview1.indexPathsForSelectedItems()![0]
}
return indexPath
}
func getIndexPathForSelectedCell2() -> NSIndexPath?
{
var indexPath2:NSIndexPath?
if collectionView2.indexPathsForSelectedItems()!.count > 0 {
indexPath2 = collectionView2.indexPathsForSelectedItems()![0]
}
return indexPath2
}
I'm Performing segue for cell touch as follows.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if let indexPath = getIndexPathForSelectedCell()
{
let DealsdetailViewController = segue.destinationViewController as! DealsDetailViewController
DealsdetailViewController.Dealsdata = Dealsdata[indexPath.row]
}
else if let indexPath2 = getIndexPathForSelectedCell2()
{
let ContainerviewController = segue.destinationViewController as! ContainerViewController
ContainerviewController.BTdata = BTdata[indexPath2.row]
}
}
if i click on a cell in first collection view segue performs correctly, when i click on a cell in second collection view
i got error
in
let DealsdetailViewController = segue.destinationViewController as! DealsDetailViewController
which is first if statement condition value, i'm stuck here
please help me, how to handle performing both segue on cell click on each collection view.
Use the method from UICollectionView protocol
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let cell = cellForItemAtIndexPath(indexPath)!
if collectionView == self.collectionView1 {
self.performSegueWithIdentifier("segue1", sender: cell)
} else if collectionView == self.collectionView2 {
self.performSegueWithIdentifier("segue2", sender: cell)
}
}
func prepareForSegue(segue: UIStoryBoardSegue, sender: AnyObject?) {
if segue.identifer == "segue1" {
let detailVC:DetailViewController = segue.destinationViewController as DetailViewController
// Your sender is cell. You have indexPath of them and can get his identity in dataSource.
//detailVC.name = ...
//detailVC.surname = ...
} else if segue.identifier == "segue2" {
//...
}
}