Custom Barcode scanner, cannot pass back scanned data - ios

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

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

UIAlertAction actionsheet fetch data to childVC

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
}

segue and passing data from uialertcontroller

I've been trying to passing some data to model file to be used in another view controller by using pop-up alert after user tab the save button it suppose to trigger prepare function and unwind to tableview on another view controller.
#IBAction func saveButton(_ sender: UIBarButtonItem) {
saveFilesName()
}
Then,
func saveFilesName() {
let alert = UIAlertController(title: "Save As", message: "Please enter the file name", preferredStyle: .alert)
alert.addTextField(configurationHandler: {(nameField) -> Void in
nameField.placeholder = "Enter the file name"
nameField.textAlignment = .center
})
alert.addTextField(configurationHandler: {(descField) -> Void in
descField.placeholder = "Enter the your description"
descField.textAlignment = .center
})
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (actions: UIAlertAction) -> Void in
}))
alert.addAction(UIAlertAction(title: "Save", style: .default, handler: { (actions: UIAlertAction) -> Void in
let nameFieldData = alert.textFields![0]
let descFieldData = alert.textFields![1]
self.fileName = nameFieldData.text ?? ""
self.descData = descFieldData.text ?? ""
print(alert.textFields![0])
let saveCSV = self.saveCSVFiles()
print(saveCSV.lastPathComponent)
self.performSegue(withIdentifier: "unwindToCSVList", sender: self)
}))
self.present(alert, animated: true, completion: nil)
}
but after I tab the save button it unwind to the table view as intended but the prepare method always return The save button was not pressed, cancelling which mean the prepare method didn't being triggered properly
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if segue.identifier == "unwindToCSVList" {
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 nsurl = String(describing: csvFile)
let name = fileName ?? ""
let description = descData ?? ""
let photo = UIImage(contentsOfFile: "defaultImage")
let url = NSURL(fileURLWithPath: nsurl)
print("yeah")
csv = CSVData(name: name, description: description, photo: photo, url: url)
}
}
any suggestion would be appreciated

Open iOS Email app through UIAlertView button

I have a UIAlertView that is triggered via a UIButton.
The UIAlertView displays two buttons, "Open Email" and "Cancel".
"Cancel" removes the UIAlert from the view. I'm trying to make it so when the user taps "Open Email", their device opens the default email application's compose screen, with an email address already in the "sender" section.
Using Swift 3.
Thanks!
import UIKit
import Kingfisher
class SettingsViewController: UIViewController {
#IBAction func copyrightInfo(_ sender: Any) {
let alert = UIAlertController(title: "Copyright Info", message: "text", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "I understand", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
#IBAction func helpfeedbackAlert(_ sender: Any) {
let alertController = UIAlertController(title: "Help & Feedback", message: "text", preferredStyle: .alert)
let cancel = UIAlertAction(title: "Cancel", style: .destructive, handler: nil)
let openEmail = UIAlertAction(title: "Open Email", style: .default, handler: nil)
alertController.addAction(openEmail)
alertController.addAction(cancel)
self.present(alertController, animated: true, completion: nil)
}
#IBAction func clearCache(_ sender: Any) {
// SDImageCache.shared().clearMemory()
// SDImageCache.shared().clearDisk()
// Clear memory cache right away.
ImageCache.default.clearMemoryCache()
// Clear disk cache. This is an async operation.
ImageCache.default.clearDiskCache()
}
#IBAction func rateApp(_ sender: Any) {
if let url = URL(string: "https://www.google.com") {
if #available(iOS 10.0, *) {
UIApplication.shared.open(url, options: [:]) {
boolean in
// do something with the boolean
}
} else {
// Fallback on earlier versions
}
}
}
#IBAction func purchasePhotos(_ sender: Any) {
if let url = URL(string: "https://google.com") {
if #available(iOS 10.0, *) {
UIApplication.shared.open(url, options: [:]) {
boolean in
// do something with the boolean
}
} else {
// Fallback on earlier versions
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override var prefersStatusBarHidden: Bool {
get {
return true
}
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
You have to use MFMailComposer to send email, this is how you use it
if MFMailComposeViewController.canSendMail() {
let mail = MFMailComposeViewController()
mail.mailComposeDelegate = self
mail.setToRecipients(["rajatpagare#hotmail.com"])
mail.setMessageBody("you email body", isHTML: false)
present(mail, animated: true)
} else {
// email is not added in app
}
Also import MessageUI framework and conform to MFMailComposeViewControllerDelegate
Also you don't need to use openURL like you mentioned in your answer as you are redirecting user from your app to another app, there is no need to do that you can use MFMailComposer.
First, I assume what do you need to add in your code snippet is only this part:
#IBAction func helpfeedbackAlert(_ sender: Any) {
let alertController = UIAlertController(title: "Help & Feedback", message: "text", preferredStyle: .alert)
let cancel = UIAlertAction(title: "Cancel", style: .destructive, handler: nil)
let openEmail = UIAlertAction(title: "Open Email", style: .default, handler: nil)
alertController.addAction(openEmail)
alertController.addAction(cancel)
self.present(alertController, animated: true, completion: nil)
}
Anyway, what do you need is to fill the handler when you create an instance of the UIAlertAction. Referring to the documentation of the init(title:style:handler:):
handler
A block to execute when the user selects the action. This
block has no return value and takes the selected action object as its
only parameter.
So, your openEmail should be like:
let openEmail = UIAlertAction(title: "Open Email", style: .destructive, handler: { (actionSheetController) in
// send your email here...
})
I'm not pretty sure of the mechanism of how do you want to send an email, but I thik you might want to check MFMailComposeViewController, this question should help you to work with it.
Hope it helped.
I got it working with this code:
#IBAction func helpfeedbackAlert(_ sender: Any) {
let alertController = UIAlertController(title: "Help & Feedback", message: "text", preferredStyle: .alert)
let cancel = UIAlertAction(title: "Cancel", style: .destructive, handler: nil)
let openEmail = UIAlertAction(title: "Open Email", style: .default, handler: { (actionSheetController) -> Void in let email = "email#example.com"
let url = NSURL(string: "mailto:\("email#example.com")")
UIApplication.shared.openURL(url as! URL)})
alertController.addAction(openEmail)
alertController.addAction(cancel)
self.present(alertController, animated: true, completion: nil)
}

Adding prepareForSegue into UIAlertAction

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)

Resources