Open iOS Email app through UIAlertView button - ios

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

Related

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

Show UIAlert before unwinding segue

I'm trying to fire an alert that asks if you want to save or delete a draft after pressing cancel. I'm quite close, but I can't seem to get it right.
I'm unwinding from 'ReplyMailViewController'(ViewController A) to 'MailContentViewController'(ViewController B).
I added the following code in ViewController A to show the alert and 'hold' the segue perform:
override func shouldPerformSegue(withIdentifier identifier: String?, sender: Any?) -> Bool {
if let ident = identifier {
if ident == "cancelDraft" {
let saveDraftActionHandler = { (action:UIAlertAction!) -> Void in
NSLog("EXIT")
}
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let deleteDraftAction = UIAlertAction(title: "Delete Draft", style: .destructive, handler: nil)
alertController.addAction(deleteDraftAction)
let saveDraftAction = UIAlertAction(title: "Save Draft", style: .default, handler: saveDraftActionHandler)
alertController.addAction(saveDraftAction)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertController.addAction(cancelAction)
present(alertController, animated: true, completion: nil)
return false
}
}
return true
}
The segue holds with this code, but the issue is that I can't figure out how to continue the unwind segue after pressing 'Save Draft' for example.
I also have an unwind function in View Controller B, but I can't seem to figure out how I can use this one for this task:
#IBAction func cancelToMailContentViewController(_ segue: UIStoryboardSegue) {
}
Instead of perform the segue directly you need to show your UIAlertViewController first and according to the user response execute your segue or not
#IBAction func showAlertViewController(){
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let replyAction = UIAlertAction(title: "Delete Draft", style: .destructive, handler: nil)
let replyAllAction = UIAlertAction(title: "Save Draft", style: .default) { (action) in
//Do whatever you need here
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (action) in
self.performSegue(withIdentifier: "cancelDraft", sender: action) //executing the segue on cancel
}
alertController.addAction(replyAllAction)
alertController.addAction(replyAction)
alertController.addAction(cancelAction)
present(alertController, animated: true, completion: nil)
}
After this you only need to change the unwind segue action to execute this method, and your segue will be executed if you press cancel in the UIAlertViewController via self.performSegue(withIdentifier: #<SegueIdentifier>, sender: #<sender>)
First, make the alert with two options:
class ViewController: UIViewController {
#IBAction func showAlertButtonTapped(_ sender: UIButton) {
// create the alert
let alert = UIAlertController(title: "UIAlertController", message: "Save this work?", preferredStyle: UIAlertControllerStyle.alert)
// add the actions (buttons)
alert.addAction(UIAlertAction(title: "Hell Yeah", style: UIAlertActionStyle.default, handler: nil))
alert.addAction(UIAlertAction(title: "Hell No", style: UIAlertActionStyle.cancel, handler: nil))
// show the alert
self.present(alert, animated: true, completion: nil)
}
After this, you have to make the segue and then name it (also connect it by control dragging from the view controller yellow icon to the other view controller):
After that put this your code to execute the segue:
self.performSegue(withIdentifier: ":)", sender: self)
After that you are going to execute the segue when the user responds to the alert:
if buttonTitle == "Hell Yeah" {
elf.performSegue(withIdentifier: ":)", sender: self)
}
so, in the end, your code should look like this:
class ViewController: UIViewController {
#IBAction func showAlertButtonTapped(_ sender: UIButton) {
// create the alert
let alert = UIAlertController(title: "UIAlertController", message: "Save this work?", preferredStyle: UIAlertControllerStyle.alert)
// add the actions (buttons)
alert.addAction(UIAlertAction(title: "Hell Yeah", style: UIAlertActionStyle.default, handler: nil))
alert.addAction(UIAlertAction(title: "Hell No", style: UIAlertActionStyle.cancel, handler: nil))
// show the alert
self.present(alert, animated: true, completion: nil)
if buttonTitle == "Hell Yeah" {
self.performSegue(withIdentifier: ":)", sender: self)
}
}
}

How to create uialertcontroller in global swift

I'm trying to create uialertcontroller in Config.swift file as follow.
static func showAlertMessage(titleStr:String, messageStr:String) -> Void {
let window : UIWindow?
let alert = UIAlertController(title: titleStr, message: messageStr, preferredStyle: UIAlertControllerStyle.Alert);
self.window!.presentViewController(alert, animated: true, completion: nil)
}
problem is I've found problem in self.window!.
Type 'Config' has no member 'window'
Please let me know how to solve that issue.
swift
Here's what I used, this is the same as #penatheboss answered, just add the ability of adding actions and handlers.
extension UIViewController {
func popupAlert(title: String?, message: String?, actionTitles:[String?], actions:[((UIAlertAction) -> Void)?]) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
for (index, title) in actionTitles.enumerated() {
let action = UIAlertAction(title: title, style: .default, handler: actions[index])
alert.addAction(action)
}
self.present(alert, animated: true, completion: nil)
}
}
Just make sure actionTitles and actions array the same count. Pass nil if you don't need any action handler closure.
self.popupAlert(title: "Title", message: " Oops, xxxx ", actionTitles: ["Option1","Option2","Option3"], actions:[{action1 in
},{action2 in
}, nil])
Objective C:
Add the category for UIViewController
UIViewController+PopAlert.h
#import <UIKit/UIKit.h>
#interface UIViewController (UIViewControllerCategory)
- (void) popAlertWithTitle: (NSString*) title message: (NSString*) message actionTitles:(NSArray *) actionTitles actions:(NSArray*)actions;
#end
UIViewController+PopAlert.m
#import "UIViewController+PopAlert.h"
#implementation UIViewController (UIViewControllerCategory)
- (void) popAlertWithTitle: (NSString*) title message: (NSString*) message actionTitles:(NSArray *) actionTitles actions:(NSArray*)actions {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
[actionTitles enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
UIAlertAction *action = [UIAlertAction actionWithTitle:obj style:UIAlertActionStyleDefault handler:actions[idx]];
[alert addAction:action];
}];
[self presentViewController:alert animated:YES completion:nil];
}
#end
Usage:
#import UIViewController+PopAlert.h
...
[super viewDidDisappear:animated];
NSArray *actions = #[^(){NSLog(#"I am action1");}, ^(){NSLog(#"I am action2");}];
[self popAlertWithTitle:#"I am title" message:#"good" actionTitles:#[#"good1", #"good2"] actions:actions];
self.window would mean that there's a window object in this class, and it's not the case.
You would need to use your let window : UIWindow? with window?.presentViewController(alert, animated: true, completion: nil), but this won't help, since this window does not actually represent any existing window, and it's not a view controller anyway.
So I suggest you pass the actual view controller you'll be using to the method:
static func showAlertMessage(vc: UIViewController, titleStr:String, messageStr:String) -> Void {
let alert = UIAlertController(title: titleStr, message: messageStr, preferredStyle: UIAlertControllerStyle.Alert);
vc.presentViewController(alert, animated: true, completion: nil)
}
and you call it from a class where a UIViewController object is available.
Details
Swift 5.1, Xcode 11.3.1
Global UIAlertController With UIViewController Extension
extension UIViewController{
// Global Alert
// Define Your number of buttons, styles and completion
public func openAlert(title: String,
message: String,
alertStyle:UIAlertController.Style,
actionTitles:[String],
actionStyles:[UIAlertAction.Style],
actions: [((UIAlertAction) -> Void)]){
let alertController = UIAlertController(title: title, message: message, preferredStyle: alertStyle)
for(index, indexTitle) in actionTitles.enumerated(){
let action = UIAlertAction(title: indexTitle, style: actionStyles[index], handler: actions[index])
alertController.addAction(action)
}
self.present(alertController, animated: true)
}
}
Usage
Alert
self.openAlert(title: "alert",
message: "add your message",
alertStyle: .alert,
actionTitles: ["Okay", "Cancel"],
actionStyles: [.default, .cancel],
actions: [
{_ in
print("okay click")
},
{_ in
print("cancel click")
}
])
ActionSheet
self.openAlert(title: "actionsheet",
message: "add your message",
alertStyle: .actionSheet,
actionTitles: ["Okay", "Cancel"],
actionStyles: [.default, .cancel],
actions: [
{_ in
print("okay click")
},
{_ in
print("cancel click")
}
])
I suggest creating an extension:
extension UIViewController {
func showAlertMessage(titleStr:String, messageStr:String) {
let alert = UIAlertController(title: titleStr, message: messageStr, preferredStyle: UIAlertControllerStyle.Alert)
self.presentViewController(alert, animated: true, completion: nil)
}
}
You can try this, please add below code in AppDelegate.swift file.
static func showAlertView(vc : UIViewController, titleString : String , messageString: String) ->()
{
let alertView = UIAlertController(title: titleString, message: messageString, preferredStyle: .alert)
let alertAction = UIAlertAction(title: "ok", style: .cancel) { (alert) in
vc.dismiss(animated: true, completion: nil)
}
alertView.addAction(alertAction)
vc.present(alertView, animated: true, completion: nil)
}
and call showAlertView method from any viewcontroller
AppDelegate.showAlertView(vc: self, titleString: "testTitle", messageString: "test msg")
I am suggest you write this code, but if you really need, try this:
static func showAlertMessage(titleStr:String, messageStr:String) -> Void {
let alert = UIAlertController(title: titleStr, message: messageStr, preferredStyle: UIAlertControllerStyle.Alert);
if let viewController = UIApplication.sharedApplication().windows.first?.rootViewController as UIViewController? {
viewController.presentViewController(alert, animated: true, completion: nil)
}
}
At least it won't break down.
#Eric D better answer.
I created a alerMessage class .I can call any where in my application
//Common Alert Message Class
class AlertMessage {
internal static var alertMessageController:UIAlertController!
internal static func disPlayAlertMessage(titleMessage:String, alertMsg:String){
AlertMessage.alertMessageController = UIAlertController(title: titleMessage, message:
alertMsg, preferredStyle: UIAlertControllerStyle.Alert)
AlertMessage.alertMessageController.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default,handler: nil))
if let controller = UIApplication.sharedApplication().keyWindow?.rootViewController?.presentedViewController {
controller.presentViewController(AlertMessage.alertMessageController, animated: true, completion: nil)
}
else{
UIApplication.sharedApplication().delegate?.window!!.rootViewController?.presentViewController(AlertMessage.alertMessageController, animated: true, completion: nil)
}
return
}
}
Please refer the below GIT Example
https://github.com/amilaim/CommonAlertView
// ViewController.swift
// CommonAlertView
//
// Created by Amila Munasinghe on 4/25/17.
// Copyright © 2017 Developer Insight. All rights reserved.
//
import UIKit
class ViewController: UIViewController,AlertViewControllerDelegate {
#IBOutlet weak var AlertViewResultTextOutlet: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func ShowAlertAction(_ sender: Any) {
let alert = AlertViewController.sharedInstance
alert.delegate = self
alert.SubmitAlertView(viewController: self,title: "Developer Insight", message: "Please enter any text value")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func SubmitAlertViewResult(textValue : String) {
AlertViewResultTextOutlet.text = textValue
}
}
Common UIAlertViewController Implementation
import UIKit
protocol AlertViewControllerDelegate {
func SubmitAlertViewResult(textValue : String)
}
class AlertViewController {
static let sharedInstance = AlertViewController()
private init(){}
var delegate : AlertViewControllerDelegate?
func SubmitAlertView(viewController : UIViewController,title : String, message : String){
let alert = UIAlertController(title: title,
message: message,
preferredStyle: .alert)
// Submit button
let submitAction = UIAlertAction(title: "Submit", style: .default, handler: { (action) -> Void in
// Get 1st TextField's text
let textField = alert.textFields![0]
if(textField.text != "")
{
self.delegate?.SubmitAlertViewResult(textValue: textField.text!)
}
})
// Cancel button
let cancel = UIAlertAction(title: "Cancel", style: .destructive, handler: { (action) -> Void in })
// Add 1 textField and cutomize it
alert.addTextField { (textField: UITextField) in
textField.keyboardAppearance = .dark
textField.keyboardType = .default
textField.autocorrectionType = .default
textField.placeholder = "enter any text value"
textField.clearButtonMode = .whileEditing
}
// Add action buttons and present the Alert
alert.addAction(submitAction)
alert.addAction(cancel)
viewController.present(alert, animated: true, completion: nil)
}
}
What I'm using based on the solution by #William Hu:
func popup(caller:UIViewController, style:UIAlertControllerStyle? = UIAlertControllerStyle.alert,
title:String, message:String, buttonTexts:[String], buttonStyles:([UIAlertActionStyle?])? = nil,
handlers:[((UIAlertAction) -> Void)?], animated:Bool? = nil, completion: (() -> Void)? = nil) {
let alert = UIAlertController(title: title, message: message, preferredStyle: style!)
for i in 0..<buttonTexts.count {
alert.addAction(UIAlertAction(title: buttonTexts[i],
style: (buttonStyles == nil || i >= buttonStyles!.count || buttonStyles![i] == nil ?
UIAlertActionStyle.default : buttonStyles![i]!),
handler: (i >= handlers.count || handlers[i] == nil ? nil : handlers[i]!)))
}
caller.present(alert, animated: animated != nil ? animated! : true, completion: completion)
}
Single function gives Alert by default and can optionally be used for ActionSheet.
Arrays buttonTexts, buttonStyles and handlers can be of unequal sizes as per requirement.
Actions can be styled.
Animated can be specified.
Optional block can be specified to be executed when presentation finishes.
Usage:
popup(caller: self, style: UIAlertControllerStyle.alert,
title: "Title", message: "Message",
buttonTexts: ["Destructive", "Cancel", "OK"],
buttonStyles: [UIAlertActionStyle.destructive, UIAlertActionStyle.cancel],
handlers: [nil], animated: false)
You can use my Utility class created for Show Alert in Swift4. Its super easy to use just by writing single line of code:
Show Simple Alert
#IBAction func showDefaultAlert(_ sender: Any) {
Alert.showAlert(title:"Alert", message:"Default Alert")
}
Demo code link: https://github.com/smindia1988/EasyAlertInSwift4
If you want to present from AppDelegate windows you can use like this
UIApplication.sharedApplication().delegate?.window.rootViewController?.presentViewController(vc, animated: true, completion: nil)
This is also the way you can present on top of the View Controller available.
UIApplication.topViewController()?.present(alertViewController!, animated: true, completion: nil)

unwind segue in UIAlert not working

I am trying to present an alert to the user if they need to be logged in to access a feature but when I press the login button in the alert self.self.performSegueWithIdentifier("tryonToLogin", sender:self) does not appear to do anything.
LoginViewController
#IBAction func unwindToLogin(segue:UIStoryboardSegue){
}
UIAlert
#IBAction func goToGallery(sender: UIButton){
if(isLoggedIn){
performSegueWithIdentifier("ShowGallery", sender: sender)
}else{
showMessage("You must login to view access this feature", sender:sender)
}
}
func showMessage(popUpMessageText : String, sender:UIButton){
let messageTitle = "Error"
print("prepreform segue")
performSegueWithIdentifier("unwindToLogin", sender:sender)
let refreshAlert = UIAlertController(title: messageTitle, message: popUpMessageText, preferredStyle: UIAlertControllerStyle.Alert)
refreshAlert.addAction( UIAlertAction(title: "Login", style: .Default, handler: { (action: UIAlertAction!) in
print("Handle Login redirect logic here")
self.performSegueWithIdentifier("unwindToLogin", sender: self)
print("after Handle Login redirect logic here")
}))
refreshAlert.addAction(UIAlertAction(title: "Cancel", style: .Default, handler: { (action: UIAlertAction!) in
print("Handle Cancel logic here")
}))
presentViewController(refreshAlert, animated: true, completion: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
print("prepare for segue called")
self.camera = nil
}
There are no errors. it is getting called as if ii put in a id that does not exist i get the no segue with specified identifier found error message.
Does the UIAlert affect the calling of the performSegueWithIdentifier()
The following post uses this approach so I think it should work. what am i missing.
**IB Screenshots **
Edit
I have tried moving self.performSegueWithIdentifier("unwindToLogin", sender:self) to view did appear and it still is snot working.
The self inside the block is the UIAlertController, not the UIViewController. Create a weak reference to the UIViewController, and call the method on that object.
weak var weakSelf = self
let refreshAlert = UIAlertController(title: messageTitle, message: popUpMessageText, preferredStyle: UIAlertControllerStyle.Alert)
refreshAlert.addAction( UIAlertAction(title: "Login", style: .Default, handler: { (action: UIAlertAction!) in
print("Handle Login redirect logic here")
dispatch_async(dispatch_get_main_queue()) {
weakSelf?.performSegueWithIdentifier("unwindToLogin", sender:self)
}
}))
Seeing that you have not provide sufficient informations, I present you this 'solution'.
Create an extension of UIViewController in order to implement facility function to implement an alertView-
I suppose that you put your code on "viewDidLoad": you have to move code on "viewDidAppear".
please check what operation you do in prepareForSegue
I think this will be sufficient.
extension UIViewController {
/**
Show alert view with OK/Cancel button.
- parameter title: alert title
- parameter message: alert message
- parameter onOk: callback on ok button tapped
- parameter onCancel: callback on cancel button tapped
- returns: alert controller
*/
func showAlert(title title: String, message: String, onOk: (() -> ())?, onCancel: (() -> ())? = nil) -> UIAlertController {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)
let okAction = UIAlertAction(title: "Ok", style: .Default) { (alert: UIAlertAction!) -> Void in
onOk?()
}
let cancelAction = UIAlertAction(title: "Cancel"), style: .Default) { (alert: UIAlertAction!) -> Void in
onCancel?()
}
alertController.addAction(okAction)
alertController.addAction(cancelAction)
self.presentViewController(alertController, animated: true, completion: nil)
return alertController
}
}
class LoginViewController: UIViewController {
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let title = "Login"
let message = messageTitle
self.showAlert(title: title, message: message, onOk: { () -> () in
self.performSegueWithIdentifier("unwindToLogin", sender: self)
})
}
}

Swift 2: Email Cancel Button Stops Working After Second Try on a Table View

I'm using a table view that has a cell that says "Send Us Feedback." It opens up the email application with preset information to be sent. I can send the email and/or cancel it, but when I cancel it the first time, stay on the table view, tap the cell again to open the email, I can't cancel it again. It just stays on the email view.
Suggestions?
My code is below:
import UIKit
import MessageUI
class FeedbackViewController: UITableViewController, MFMailComposeViewControllerDelegate {
let mailComposerVC = MFMailComposeViewController()
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.section == 0 && indexPath.row == 0
{
let alertController = UIAlertController(title: "Rate Us", message: "\nAre you enjoying our app? Please rate us in the app store!\n\nElse if you know of ways we can make our app better, please send us feedback so we can improve the experience for you!\n\nThank you!\n\nTimmy Caish", preferredStyle: .Alert)
alertController.addAction(UIAlertAction(title: "Rate on iTunes", style: .Default, handler: {
(action: UIAlertAction!) -> Void in
UIApplication.sharedApplication().openURL((NSURL(string: "http://google.com")!))
print("Rate us alert button worked.")
print("Send to iTunes")
}))
alertController.addAction(UIAlertAction(title: "Send Us Feedback", style: .Default, handler: {
(action: UIAlertAction!) in
print("Rate Us feeback button worked.")
let mailComposeViewController = self.configureMailComposeViewController()
if MFMailComposeViewController.canSendMail()
{
self.presentViewController(mailComposeViewController, animated: true, completion: nil)
}
else
{
self.showSendMailErrorAlert()
}
}))
alertController.addAction(UIAlertAction(title: "Cancel", style: .Default, handler: { (action: UIAlertAction) in
print("Rate us cancel button worked.")
print("Rate us")
}))
presentViewController(alertController, animated: true, completion: nil)
}
if indexPath.section == 0 && indexPath.row == 1
{
let mailComposeViewController = configureMailComposeViewController()
if MFMailComposeViewController.canSendMail()
{
self.presentViewController(mailComposeViewController, animated: true, completion: nil)
}
else
{
self.showSendMailErrorAlert()
}
print("Send us feedback")
}
}
func configureMailComposeViewController() -> MFMailComposeViewController {
mailComposerVC.mailComposeDelegate = self
mailComposerVC.setToRecipients(["developer.timmy#gmail.com"])
mailComposerVC.setSubject("Weather Simplicity Feedback")
mailComposerVC.setMessageBody("Hello,\n\nI would like to share the following feedback...\n\n", isHTML: false)
return mailComposerVC
}
func showSendMailErrorAlert() {
let sendMailErrorAlert = UIAlertController(title: "Error", message: "Your device could not send the email. Check your email configurations and try again.", preferredStyle: UIAlertControllerStyle.Alert)
let okay = UIAlertAction(title: "Okay", style: UIAlertActionStyle.Default, handler: nil)
sendMailErrorAlert.addAction(okay)
self.presentViewController(sendMailErrorAlert, animated: true, completion: nil)
}
func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
switch result {
case MFMailComposeResultCancelled:
print("Cancelled mail")
break
case MFMailComposeResultSent:
print("Message sent")
break
default:
break
}
self.dismissViewControllerAnimated(true, completion: nil)
}
}
Try creating a new mailViewController only when you need it in didSelectRow rather than at the creation of the view controller. This will ensure it is clean each time and is not created unless needed and may fix the problem of the second cancel not working.

Resources