Hello StackOverflow,
I'm just picking up swift and trying to implement data being passed between UITableView Cell to a UIViewController which will show a detailed view of the info shown on the tableview, and whenever I test the application on my emulator first time I press a table cell it passes an empty string and then when I try pressing another cell the viewController shows the string that was supposed to be seen earlier.I pasted the code I have for my tableview didSelectRowAtIndexPath below.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: false)
var7 = lat[indexPath.item]
var6 = long[indexPath.item]
var5 = items[indexPath.item]
var1 = detail[indexPath.item]
var2 = date[indexPath.item]
var3 = wop[indexPath.item]
var4 = ViewController()
nextView.locationPassed = var1
//self.performSegueWithIdentifier("DetailPush", sender: self)
println("value stored in var1: \(var1)")
//println("The selected indexPath is \(indexPath.item + 1)")
println("The stored id is: \(storeSend)")
}
Here is my implementation for my push segue method
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "DetailPush"
{
if let crimesView = segue.destinationViewController as? ViewController {
crimesView.locationPassed = var1
//println("The passing address is: \(var1)")
}
}
}
Any idea on why I'm getting data delayed during the segue?
Thank you
Solution Found: I edited my prepareForSegue method with the following and it fixed my issue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
//Adding the indexPath variable for the selected table Row within the segue
var indexPath: NSIndexPath = self.tableView.indexPathForSelectedRow()!
if segue.identifier == "DetailPush"
{
if let crimesView = segue.destinationViewController as? ViewController {
//Then just pass the data corresponding to the array I created identified by the index of the selected row
crimesView.locationPassed = self.arrayName[indexPath.row]
println("The passing address is: \(self.addressSend)")
}
}
}
I found the solution by watching some online videos and all I did to fix my issue was redefine my prepareForSegue function with:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
//Adding the indexPath variable for the selected table Row within the segue
var indexPath: NSIndexPath = self.tableView.indexPathForSelectedRow()!
if segue.identifier == "DetailPush"
{
if let crimesView = segue.destinationViewController as? ViewController {
//Then just pass the data corresponding to the array I created identified by the index of the selected row
crimesView.locationPassed = self.arrayName[indexPath.row]
println("The passing address is: \(self.addressSend)")
}
}
}
And it seems to work like a regular segue for me.......Thank you for all the suggestions given me
you said you are doing the prepareForSegue from async request
so try this:
if segue.identifier == "DetailPush"
{
dispatch_async(dispatch_get_main_queue()) {
if let crimesView = segue.destinationViewController as? ViewController {
crimesView.locationPassed = var1
//println("The passing address is: \(var1)")
}
}
}
try to remove the line
tableView.deselectRowAtIndexPath(indexPath, animated: false)
see if it still happens.
maybe move it to the end
Related
In Swift 3, I'd like to pass the string contained in a cell of a UITableView into the subsequent View Controller.
As a note, I read several answers to this that seem to be specific to earlier versions of Swift, so I wanted to reopen. As an example, the last solution here looked straightforward, but I can't get it to work.
In TableViewController, I create a string of an audio file's name and date posted with this JSON extraction:
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!)
let testString = TableData.append(episode_date! + " | " + episode_name!)
// the part above runs and will add the string into each cell. now here, I want to pass the value of that string into a UILabel called episodeTitle in the target view controller
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let indexPath = self.tableView.indexPathForSelectedRow {
let destinationVC = segue.cellPasser
EpisodeViewController.text = testString //this is the string in second view controller
}
}
}
}
}
This is throwing two errors:
Value of type 'UIStoryboardSegue' has no member 'cellPasser'
In the Storyboard, I have added an identifier to the Show segue called 'cellPasser.' My belief is I should be able to call that here but it's being flagged.
EpisodeViewController.episodeTitle = testString
I have an outlet in EpisodeViewController that is called episodeTitle, so I am wondering if there is a preferred way other than this to pass strings into an element like that.
I'm new to Swift -- hoping someone sees a better way to do this.
Edit: In case useful, here's the View Controller linked from the segue.
class EpisodeViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBOutlet var episodeTitle: UILabel!
Here are steps to pass value from TableViewController to next ViewController :
in TableViewController You should declare a didSelectRowAt method.
Declare a method prepare for segue
Do not forget to declare a variable in second view Controller.
1.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "Identifier", sender: indexPath)
}
2.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "Identifier" {
let vc = segue.destination as! NameOfYourViewController
vc.variableInSecondVc = variableInTableView
}
}
3.
var variableInSecondVc = ""
I'm making ios app. Please look my table view image below.
If you click add(+) button, you can add ENG word and its meaning in Korean(KOR) in each textfield.
After filling the textfield and click save button (it is located on right-top, "저장"), the word is added like the image below.
word is added
For example, the ENG is endless and the meaning(KOR) is "끝없는".
And, I want to use UIReferenceLibraryViewController .
If i click the cell of the list, i want to show its dictionary.
#IBAction func viewDictionary(_ sender: UITapGestureRecognizer) {
let engDictionaryWord = **engListWord**
let ViewController = UIReferenceLibraryViewController(term: engDictionaryWord)
self.present(ViewController, animated: true, completion: nil)
}
I want to use this method.
But, I don't know how to save my ENG input in engListWord.
In pic2 's swift file(addWordViewController.swift), there is prepare() method like this.
// This method lets you configure a view controller before it's presented.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
// Configure the destination view controller only when the save button is pressed.
guard let button = sender as? UIBarButtonItem, button === saveButton else {
os_log("The save button was not pressed, cancelling", log: OSLog.default, type: .debug)
return
}
let eng = engTextField.text ?? ""
let kor = korTextField.text ?? ""
// Set the meal to be passed to WordTableViewController after the unwind segue.
word = Word(eng:eng, kor:kor)
}
and viewDidLoad() method in addWordViewController.swift
override func viewDidLoad() {
super.viewDidLoad()
engTextField.delegate = self
korTextField.delegate = self
// Set up views if editing an existing Word.
if let word = word{
engTextField.text = word.eng
korTextField.text = word.kor
}
// Do any additional setup after loading the view.
}
I don't know which variable i have to use.
There is other swift file in my project, If i misuploaded that codes above, please tell me! I will edit my question immediately.
Main.Storyboard
If i use GestureRecognizer, i made this code but I don't know it is right...
#IBAction func MyDictionary(_ sender: UITapGestureRecognizer) {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "viewDictionary", sender: indexPath)
}
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// I just made this identifier up, but create one yourself in the storyboard
if segue.identifier == "viewDictionary" {
// Define your vc
let libController = segue.destination as! UIReferenceLibraryViewController
// Define indexPath
let indexPath = sender as! IndexPath
// Set value in destination vc
libController.engWord = words[indexPath.row].eng
}
}
}
I think the way to go is to use the UITableViewDelegate method didSelectRowAtindexPath in the WordTableViewController (if that's the class with your table view).
A gestureRecognizer does not seem like something you want in your tableViewController as it has nice build in delegate methods to register user presses. Therefore, replace your viewDictionary(_:) function with the following:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "viewDictionary", sender: indexPath)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// I just made this identifier up, but create one yourself in the storyboard
if segue.identifier == "viewDictionary" {
// Define your vc
let libController = segue.destination as! UIReferenceLibraryViewController
// Define indexPath
let indexPath = sender as! IndexPath
// Set value in destination vc
libController.engWord = yourArrayOfEngWords[indexPath.row]
}
}
This will get your eng word of the cell you have pressed and save it to an attribute "engWord" that you then define in your UIReferenceLibraryViewController:
class UIReferenceLibraryViewController(){
var engWord: String = ""
// Rest your class properties and functions here...
}
Once it is set you can use it as you like after the segue has been performed :=)
I am new to Swift and I have this interesting problem.
I am trying to send the label of a table cell when I segue to another view controller where I print it. The problem is that it is printing the label of the cell that was pressed previous to this press.
Here is the code in the main view controller that passes the label:
// When a user taps on a cell on the tableView, it asks for a tag name for that image.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Cell \(indexPath) selected")
// Get cell image.
let indexPath = tableView.indexPathForSelectedRow
let currentCell = tableView.cellForRow(at: indexPath!) as! ImageFeedItemTableViewCell
imagePass = currentCell.itemImageView
labelPass = currentCell.itemTitle
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Send image to GreetingViewController.
if segue.identifier == "GoToGreeting" {
var greetingvc = segue.destination as! GreetingViewController
greetingvc.passedImage = imagePass
greetingvc.passedLabel = labelPass
}
}
and here is the relevant code in the view controller that receives the passed label:
var passedImage: UIImageView? = nil
var passedLabel: UILabel? = nil
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
print(passedLabel?.text)
}
Any help would be appreciated.
I believe prepare(for:sender:) gets called before tableView(_:didSelectRowAt:) when you hook up that segue in the storyboard.
What you can do is just use the sender parameter of the prepare(for:sender:) method to get the information you need at the right time. When a segue is triggered by a cell, as it seems to be in your case, then that cell will be the sender passed into the the prepare method. So, you could do something like:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Send image to GreetingViewController.
if let cell = sender as? ImageFeedItemTableViewCell, segue.identifier == "GoToGreeting" {
var greetingvc = segue.destination as! GreetingViewController
greetingvc.passedImage = cell.itemImageView
greetingvc.passedLabel = cell.itemTitle
}
}
I have a problem with indexPathForSelectedRow()
I have 2 viewcontroller:
tableview and view controller
I want to move from tableview to another controller
and I used func prepareForSegue but I have problem in indexpathselectedrow()
This is issue for the problem:
cannot invoke "indexpathforselectedRow" with no arguments
The Xcode is a last version
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "show"
{
let indexpath = tableView.indexPathForSelectedRow()
let detailvc: fiveViewController = segue.destinationViewController as! fiveViewController
}
}
There is the indexPathForSelectedRow definition in Swift 1.2:
- (NSIndexPath *)indexPathForSelectedRow; // returns nil or index path representing section and row of selection.
There is its definition in Swift 2.0:
var indexPathForSelectedRow: NSIndexPath? { get } // returns nil or index path representing section and row of selection.
In Swift 2.0, the indexPathForSelectedRow is a property not a method, so you should change:
let indexpath = tableView.indexPathForSelectedRow()
to
let indexpath = tableView.indexPathForSelectedRow
Sounds like there is no reference to tableView or it's not of type UITableView.
override func prepareForSegue(segue: UIStoryboardSegue , sender: AnyObject?) {
if segue.identifier == "show"
{
let indexpath = self.tableView.indexPathsForSelectedRows()!
let detailv:fiveViewController = segue.destinationViewController as! fiveViewController
detailv.pic = self.menu[indexpath.row].picName
}
this link for the pic " my problem "
I want to select a username from a UICollectionView, and pass that string to another view.
I can select the cell using "didSelectRowAtIndexPath". However the prepareForSegue function runs before my selection is set, and the segue passes the initial value.
I can't figure out how to get the index value in the prepareForSegue overide. If it were a UITableView, I think I could use indexPathForSelectedRow.
Here's what I have:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
selectedUsername = userNames[indexPath.row]
selectedRow = indexPath.row
println ("Cell \(indexPath.row) selected")
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "userSelectSegue") {
let nextVC = segue.destinationViewController as ViewController;
nextVC.passedUsername = userNames[selectedRow]
println("prepareForSegue")
}
}
Running this always passes userNames[0]
The output window Prints:
prepareForSegue
Cell 2 selected
EDIT 1:
I basically think I want the following tableview code, but I can't get it working for UICollectionView (i.e. I can't get the cell number):
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "userSelectSegue") {
let nextVC = segue.destinationViewController as ViewController;
let indexPath = UserSelectCollection.indexPathForSelectedRow()
nextVC.passedUsername = userNames[indexPath.row]
}
}
Here's How I solved it:
I deleted the segue connecting the collection cell to the second view controller
I created another segue between the two view controllers (called the identifier "userSelectSegue")
Added a performSegueWithIdentifier call to the didSelectItemAtIndexPath
Here's the code:
var userNames = ["Bob", "Sally", "Mike", "Mary", "James"]
var selectedRow = 0
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
selectedRow = indexPath.row
self.performSegueWithIdentifier("userSelectSegue", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "userSelectSegue") {
let nextVC = segue.destinationViewController as ViewController;
nextVC.passedUsername = userNames[selectedRow]
}
}
This is the general behavior of the iOS. What i implement is in this case is. Do not override the method didSelectRowAtIndexPath. When you tap on any cell, then in the function prepareForSegue. You can get the cell in the sender object. From that cell get the selected item. Get the indexPath.item. After that get the object from the array and pass it to the next view controller.