Adding prepareForSegue into UIAlertAction - ios

I would like to pass an array to another ViewController when pressing the "Next" button in the alertview.
userInformation += [userName, userGender, String(userAge), String(userHeight), String(userWeight)]
let alert = UIAlertController(title:"Confirmation", message: confirmationMessage, preferredStyle: UIAlertControllerStyle.Alert)
let confirmBtn : UIAlertAction = UIAlertAction(title: "Next", style: UIAlertActionStyle.Default, handler: {(action:UIAlertAction!)-> Void in
let vc = (self.storyboard?.instantiateViewControllerWithIdentifier("toPerInfo"))! as UIViewController
print(self.userInformation)
self.showDetailViewController(vc, sender: self)
})
let cancelBtn : UIAlertAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil)
alert.addAction(cancelBtn)
alert.addAction(confirmBtn)
self.presentViewController(alert, animated: true, completion: nil)
and here is the perpareForSegue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var destViewController: PersonalInformation = segue.destinationViewController as! PersonalInformation
var arrayToSegue: [String] = self.userInformation
destViewController.useInfo = arrayToSegue
}
I would like to put the perpareForSegue into the "next" button.
How should I modify my code..
I couldn't find other similar questions...

The method prepareForSegueis actually made to customize or pass data to the new view controller, as written in UIViewController documentation :
The default implementation of this method does nothing. Subclasses override this method and use it to configure the new view controller prior to it being displayed. The segue object contains information about the transition, including references to both view controllers that are involved.
If you really want to, you can push manually the PersonalInformation view controller:
let storyboard = UIStoryboard(name: "StoryboardName", bundle: nil)
let destVC = storyboard.instantiateViewControllerWithIdentifier("PersonalInformationId") as! PersonalInformation
var arrayToSegue: [String] = self.userInformation
destVC = arrayToSegue
// present or push, as you wish
presentViewController(destVC, animated: true, completion: nil)

Related

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

Controller being pushed twice on iPad screen

I am trying to segue to another controller by clicking on one of presented options on actionsheet. It works just fine on iPhone screens and it's being pushed to appropriate scenes, however issue occurs on iPad. I have been searching a lot for similar issue, but with no success.
#IBAction func actionSheet(_ sender: UIButton) {
let alert = UIAlertController(title: "Please select one of the options", message: nil, preferredStyle: .actionSheet)
let cancelActionButton = UIAlertAction(title: "Cancel", style: .cancel) { action -> Void in }
let recipeActionButton = UIAlertAction(title: "Get The Recipe", style: .default) { action in self.performSegue(withIdentifier: "GetRecipeID", sender: self) }
let facebookActionButton = UIAlertAction(title: "Login with Facebook", style: .default) { action in self.handleCustomFacebookLogin() }
//actions
alert.addAction(cancelActionButton)
alert.addAction(recipeActionButton)
alert.addAction(facebookActionButton)
// support ipad
if let popoverController = alert.popoverPresentationController {
popoverController.sourceView = sender
popoverController.sourceRect = sender.bounds
}
self.present(alert, animated: true, completion: nil)
}
This approach is also not working:
let viewController = UIStoryboard(name: "Detail", bundle: nil).instantiateViewController(withIdentifier: "DetailsVC") as! DetailsViewController
let recipeActionButton = UIAlertAction(title: "Get The Recipe", style: .default, handler: { action in
self.navigationController?.pushViewController(viewcontroller, animated: true)})
I am getting this warning in console when pushing from iPhone:
pushViewController:animated: called on <UINavigationController
0x7fd96a81f800> while an existing transition or presentation is
occurring; the navigation stack will not be updated.
This is not showing when I trigger action from iPad, but new controller is stacked on top.FirstController, SecondController
after clicking on getRecipe/Login button from previous screen.
You could try to perform the segue from another operation
OperationQueue.main.addOperation {
self.performSegue(withIdentifier: "GetRecipeID", sender: nil)
}

presentViewController() pops the view behind the last view

I'm trying to perform a transition to another UIViewController in another storyboard but the problem is that the view that I want to display pops behind the view where I'm from.
I know that because my app includes a Snapchat-like navigation between views, so I can drag the view to the left or the right and I can see the view behind.
Here is how I attempt to do that :
#IBAction func account(sender: UIButton) {
if self._isOnline {
self.pageController?.reverseViewControllerAnimated(true)
}
else {
let alertView = UIAlertController(title: "blablablabla", message: "blablablabla", preferredStyle: .Alert)
alertView.addAction(UIAlertAction(title: "No", style: .Cancel, handler: nil))
alertView.addAction(UIAlertAction(title: "Yes", style: .Default, handler: { (alertAction) -> Void in
let storyboard = UIStoryboard(name: "SignUpLogin", bundle: NSBundle.mainBundle())
let vc = storyboard.instantiateInitialViewController() as! UIViewController
self.presentViewController(vc, animated: false, completion: nil)
}))
presentViewController(alertView, animated: true, completion: nil)
}
}
With SignUpLogin that is the name of my second .storyboard file, here I'm in Heart.storyboard.
The action takes place in a UIAlertController, if the user press no, nothing append, if he press yes he's supposed to be redirected to the initial view of my SignUpLogin.storyboard file.
My problem come from the view at the bottom left corner. And if I use the code above in the view at the top right corner, that works ! Why ?
I have no idea of how I can do differently.
I've found the solution to my problem !
#IBAction func account(sender: UIButton) {
if self._isOnline {
self.pageController?.reverseViewControllerAnimated(true)
}
else {
let alertView = UIAlertController(title: Constants.LocalizedJoinOurBand, message: Constants.LocalizedNeedToCreatAnAccount, preferredStyle: .Alert)
alertView.addAction(UIAlertAction(title: Constants.LocalizedNo, style: .Cancel, handler: nil))
alertView.addAction(UIAlertAction(title: Constants.LocalizedYes, style: .Default, handler: { (alertAction) -> Void in
if let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate {
let storyboard = UIStoryboard(name: "SignUpLogin", bundle: NSBundle.mainBundle())
let vc = storyboard.instantiateInitialViewController() as! UIViewController
UIApplication.sharedApplication().keyWindow?.rootViewController = vc
}
}))
presentViewController(alertView, animated: true, completion: nil)
}
}
I don't know why in this case particularly but I have to directly set the rootViewController of my AppDelegate with this line :
UIApplication.sharedApplication().keyWindow?.rootViewController = vc

Adding arguments to UIAlertAction

I have 2 classes in separate files: lets call them NotificationManagement and NotificationReceiver
in my NotificationReceiver class i have the following code:
class NotificationReceiver: UIViewController{
//...
func showNotificationHandler(alert: UIAlertAction!) {
var storyboard : UIStoryboard = UIStoryboard(name: Constants.storyboardName, bundle: nil)
var vc : Article = storyboard.instantiateViewControllerWithIdentifier(Constants.articleVCTitle) as! Article
self.presentViewController(vc, animated: false, completion: nil)
}
func dismissNotificationHandler(alert: UIAlertAction!) {
Constants.articleAddress = ""
}
func showAlert(title:String, message:String) {
let alert = UIAlertController(title: title,
message: message, preferredStyle: .Alert)
let okAction = UIAlertAction(title: Messages.showMsg, style: .Default , handler: showNotificationHandler)
let dismissAction = UIAlertAction(title: Messages.discardMsg, style: .Cancel, handler: dismissNotificationHandler)
alert.addAction(dismissAction)
alert.addAction(okAction)
self.presentViewController(alert, animated: false, completion: nil)
}
//...
}
Now I want to put handling of this notification in NotificationManagement class instead the NotificationReceiver class. However if I do put it there i need something like that in the handler, to pass the information about current view controller:
func showNotificationHandler(alert: UIAlertAction!, currentViewController: UIViewController) {
var storyboard : UIStoryboard = UIStoryboard(name: Constants.storyboardName, bundle: nil)
var vc : Article = storyboard.instantiateViewControllerWithIdentifier(Constants.articleVCTitle) as! Article
currentViewController.presentViewController(vc, animated: false, completion: nil)
}
But then i cant compile and the errors are really misleading like the compiler cannot find style .Default (and its because i added arguments to the showNotificationHandler ). I would like to use the function in NotificationReceiver like this :
let notificationManagement = NotificationManagement()
notificationManagement.showAlert("title",message: "message")

Resources