parse data to vc in swift 4 always nil - swift4

i want to parse data from one VC to antoher to open a webview with the given data as URL String. The data comes from a tableview. In the table view i have a button with a function to open the segue.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath, object: PFObject?) -> PFArchivTableViewCell? {
let cell = tableView.dequeueReusableCell(withIdentifier: "PFCell") as! PFArchivTableViewCell?
cell?.button.addTarget(self, action: #selector(someAction), for: UIControlEvents.touchUpInside)
cell?.button.accessibilityHint = object?.object(forKey: "calameoURL") as? String} return cell
Then i use a function for the button:
#objc func someAction(sender: UIButton) {
let PFurlString = sender.accessibilityHint!
print ("URL in the cell: \(PFurlString)")
self.performSegue(withIdentifier: "showPFArchivUrl", sender: AnyObject.self)
}
and the prepare for segue:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showPFArchivUrl" {
let destination = segue.destination as? ArchivWebViewController
print ("button pressed")
destination?.dataFromFirst = "Hello World"
destination?.PFurlString? = PFurlString!
}
}
The Problem is: the passed string in the ArchivWebViewController "Hello World" is available, but the given variable "PFurlString" is always nil. Has anyone an idea to get this variable on the other viewcontroller?
thanks a lot for the answer. i have change the following lines:
let cell = tableView.dequeueReusableCell(withIdentifier: "PFCell") as! PFArchivTableViewCell
cell.button.addTarget(self, action: #selector(someAction), for: UIControlEvents.touchUpInside)
cell.button.accessibilityHint = object?.object(forKey: "calameoURL") as? String
in the func for the button i get the value for the accessibilityHint in my print statement.
but in prepare(for segue: UIStoryboardSegue, sender: Any?) the value is always nil
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showPFArchivUrl" {
let destination = segue.destination as! ArchivWebViewController
print ("URL: \(PFurlString)")
destination.PFurlString = PFurlString
}

You're making a local PFurlString in #objc func someAction(sender: UIButton). IDK, where you get the PFurlString but try replacing
let PFurlString = sender.accessibilityHint!
with
PFurlString = sender.accessibilityHint!
Make sure you have a class variable of something like var PFurlString : String?

You can create a class with a variable in which you save the data of the URL. After you have presented the new view controller you can call this class in it and get the value of the variable and the as a result the url

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 Object from Table View Cell to Another View Controller Via Segue

I have the following portion of my code that I'm trying to work out in order to move from a table view controller to a view controller.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
let donation = donations[indexPath.row]
print(donation)
self.performSegue(withIdentifier: "showDonationReviewForm", sender: Any?)
}
On the above, when I print donation, it correctly prints the object and it's related fields. I know at some point I would need to use override func prepare(for segue... but I don't know how I am passing along the donation object to the next controller.
You can try
performSegue(withIdentifier: "showDonationReviewForm", sender:donations[indexPath.row])
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDonationReviewForm" {
if let nextViewController = segue.destination as? NextViewController {
nextViewController.toSend = sender as! Donation
}
}
}
class NextViewController :UIViewController {
var toSend:Donation?
....
}
Assuming donations is an array of Donation model

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

How to pass the index of the cell in the tableview from one view controller to the next upon pressing a button?

Every time I try to do the following, it passes on the index to the next view controller as being 0. I'm not sure what I'm doing wrong, can someone help? Thank you so much! Here is the relevant code:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "a", for: indexPath) as! TableViewCell
cell.useButton.tag = tagBaseValue + indexPath.row
cell.useButton.addTarget(self, action: #selector(ListViewController.useButtonPressed(_:)), for: UIControlEvents.touchUpInside)
return cell
}
#IBAction func useButtonPressed(_ sender: Any) {
performSegue(withIdentifier: "toDisplay", sender: self)
}
func prepare(for segue: UIStoryboardSegue, sender: UIButton) {
if segue.identifier == "toDisplay" {
let nextVC = segue.destination as! NextVC
nextVC.index = sender.tag
}
}
prepare(for is never called because the signature is wrong (the type of sender is Any?)
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toDisplay" {
let nextVC = segue.destination as! NextVC
nextVC.index = (sender as! UIButton).tag
}
}
and the IBAction must be
#IBAction func useButtonPressed(_ sender: UIButton) {
performSegue(withIdentifier: "toDisplay", sender: sender)
}
Prepare for segue must be overridden, and in button action while sending sender, you are sending the self, which is pointing to viewcontroller itself, hence you are receiving the tag always as 0.
Make changes for prepare for segue, make sender as Any and do overrride it. And in your button action while calling performSegue do mention sender as sender(which is button) and not self(which is view controller).
Hope it helps...

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.