Unwind Segue with Image - ios

I'm trying to use a unwind Segue with an ImageView. In my main VC I created this function for the unwind segue:
#IBAction func didUnwindFromSelectIcon(_ sender: UIStoryboardSegue){
guard let imageSelectionImage = sender.source as? SelectIconViewController else {return}
addEatImageViewEat.image = imageSelectionImage.img
}
Then I use this in my second VC
var img: UIImage?
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let selectedImage = collectionView.cellForItem(at: indexPath) as! SelectIconCollectionViewCell
img = selectedImage.selectIconImageView.image
}
I selected the didUnwindFromSelectIcon at the CollectionViewCell on the Storyboard. I get no error or something and I'm not sure what my mistake is. My addEatImageViewEat won't show my selected Image... Hope someone see what's my mistake - Thanks in advance
Update:
MainVC:
#IBAction func didUnwindFromSelectIcon(_ sender: UIStoryboardSegue){
guard let imageSelectionImage = sender.source as? SelectIconViewController else {return}
addEatImageViewEat.image = imageSelectionImage.img
}
SecondVC:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "unwindSegue" {
if let cell = sender as? SelectIconCollectionViewCell {
img = cell.selectIconImageView.image
}
}
}

The problem is that the segue happens before func collectionView(_:didSelectItemAt:) is called.
Instead of using that function, use prepare(for:sender:) to set the image:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "unwindSegue" {
if let cell = sender as? SelectIconCollectionViewCell {
img = cell.selectIconImageView.image
}
}
}
Make sure to set the identifier for your segue and use that in place of "unwindSegue" above. To set the segue identifier, find the unwind segue in the Document Outline view and select it. Then in the Attributes Inspector on the right, set the Storyboard Segue Identifier to your identifier.

Related

Receiver has no segue with identifier 'goToDetail'

I've double-checked that my identifier is spelled correctly in the storyboard and that the segue is pointed in the right direction, but I keep receiving this error. Could someone take a look at my code to see if I'm missing something?
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedData = tableData[indexPath.row]
tableView.deselectRow(at: indexPath, animated: true)
performSegue(withIdentifier: "goToDetail", sender: selectedData)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? DetailViewController {
destination.vocab.text = sender as? String
}
}
Edit:
segue can be used only with if you have a UINavigationController that will handle the navigation. You performing a segue to UINavigationController. UINavigationController should be at the root of your storyboard.
In your didSelectRowAt function change
performSegue(withIdentifier: "goToDetail", sender: selectedData)
To NavigationController Identifier (Note if you do not have identifier already set up in storyboard you will need to do that first)
performSegue(withIdentifier: "goToNavigationConrtoller", sender: selectedData)
And then change the prepareForSegue function to below.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//check destination for segue is Navigation controller
if let navVC = segue.destinationViewController as? UINavigationController {
// get hold of the first viewController.
if let destination = navVC.viewControllers[0] as? DetailViewController {
destination.vocab.text = sender as? String
//all the other code you need
}
}
}

IOS/Swift: Pass Object in tableview to detail view controller

I am trying to grab an object from a tableview and pass it to a detail view, something I know how to do in Objective-C but am learning for first time Swift. However, my code is not getting the row from the index path or object.
Here is my code.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
print("segue")
if segue.identifier == "showDetail"{
if let destinationVC = segue.destination as? detailVC {
)
if let indexPath = self.tableView.indexPathForSelectedRow {
print("row%#",indexPath)//Prints as nil
let thisItem = myItems[indexPath.row]//never gets here
destinationVC.item = thisItem
}
}
}
}
Can anyone see why I am not getting the row or the object? Thanks in advance for any suggestions.
Edit:
I got it to work with following:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail" {
let indexPath: NSIndexPath = self.tableView.indexPathForSelectedRow! as NSIndexPath
let anItem: myItem = myItems[indexPath.row];
let destVC = segue.destination as? detailVC
destVC?.item = anItem
}
}
Implement UITableViewDelegate method,
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let item = myItems[indexPath.row]
self.performSegue(withIdentifier: "showDetail", sender: item)
}
then implement below,
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showdetail" {
let detailController = segue.destination as! detailVC
detailController.item = sender as! Your_Item
}
}
Why don't you use these methods to save the value of the selected row or item? and then perform segue?
tableView(_:didDeselectRowAt:)
tableView(_:didSelectRowAt:)

Set a string as a var after selecting a UITableView cell in Swift 3

I am making an audio app, and I am populating a table view controller with data from JSON. Based on the user's selection, I want to pass the episode_name, shown in the cell, into the next view after segue.
So far, the table loads with data, I can pass a locally defined variable to the next view, but I can't copy the string from the cell into that variable.
Here's my code.
func extract_json(_ data: Data)
{
//... removed to condense
if let shows_list = json as? NSArray
{
for i in 0 ..< data_list.count
{
if let shows_obj = shows_list[i] as? NSDictionary
{
let episode_name = shows_obj["episode"] as? String
let episode_date = shows_obj["date"] as? String
TableData.append(episode_date! + " | " + episode_name!)
}
}
}
DispatchQueue.main.async(execute: {self.do_table_refresh()})
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "passer", sender: indexPath)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "passer" {
let vc = segue.destination as! EpisodeViewController
vc.variableInSecondVc = "Pass Variable" // this is where I want to pass episode_name
}
} // end segue
Solutions I have tried:
1) if I call episode_name immediately, it flags it because that variable is contained in the prior function,
2) if I try to run the extract_json function in the ViewDidLoad, it's causing other issues in the code.
I'm new to Swift and unsure -- is there a better way to "copy" the string from that cell and pass it to the vc.variableInSecondVc?
EDIT: One point of clarification. If I ran this code, it would successfully change the subsequent UILabel to "Pass Variable" -- but of course, I actually want to turn PassVariable dynamic by changing it to reflect the string of episode_name.
The performSegue(withIdentifier:sender:) method takes two arguments, 1. The Segue identifier, 2. The parameter you want to pass of type AnyObject?
self.performSegue(withIdentifier: "passer", sender: indexPath)
In the prepare(for:sender:) method, you check the segue identifier and cast the sender parameter to the type you had passed earlier, and get data from the array list to pass it to next view controller.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "passer" {
guard let indexPath = sender as? IndexPath else { return }
let data = TableData[indexPath.row] //write your logic here to get value from your data list based on index path row value and pass value to view controller.
let vc = segue.destination as! EpisodeViewController
vc.variableInSecondVc = data //value which you got from list based on indexPath
}
}
Get data from indexPath
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "passer" {
let vc = segue.destination as! EpisodeViewController
vc.variableInSecondVc = TableData[indexPath.row]
}
}
And carefully, you should get the string in viewDidAppear in secondViewController
override func viewDidAppear() {
label.text = variableInSecondVc
}
Thanks for the help, all.
While these solutions didn't work, they helped me rethink the problem, and I found a solution that will pass the value to the label in the next VC successfully. Here's the approach:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "passer", sender: indexPath)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let indexPath = self.tableView.indexPathForSelectedRow {
let controller = segue.destination as! EpisodeViewController
controller.variableInSecondVc = TableData[indexPath.row]
}
}
The label now updates in the next view controller.
try this it will send the selected string to next View controller
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "passer" , let indexPath = sender as? IndexPath{
let vc = segue.destination as! EpisodeViewController
vc.variableInSecondVc = TableData[indexPath.row]
}
}

Usage of performSeguewithIdentifier Function in Dynamic Values Tableview

I can list datas in tableview. When I choose a row and trying to pass another view controller with showing specific data related to my pressed cell, It couldn't make it.
I didn't able to store data "selectedMeal" variable in prepareforsegue function, it always return [ ].
I think, my main problem is selecting the cell and sending to this cell to prepare for segue function. Perhaps, it has a problem in DispatchQueue.main.async function.
*When I try to pass to static data, it works great.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .checkmark;
DispatchQueue.main.async {
self.performSegue(withIdentifier: "gotoOrderDetail", sender: self)
}
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "gotoOrderDetail") {
let DestViewController : OrderDetailListViewController = segue.destination as! OrderDetailListViewController
let selectedMeal = selectedCells.map { (index: Int) -> SavedMeal in
return savedMeal[index]
}
DestViewController.mealarray = selectedMeal
}
}
Try to use this code
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "gotoOrderDetail") {
let DestViewController : OrderDetailListViewController = segue.destination as! OrderDetailListViewController
let path = self.tableView.indexPathForSelectedRow()! // get the selected indexPath
DestViewController.mealarray = savedMeal[path.row]
}
}
Try to use Sender parameter
you can you like this:
self.performSegue(withIdentifier: "gotoOrderDetail", sender: indexPath)
and then in prepare(for segue: sender?)
if (segue.identifier == "gotoOrderDetail") {
let DestViewController : OrderDetailListViewController = segue.destination as! OrderDetailListViewController
let index = sender as! Int
DestViewController.mealarray = savedMeal[index]
}
p/s: you do not need to use dispatch queue in this case

Getting object for tapped UITableViewCell in new UIView?

What is the right way to segue from a cell in a UITableViewCell to a new view, passing parameter data?
I have specified a segue from my prototype cell in my UITableViewCell, that links it to a new UIVIew and has it set to show (aka push). The new UIView displays, but I am not sure how to make tell the UIView the section/row that was selected or tell it about the object associated with that selection.
An abridged version of my code is shown below:
class MyTableViewController : UITableViewController {
// other code omitted
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let files = filesByDate[filesByDateKeys![indexPath.section]]
self.selectedFile = files![indexPath.row]
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "SegueToFileDetails") {
let destinationViewController = segue.destinationViewController as! FileDetailsViewController
destinationViewController.file = self.selectedFile
}
}
}
class FileDetailsViewController : UIViewController {
var file: NSURL
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
print("File: ", file)
}
}
What I find happening is the tableView() function is called after the prepareForSegue() functon, causing the file attribute to be nil when viewWillAppear() is called.
A little more search turned up this other post, which indicated the right approach. The tableView() function in my question is not needed. Instead (in Swift 2):
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "SegueToFileDetails") {
let destinationViewController = segue.destinationViewController as! FileDetailsViewController
let path = self.tableView.indexPathForSelectedRow
let files = filesByDate[filesByDateKeys![path!.section]]
destinationViewController.file = files![path!.row]
}
}
And if you want to simply do behaviour based on the specific destination class, based on another suggestion:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let destinationViewController = segue.destinationViewController as? FileDetailsViewController {
let path = self.tableView.indexPathForSelectedRow
let files = filesByDate[filesByDateKeys![path!.section]]
destinationViewController.file = files![path!.row]
}
}

Resources