Populate textfield.text after segue - ios

I have a show-type segue. I want destinationViewController nameTextField to contain some text in it when segue is performed. I tried doing:
override func prepare (for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ToEditScreen" {
let svc = segue.destination as! EditViewController
svc.nameTextField.text = cars[selectedIndex!].name //crashes
svc.nameString = cars[selectedIndex!].name
}
}
The error I get is: Unexpectedly found nil while implicitly unwrapping an Optional value.
I know that cars[selectedIndex!].name is not nil.
If I delete the textfield line everything is fine and nameString does get its value which is equal to cars[selectedIndex!].name. I know I can do:
nameTextField.text = randomString
but it seems like an extra step. Can I populate textfield.text from original ViewController?

You can add a string variable to the destination vc and set it there or
let svc = segue.destination as! EditViewController
svc.loadViewIfNeeded() // add this line
svc.nameTextField.text = cars[selectedIndex!].name

Related

How to access custom annotation properties when using calloutAccessoryView as the sender of a segue to a new viewcontroller?

I have the following code to prepare for my segue:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Make sure we are acting on the correct segue
if segue.identifier == "CreateJumpSpot", let jumpSpotCreatorControllerVC = segue.destination as? JumpSpotCreatorController {
// Set the delegate in the JumpSpotCreatorController we're navigating to
jumpSpotCreatorControllerVC.delegate = self
} else if segue.identifier == "JumpSpotInfo", let jumpSpotInfoVC = segue.destination as? JumpSpotInfoController {
if let senderAnnotationView = sender as? JumpSpotAnnotationView {
jumpSpotInfoVC.titleLabel.text = senderAnnotationView.annotation?.title as? String
jumpSpotInfoVC.imageView.image = senderAnnotationView.annotation.
}
}
}
We are focusing on the 'else if' part of the statement here. I have a custom annotation and annotation view. I am populating labels and imageViews in the view controller that I am segueing to, using the properties of the annotation that the user clicked on to reveal the .detailDisclosure version of the rightCalloutAccessoryView. However that sender (.detailDisclosure of rightCalloutAccessoryView) is only allowing me to access the title and subtitle of the annotation. As you can see when I got to the image property I stopped typing, as there was no property to access. How can I access the properties of my custom annotation?
Can‘t you just get the image by senderAnnotationView.annotation?.image, just like what you are doing to get the title?
PS: Don't depend too much on Xcode autocompletion. Sometimes it's doesn't work perfectly well.
Ok I figured it out. All I had to do was adjust the code so that I had a constant of the annotation itself, and cast it as my custom class. Here's the code:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Make sure we are acting on the correct segue
if segue.identifier == "CreateJumpSpot", let jumpSpotCreatorControllerVC = segue.destination as? JumpSpotCreatorController {
// Set the delegate in the JumpSpotCreatorController we're navigating to
jumpSpotCreatorControllerVC.delegate = self
} else if segue.identifier == "JumpSpotInfo", let jumpSpotInfoVC = segue.destination as? JumpSpotInfoController {
if let senderAnnotationView = sender as? JumpSpotAnnotationView {
let senderAnnotation = senderAnnotationView.annotation as? JumpSpotAnnotation
jumpSpotInfoVC.titleLabel.text = senderAnnotation?.title
jumpSpotInfoVC.imageView.image = senderAnnotation?.image
jumpSpotInfoVC.descriptionLabel.text = senderAnnotation?.description
jumpSpotInfoVC.heightLabel.text = senderAnnotation?.estimatedHeight
jumpSpotInfoVC.warningsLabel.text = senderAnnotation?.warnings
}
}
}
The key line there is: let senderAnnotation = senderAnnotationView.annotation as? JumpSpotAnnotation

Value of type 'HistoryViewController' has no member 'match'

I cannot figure out what the error "Value of type 'HistoryViewController' has no member 'match'" is telling me. Directly above, similar code seems to work:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "throwDownScissors" {
let controller = segue.destination as! ResultViewController
controller.match = self.match
}
else if segue.identifier == "showHistory" {
let controller = segue.destination as! HistoryViewController
controller.match = self.match
}
}
Why does the second bit of code trigger the error?
It seems that your ResultViewController has a match property declared inside it but HistoryViewController doesn't have this property so when the if statment go through the else condition it cannot call the match property which is not existing since you force casted the destination controller to HistoryViewController

Prepare for segue function not loading new values

The statValue attribute of my UIButton class has been updated since the segue was last called, but the segue still sends the old, original value. Is there a way to refresh the prepare function (below) so that it sends the new value?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "StatDetailSegue" {
if let destinationVC = segue.destination as? StatDetailViewController,
let index = (sender as? StatButton)?.buttonIndex,
let sendVal = (sender as? StatButton)?.buttonValue,
let sendUnit = (sender as? StatButton)?.buttonUnit,
let sendTitle = (sender as? StatButton)?.detailTitle {
destinationVC.statID = index
destinationVC.statValue = sendVal
destinationVC.statUnit = sendUnit
destinationVC.statTitle = sendTitle
print("Destination STATID: \(destinationVC.statID)")
print("Destination value: \(destinationVC.statValue)")
}
}
}
Check your StatButton if you using in storyboard your buttons , then your button should inherit from StatButton instead of UIButton otherwise your code looks fine.
Can you debug the value of statValue in your destinationVC and check if it gets updated after the destinationVC is presented? Also, check the implementation of 'StatButton' class, maybe the buttonValue property is a lazily initialized property and initialized only once? That's why maybe you keep getting the first value that was assigned to the buttonValue always.

String not being passed to next view controller from prepareForSegue

I have a push segue on my StoryBoard which is named toGuestVC.
I use that to segue to the next ViewController in my didSelectRowAtIndexPath method like so:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let username = followUsernameArray[indexPath.row]
performSegue(withIdentifier: SG_TO_GUEST_VIEW_CONTROLLER, sender: username)
}
Then in my prepareForSegue:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == SG_TO_GUEST_VIEW_CONTROLLER {
if let nextVC = segue.destination as? GuestCollectionVC, let sender = sender as? String {
print("PRINTING NEXT VC: \(nextVC)") //This prints out the memory address. Not sure if this is what you meant by print nextVC.
nextVC.guestUser = sender
}
}
}
For some reason this line in my prepareForSegue is not running:
nextVC.guestUser = sender.username
When I try to print out the value guestUser in my nextViewController the value of guestUser is nil. But when I print out the value of sender in my prepareForSegue method it is not nil.
So is my sender value not being passed to the next ViewController? I can't find a solution to this problem any ideas?
GuestCollectionVC Implementation:
import UIKit
import Parse
private let reuseIdentifier = "Cell"
class GuestCollectionVC: UICollectionViewController {
var guestUser: String!
override func viewDidLoad() {
super.viewDidLoad()
print("PRINTING SELF IN GuestCollectionVC: \(self)")
loadPosts()
}
func loadPosts() {
//Load posts query
let query = PFQuery(className: PF_POSTS_CLASS)
query.limit = postCount
//Getting error here below this comment when I use guestUser since it is nil
query.whereKey(PF_POSTS_USERNAME_COLUMN, equalTo: guestUser)
query.findObjectsInBackground { (result: [PFObject]?, error: Error?) -> Void in
if error == nil {
if let result = result {
self.uuidOfPosts.removeAll(keepingCapacity: false)
self.imageArrayOfPFFIle.removeAll(keepingCapacity: false)
for postObject in result {
if let uuid = postObject[PF_POSTS_UUID_COLUMN] as? String, let pic = postObject[PF_POSTS_PIC_COLUMN] as? PFFile {
self.uuidOfPosts.append(uuid)
self.imageArrayOfPFFIle.append(pic)
}
}
self.collectionView?.reloadData()
}
}else if error != nil {
print("ERROR FROM GUEST COLLECTION VC FROM loadPosts FUNCTION: \(error?.localizedDescription)")
}
}
}
}
So this is my implementation in the GuestViewController. In my loadPosts method where I used the variable guestUser I am getting the error:
fatal error: unexpectedly found nil while unwrapping an Optional value
From console printing
PRINTING NEXT VC: "InstagramClone.GuestCollectionVC: 0x7a6c5cc0"
PRINTING SELF IN GuestCollectionVC: "InstagramClone.GuestCollectionVC: 0x7a6c5100"
it's now obvious that hidden unexpected instance of GuestCollectionVC was created. So, there are different errors occurs depending on order of this two objects invoke their viewDidLoad method (can be any order). Also there are can be other errors in nextVC viewDidLoad method, but this is other story for other question.
You got this problems because you created action segue, that works automatically on cell click (hidden view controller created), and at the same time you are perform this segue in code, creating second controller nextVC.
To solve issue, you should find and remove that segue and add new one, not action segue from some element of your view controller, but "empty" segue between view controllers. To create segue of this type you should select first view controller, hold "control" key and start dragging to next view controller from yellow square on top of first view controller (that symbol controller itself), choose "show", and set identifier.
Since I don't have the full context of the values within your tableView method I can only speculate. That said, the sender you're passing in should be the view controller:
performSegue(withIdentifier: "toGuestVC", sender: username)
You're passing in a value called username which looks to be a string value? It should be something like:
performSegue(withIdentifier: "toGuestVC", sender: self)
where self is your view controller. If you're passing in a string value to sender then in your prepareForSegue method then sender does not have a property called username sender actually is username. Therefore you should pass the value elsewhere:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let indexPath = self.tableView.indexPathForSelectedRow
if let nextVC = segue.destination as? GuestCollectionVC {
nextVC.guestUser = followUsernameArray[indexPath.row]
}
}

Value of type 'UIViewController' has no member 'jsonfile' named JSON

I currently have a button set to go to a TableViewController but decided I wanted to embed that TableViewController in a TabBarController. I am running into an error while trying to pass it to the UITabBarController.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "showListSegue") {
let tabBarController = segue.destinationViewController as! UITabBarController
tabBarController.selectedIndex = 0 // choose which tab is selected
let des = tabBarController.selectedViewController!
des.jsonfile = self.jsonfile
}
}
In the last line of code, des.jsonfile = self.jsonfile, I am getting the error...
Value of type 'UIViewController' has no member 'jsonfile'
I am trying to pass the jsonfile to the TableViewController which is now embedded in the UITabBarController. How can this be done? I have this variable in the TableViewController is was getting passed to but now that I threw this TabBarController in the mix I am getting all confused.
I also tried to create a Cocoa file for the TabBarcontroller and set the variable var jsonfile : JSON! but that did not work either. (That is the variable in my TableViewController that I want to pass it to) Please help. Thank you.
You need to let the compiler know that selectedViewController is a type with the member jsonFile. Also, you should check that it actually is existing and of the correct class at runtime. Here's the kind of pattern you should be using:
class JSONDisplayController: UIViewController {
var jsonfile: String
}
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "showListSegue") {
guard let tabBarController = segue.destinationViewController as? UITabBarController else {
preconditionFailure("Unexpected destination.")
}
tabBarController.selectedIndex = 0 // choose which tab is selected
guard let des = tabBarController.selectedViewController as? JSONDisplayController else {
preconditionFailure("Unexpected selection.")
}
des.jsonfile = jsonfile
}
}

Resources