UIAlertAction actionsheet fetch data to childVC - ios

I have a parentVC that allows user to add by using actionsheet's choices
Expected Result :
when actionsheet presented, user choose the choices and the actionsheet will perform segue to childVC and childVC's label.text will become the chosen choice
My issue is I print out self.textInAS is exactly what the action.title, however, when segue performed, textFromAS become nil, so after some research I guess I lack of closure that required, however I am still new in Swift and I not sure how to properly perform a closure. Please provide example with code to help.
Many Thanks!!
/* parentVC */
var textInAS : String?
#IBAction func addBtnPressed(_ sender: UIBarButtonItem) {
let alert = UIAlertController(title: "Alert Title", message: "alert msg", preferredStyle: .actionSheet)
let actionA = UIAlertAction(title: "Choices A", style: .default) { (action) in
let chosenTitle = action.title
self.textInAS = choosenTitle
self.performSegue(withIdentifier: "goChildVC", sender: self)
}
let actionB = UIAlertAction(title: "Choices B", style: .default) { (action) in
let chosenTitle = action.title
self.textInAS = choosenTitle
self.performSegue(withIdentifier: "goChildVC", sender: self)
}
alert.addAction(actionA)
alert.addAction(actionB)
present(alert, animated: true, completion: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "goChildVC") {
let destinationVC = segue.destination as! ChildTableViewController
destinationVC.textFromAS = self.textInAS
}
}
}
}
/* ChildVC */
#IBOutlet weak var label: UILabel!
var textFromAS: String?
override func viewDidLoad() {
super.viewDidLoad()
label.text = textFromAS
}

Related

Prepare for segue function can't pass data to another VC Swift,

I'm trying to pass data from the alert text field to another VC's variable.
And here's my alert controller.
let alert = UIAlertController(title: "Download URL", message: "", preferredStyle: .alert)
let action = UIAlertAction(title: "Download", style: .default) { (action) in
guard let textField = alert.textFields?.first else {return}
self.ayb = textField.text ?? "Blank"
UserDefaults.standard.set(self.ayb, forKey: "urlString")
self.performSegue(withIdentifier: "segAdd", sender: self)
}
let secondAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alert.addTextField { (actionTextField) in
actionTextField.placeholder = "Paste link here"
}
alert.addAction(action)
alert.addAction(secondAction)
present(alert, animated: true, completion: nil)
}
And here's my prepare function for passing data.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segAdd" {
let destinationVC = tabBarController?.viewControllers?[0] as? BrowserWebViewController
destinationVC?.urlFromDownloads = self.ayb
print("The value of destinationVC?.urlFromDownloads is \(destinationVC?.urlFromDownloads)")
}
}
And in the console, it writes "The value of destinationVC?.urlFromDownloads is \Optional("Text I typed in textField")".
But in BrowserWebViewController my "urlFromDownloads" is = ""(which is default).
Note: Segue's name is true.
First of all rather than declaring an extra property or saving the value to UserDefaults you can pass the string in the sender parameter
let action = UIAlertAction(title: "Download", style: .default) { (action) in
guard let textField = alert.textFields?.first else {return}
self.performSegue(withIdentifier: "segAdd", sender: textField.text!)
}
Your way to determine the destination view controller is wrong. Ask the segue for the destination. And you can force downcast the type. The code must not crash if the segue is designed correctly.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segAdd" {
let destinationVC = segue.destination as! BrowserWebViewController
destinationVC.urlFromDownloads = sender as! String
print("The value of destinationVC?.urlFromDownloads is \(destinationVC.urlFromDownloads)")
}
}

How to send the title from UIAlertAction to another UIViewController as title of that VC

I have an UIAlertController with 4 options. When I choose any of that options I want to send the name of that option to the next ViewController as Title of that ViewController.
Here is my code:
func showOptions(){
let actionSheet = UIAlertController(
title: "Select a type of inspection",
message: nil,
preferredStyle: .actionSheet
)
let cancel = UIAlertAction(
title: "Cancel",
style: .cancel,
handler: nil
)
let copyOfVehicleShortCheck = UIAlertAction(
title: "Copy of Vehicle Short Check",
style: .default
) { action in
self.performSegue(
withIdentifier: Constants.checklistInspectionIdentifier,
sender: self
)
}
let fullDailyDefect = UIAlertAction(
title: "Full Daily Defect and Damage Check",
style: .default
) { action in
self.performSegue(
withIdentifier: Constants.checklistInspectionIdentifier,
sender: self
)
}
let licenceCheck = UIAlertAction(
title: "Licence Check Y/N",
style: .default
) { action in
self.performSegue(
withIdentifier: Constants.checklistInspectionIdentifier,
sender: self
)
}
let vehicleShortCheck = UIAlertAction(
title: "Vehicle Short Check",
style: .default
) { action in
self.performSegue(
withIdentifier: Constants.checklistInspectionIdentifier,
sender: self
)
}
actionSheet.addAction(copyOfVehicleShortCheck)
actionSheet.addAction(fullDailyDefect)
actionSheet.addAction(licenceCheck)
actionSheet.addAction(vehicleShortCheck)
actionSheet.addAction(cancel)
self.present(actionSheet, animated: true, completion: nil)
}
It is possible to send that parameter title from UIAlertAction to the next ViewController ?
As #Sh_Khan pointed out, to get the title you need action.title.
My answer is an add-on, since from your question and code it's not clear that you know how to do this.
To actually send the title from one VC to another you need to override the prepareForSegue method.
Create a global variable:
var selectedTitle = ""
In the action handlers set:
selectedTitle = action.title
Create a new property in your destination view controller:
var title = ""
And override prepareForSegue:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "insert your identifier here" {
if let vc = segue.destination as? YourDestinationViewController {
vc.title = selectedTitle
print("Title set in destination VC")
}
}
}
The callBack of the alertAction returns it
let copyOfVehicleShortCheck = UIAlertAction(title: "Copy of Vehicle Short Check", style: .default) { action in
print(action.title)
}
As #Sh_Khan mentioned, you can get title of action inside action handler.
Now you need to stored selected title and pass it to next controller, like that:
Save action title:
let copyOfVehicleShortCheck = UIAlertAction(
title: "Copy of Vehicle Short Check",
style: .default
) { action in
self.selectedActionTitle = action.title
self.performSegue(
withIdentifier: Constants.checklistInspectionIdentifier,
sender: self
)
}
Pass in prepareForSegue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let destination = segue.destination as? MyViewController {
destination.title = selectedActionTitle
}
}

Custom Barcode scanner, cannot pass back scanned data

I am having trouble passing back data that is scanned by my custom barcode scanner.
The data is read successfully and I am able to assign the value to a variable. But I cannot pass the data back to the previous view controller to populate a text view.
I am using this below to pass to my barcode VC to store the data inside it
var barcodeScanData: String = ""
I am using prepare for segue below to
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "BarcodeScanVC" {
let desitnationVC = segue.destination as! BarcodeScanVC
desitnationVC.xyz = barcodeScanData
}
}
Below here is where I am attempting to send back the data from my custom barcode scanner
var xyz: String = ""
func launchApp(barcodeScan: String) {
if presentedViewController != nil {
return
}
let alertPrompt = UIAlertController(title: "Barcode Found", message: "\(barcodeScan)", preferredStyle: .actionSheet)
let confirmAction = UIAlertAction(title: "Confirm", style: UIAlertAction.Style.default, handler: { (action) -> Void in
let barcodeData = PartsVCDetail()
self.xyz = barcodeScan
barcodeData.barcodeScanData = self.xyz
print(self.xyz, "This is what I am sending")
print(barcodeData.barcodeScanData, "This is what I am sending it TO" )
self.navigationController?.popViewController(animated: true)
})
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertAction.Style.cancel, handler: nil)
alertPrompt.addAction(confirmAction)
alertPrompt.addAction(cancelAction)
present(alertPrompt, animated: true, completion: nil)
}
The two print lines
print(self.waybill, "This is what I am sending")
print(barcodeData.barcodeScanData, "This is what I am sending it TO"
Show me the correct scan data, however, when I use the last line below:
self.navigationController?.popViewController(animated: true)
The data is lost and I see an empty value in my viewDidAppear on the first view controller:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
print(barcodeScanData, "This is empty but it shouldnt be")
dataFromBarcodeScanner.text = barcodeScanData
}
What am I missing ?
With this code let barcodeData = PartsVCDetail() you are creating a new instance of PartsVCDetail and then setting the property of that instance. As soon as the action ends this instance will be deallocated and you will return to the previous view controller via popViewController.
A common solution to your requirement is a delegation pattern.
You declare a protocol for your delegate to implement
You have the original view controller implement this delegate protocol
You have the original view controller set itself as the second view controller's delegate
The second view controller can invoke the delegate method to pass the data back
Protocol
protocol BarcodeScanDelegate {
func didScan(barcodeData: String)
}
PartsVCDetail
class PartsVCDetail: UIViewController, BarcodeScanDelegate {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let desitnationVC = segue.destination as? BarcodeScanVC {
desitnationVC.delegate = self
}
}
func didScan(barcodeData: String) {
self.barcodeScanData = barcodeData
}
}
BarcodeScanVC
var delegate: BarcodeScanDelegate?
func launchApp(barcodeScan: String) {
guard presentedViewController == nil else {
return
}
let alertPrompt = UIAlertController(title: "Barcode Found", message: "\(barcodeScan)", preferredStyle: .actionSheet)
let confirmAction = UIAlertAction(title: "Confirm", style: UIAlertAction.Style.default, handler: { (action) -> Void in
self.delegate?.didScan(barcodeData: self.xyz)
self.navigationController?.popViewController(animated: true)
})
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertAction.Style.cancel, handler: nil)
alertPrompt.addAction(confirmAction)
alertPrompt.addAction(cancelAction)
present(alertPrompt, animated: true, completion: nil)
}

unwindSegue could not pass data (Swift - Xcode)

I'm using UserDefaults to store and retrieve my data but I have no idea why when I perform an unwind segue, my userdefaults data could not be passed over to the next view controller but if i do a normal push segue, my userdefaults data could be seen in the next viewcontroller.
P.S: ONLY self.performSegue(withIdentifier: "unwindSegue", sender: nil) is the unwindSegue.
FirstViewController
#IBAction func Button1(_ sender: Any) {
var i: Int = 0
let randomNumber = arc4random_uniform(3) + 1
i = Int(randomNumber)
let alert = AlertController(title: "Congratualations", message: "You earned \(i) tokens!", preferredStyle: .alert)
alert.setTitleImage(UIImage(named: "token"))
// Add actions
alert.addAction(UIAlertAction(title: "Let's See!", style: UIAlertActionStyle.default, handler: { (action) in
var returnValue: Int = UserDefaults.standard.integer(forKey: "tokens")
returnValue = returnValue + i;
UserDefaults.standard.set(returnValue, forKey:"tokens")
self.performSegue(withIdentifier: "unwindSegue", sender: nil)
}))
if (returnValue != 30){
alert.addAction(UIAlertAction(title: "Continue Playing", style: UIAlertActionStyle.default, handler: { (action) in
var returnValue: Int = UserDefaults.standard.integer(forKey: "tokens")
returnValue = returnValue + i;
UserDefaults.standard.set(returnValue, forKey:"tokens")
self.performSegue(withIdentifier: "continue", sender: self)
}))
}
self.present(alert, animated: true, completion: nil)
}
SecondViewController
import UIKit
class TokenController: UIViewController {
#IBOutlet var tokens: UILabel!
#IBOutlet var minus1: UIButton!
#IBOutlet var minus2: UIButton!
var returnValue: Int = UserDefaults.standard.integer(forKey: "tokens")
override func viewDidLoad() {
super.viewDidLoad()
tokens.text = "x\(returnValue)"
}
#IBAction func unwindSegue(_ sender: UIStoryboardSegue) {
}
Because when you do a Push of a new ViewController, this is loaded into memory and it's method "ViewDidLoad" is called.
When you do an unwind segue , the previous ViewController is already in memory, so the viewDidLoad and all the initialization are not called and the labels and all the graphics are not updated.
This is not a problem, because you can access all the data you needed in the unwindSegue implementation through the variable sender. See this example:
 
func unwindToViewController(segue: UIStoryboardSegue) {
        let vc_source = segue.source as! SecondViewController
        self.myLabel.text! = vc_sorgente.myTextField.text!      
}
#Kinja Please refer this url to use unwind segue
Click here:- Perform action when segue is closed

Stop Segue and pass to next view the content of textfield shown in alert - Swift

I need to stop a segue transition and show alert with a textField.
But then, when I press "OK" button, I want to pass to the next view, the content of the textfield.
The problem is when I declare a view controller destination in prepareForSegue and I pass the text, because this is nil. I write my example:
override func shouldPerformSegueWithIdentifier(identifier: String?, sender: AnyObject?) -> Bool {
var shouldSegue:Bool = true
if identifier == "FirstToSecondView" {
var alert = UIAlertController(title: "End the First", message: "Are you sure you want to end the first?", preferredStyle: UIAlertControllerStyle.Alert)
alert.addTextFieldWithConfigurationHandler{ (textField) in
textField.placeHolder = "Name"
}
presentViewController(alert, animated: true, completion: nil)
var okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default) {
UIAlertAction in
println("OK Pressed")
let tf = alert.textFields?.First as? UITextField
//name is a declared variable above
if tf != nil {self.name = tf.text}
self.performSegueWithIdentifier("WorkoutToSummary", sender: self)
}
var cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel) {
UIAlertAction in
println("Cancel Pressed")
shouldSegue = false
}
alert.addAction(okAction)
alert.addAction(cancelAction)
}
return shouldSegue
}
And then in the prepareForSegue, I put that:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?){
var namePass: String = self.name
if segue.identifier == "FirstToSecondView" {
let secondViewController = segue.destinationViewController as SecondViewController
secondViewController.name = namePass
}
}
But at the moment that prepareForSegue is launched, self.name is nil
Thanks in advance!!
first you are to do is that set a tag for your alert as
alert.tag = 1
create a variable in your view controller as
class SBViewController : UIViewController{
//GlobalVariables
var demoText : String = String()
override func viewDidLoad(){
super.viewDidLoad()
}
}
the write a delegate method for your alert view and set you alert view delegate to self as
alert.delegate = self
var name : String = String()
func alertView(alertView: UIAlertView, clickedButtonAtIndex buttonIndex: Int) {
if alertView.tag == 20 {
if alertView.buttonTitleAtIndex(buttonIndex) == "OK"{
var textFeild : UITextField = alertView.textFieldAtIndex(0)!
if textFeild.text != "" {
name = textFeild.text
}
}
}

Resources