Error when loading UIAlertController - swift2

I want to load an alert when internet connection is not available. The function for checking internet connection is ready but I cannot load the alert. So I just put the alert code in viewDidLoad without any conditions etc. and got this error:
Warning: Attempt to present UIAlertController: 0x12752d400 on x.ViewController: 0x127646f00 whose view is not in the window hierarchy!
Code:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Delegates
verificationCode.delegate = self
let alert = UIAlertController(title: "Oops!", message:"This feature isn't available right now", preferredStyle: .Alert)
let action = UIAlertAction(title: "OK", style: .Default) { _ in }
alert.addAction(action)
self.presentViewController(alert, animated: true) {}
if (!Util.isConnectedToNetwork()) {
self.isConnected = false
}
}
Could you tell me how to fix it?

The error tells you what has gone wrong.
You are trying to present a view controller in viewDidLoad except the view, although loaded, is not in any hierarchy. Try putting the code in the viewDidAppear method, which is called after the view appears on screen, and is in a view hierarchy.

Swift 4 Update
I think this could help you for your problem :
override func viewDidLoad() {
super.viewDidLoad()
verificationCode.delegate = self
let alert = UIAlertController(title: "Oops!", message:"This feature isn't available right now", preferredStyle: .alert)
let delete = UIAlertAction(title: "OK", style: .default) { (_) in }
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (_) in }
alert.addAction(cancelAction)
alert.addAction(delete)
alert.popoverPresentationController?.sourceView = sender as UIView
UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: true, completion: nil)
if (!Util.isConnectedToNetwork()) {
self.isConnected = false
}
}

Move the code to viewDidAppear from viewDidLoad
override func viewDidAppear(animated: Bool) {
// Delegates
verificationCode.delegate = self
let alert = UIAlertController(title: "Oops!", message:"This feature isn't available right now", preferredStyle: .Alert)
let action = UIAlertAction(title: "OK", style: .Default) { _ in }
alert.addAction(action)
self.presentViewController(alert, animated: true) {}
if (!Util.isConnectedToNetwork()) {
self.isConnected = false
}
}

Related

Alert message button, with restrictions to go further to next viewcontroller

Hello I am making a ViewController with a PickerView that has age restrictions. I made it with the alert and age restrictions but I need it to deny access to next ViewController if the user isn't old enough.
Made my code like this, I guess its in the Else true I need some more code, but I'm not sure tho. I hope a kind soul can help me :)
#IBAction func verificerKnap(sender: AnyObject) {
// Creating the age restriction for the datepicker
let dateOfBirth = datoPicker.date
let today = NSDate()
let gregorian = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
let age = gregorian.components([.Year], fromDate: dateOfBirth, toDate: today, options: [])
if age.year < 18 {
// Alert controller som sender en advarsel hvis personen er under 18år
let alertController = UIAlertController(title: "Age restriction", message:
"This app requires an age of 18+", preferredStyle: UIAlertControllerStyle.Alert)
alertController.addAction(UIAlertAction(title: "Okay", style: UIAlertActionStyle.Default,handler: nil))
self.presentViewController(alertController, animated: true, completion: nil)
} else {
true
You can present an UIAlertController which asks if you are 18 years or older. Than link 2 buttons "Ok" and "Cancel" and add delegates for those:
let alertController = UIAlertController(title: "Default Style", message: "Are you 18 years or older?", preferredStyle: .Alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) {
(action) in
print("User is not yet >18")
}
alertController.addAction(cancelAction)
let OKAction = UIAlertAction(title: "OK", style: .Default) {
(action) in
dispatch_async(dispatch_get_main_queue(), {
self.presentViewController(desired_view_controller, animated: true, completion: nil)
})
}
alertController.addAction(OKAction)
self.presentViewController(alertController, animated: true) {
// ...
}
based on: http://nshipster.com/uialertcontroller/

My function in my main view controller is not working

I´m trying to use a function that I wrote in my main viewController, this is it.
func displayAlert(title: String, message: String)
{
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction((UIAlertAction(title: "Ok", style: .Default, handler:
{ (action) -> Void in
self .dismissViewControllerAnimated(true, completion: nil)
})))
self.presentViewController(alert, animated: true, completion: nil)
}
I´m trying to use it on other viewController call viewControllerRegistro, for some reason is not working. this is it...
#IBAction func signUp(sender: AnyObject)
{
//checar que el usuario copero al poner su correo electronico y su contraseña
if usernameRegistro.text == "" || correoRegistro.text == "" || contraseñaRegistro.text == ""
{
ViewController().displayAlert("Informando Error", message: "Porfavor completa los cuadros de registro")
}
any help?
I´m using xcode 7.0 beta 6 with swift 2
ViewController() creates a new ViewController instance. That view controller is not part of your view hierarchy (because you just created it, without adding it anywhere).
You have to call that method on the view controller that is currently visible. Because of that the function should not be part of your MainViewController class. It should be part of the ViewController class that needs it. Or if you need it in multiple view classes you could add the function to an extension of UIViewController:
extension UIViewController {
func displayAlert(title: String, message: String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction((UIAlertAction(title: "Ok", style: .Default, handler:
{ (action) -> Void in
self .dismissViewControllerAnimated(true, completion: nil)
})))
presentViewController(alert, animated: true, completion: nil)
}
}
With this extension you can call displayAlert on any UIViewController and UIViewController subclasses.

Error alert in uipickerview options

I'm working in these lines trying to show an "Error" message if the user forgot to fill the username label or choose an option from the PickerView ("-- Choose an option please --"), but, when I run this, it takes also the other options from the picker view as an error.
If the user choose A,B,C,D it's okay. I just want to define the first one ("-- Choose an option please --") as an error, but it doesn't works.
class ViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {
let userRole:[String] = ["-- Choose an option please --", "A", "B", "C", "D"]
var selectedOption:String?
#IBOutlet weak var usernameLabel: UITextField!
#IBOutlet weak var pickerRoleLabel: UIPickerView!
#IBAction func continueButton(sender: AnyObject) {
if usernameLabel.text == "" || userRole[0] == "-- Choose an option please --" {
let alert = UIAlertController(title: "Error in form", message: "Please fill the information", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Okay", style: .Default, handler: { (action) -> Void in
self.dismissViewControllerAnimated(true, completion: nil)
}))
self.presentViewController(alert, animated: true, completion: nil)
}
}
How can I improve this?
Thanks in advance!
You could always ensure your "-- Choose an option please --" string as first item. So you can just test if the value of the desired component with UIPickerView´s selectedRowInComponent method is bigger than "0".
If "0" is returned from this method, means your first position is selected, but if you receive "-1", no value was selected in your picker. Any value bigger than "0" you can considerate as a valid value.
selectedRowInComponent(_ component: Int)
#IBAction func continueButton(sender: AnyObject) {
//If you
if usernameLabel.text == "" || myPickerView.selectedRowInComponent(0) < 1 {
let alert = UIAlertController(title: "Error in form", message: "Please fill the information", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Okay", style: .Default, handler: { (action) -> Void in
self.dismissViewControllerAnimated(true, completion: nil)
}))
self.presentViewController(alert, animated: true, completion: nil)
}
}

waits until the user finishes responding to the popup dialog in Swift

I want the user to type up the text in the pop up dialog, but I want the program to wait until the user finished writing the text in the pop up dialog
Use UIAlertController:
let alertController = UIAlertController(title: "title", message: nil, preferredStyle: .Alert)
alertController.addTextFieldWithConfigurationHandler { (textField) -> Void in }
alertController.addAction(UIAlertAction(title: "cancel", style: UIAlertActionStyle.Cancel, handler: nil))
logInAlertController.addAction(UIAlertAction(title: "go", style: UIAlertActionStyle.Default, handler: { (action) -> Void in }
Swift 4
It sounds like you are doing your completion handling when presenting the controller instead of when the user selects an alert action.
You'll want to try something like this:
import UIKit
class MyViewController: UIViewController
{
var someStringVariable:String = ""
func presentAnAlert()
{
let alert = UIAlertController(
title: "Title",
message: "Message",
preferredStyle: .actionSheet //choose which style you prefer
)
alert.addTextField()
{ (textField) in
//this is for configuring the text field the user will see
textField.borderStyle = UITextField.BorderStyle.bezel
}
alert.addAction(UIAlertAction(title: "OK", style: .default)
{ action in
//use this space to transfer any data
let textField = alert.textFields![0]
self.someStringVariable = textField.text ?? ""
})
self.present(alert, animated: true)
{
//this will run once the action of **presenting** the view
//is complete, rather than when the presented view has been
//dismissed
}
}
override viewDidLoad()
{
super.viewDidLoad()
self.presentAnAlert()
print(self.someStringVariable)
//prints whatever the user input before pressing the OK button
}
}
I hope that helped!

EXC_BAD_ACCESS crash on didSelectRowAtIndexPath

My application suddenly started crashing and after four hours I still can't figure out why. It worked perfectly last Friday and I haven't changed anything to the code since.
I have tried:
Stepping through code with breakpoints.
Adding an Exception Breakpoint.
Enabling Zombie objects.
Turning static analyser on.
None of these made me any wiser or pointed me to a more exact error message.
The crash happens when I select a cell. It then points to the AppDelegate with the message "Thread 1: EXC_BAD_ACCESS". Continueing the program execution does not give a more clear error message.
Some images of the error and my code can be seen below. I am really at a loss here so any help will be much appreciated.
Code:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
var dealer : DealerList
var alldealer : TotalDealerList
var id : String
if scAll.selectedSegmentIndex == 0
{
if scMatur.selectedSegmentIndex == 0
{
if (self.resultSearchController.active)
{
dealer = filtereddealers[indexPath.row]
}
else
{
dealer = dealers[indexPath.row]
}
}
else
{
if (self.resultSearchController.active)
{
dealer = filtereddealers[indexPath.row]
}
else
{
dealer = sorteddealers[indexPath.row]
}
}
//Create a message box with actions for the user.
let actionSheetController: UIAlertController = UIAlertController(title: "What to do with:", message: "'\(dealer.dlName)'?", preferredStyle: .ActionSheet)
let cancelAction: UIAlertAction = UIAlertAction(title: "Cancel", style: .Cancel) { action -> Void in
//Just dismiss the action sheet
}
//starts a phonecall to the selected dealer
let callAction: UIAlertAction = UIAlertAction(title: "Call", style: .Default) { action -> Void in
var phonenr = "0634563859"
let alert2 = UIAlertController(title: "Please confirm", message: "Call '\(dealer.dlName)' at \(phonenr)?", preferredStyle: UIAlertControllerStyle.Alert)
alert2.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.Default, handler: nil))
alert2.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.Default) { UIAlertAction in
self.callNumber(phonenr)
})
self.presentViewController(alert2, animated: true, completion: nil)
}
//action that opens the DealCustView. Pass data from this view to the next. ID is used in the next view.
let showcustomersAction: UIAlertAction = UIAlertAction(title: "Customers", style: .Default) { action -> Void in
let reportview = self.storyboard?.instantiateViewControllerWithIdentifier("dealcustList") as! DealCustView
reportview.id2 = dealer.dlSCode
reportview.sourceid = self.id
self.navigationController?.pushViewController(reportview, animated: true)
}
//add the actions to the messagebox
actionSheetController.addAction(cancelAction)
actionSheetController.addAction(showcustomersAction)
actionSheetController.addAction(callAction)
//present the messagebox
dispatch_async(dispatch_get_main_queue(), {
self.presentViewController(actionSheetController, animated: true, completion: nil)
})
}
else
{
if scMatur.selectedSegmentIndex == 0
{
if (self.resultSearchController.active)
{
alldealer = filteredalldealers[indexPath.row]
}
else
{
alldealer = alldealers[indexPath.row]
}
}
else
{
if (self.resultSearchController.active)
{
alldealer = filteredalldealers[indexPath.row]
}
else
{
alldealer = sortedalldealers[indexPath.row]
}
}
///
//Create a message box with actions for the user.
let actionSheetController: UIAlertController = UIAlertController(title: "What to do with:", message: "'\(alldealer.tdlName)'?", preferredStyle: .ActionSheet)
let cancelAction: UIAlertAction = UIAlertAction(title: "Cancel", style: .Cancel) { action -> Void in
//Just dismiss the action sheet
}
//starts a phonecall to the selected dealer
let callAction: UIAlertAction = UIAlertAction(title: "Call", style: .Default) { action -> Void in
var phonenr = "0634563859"
let alert2 = UIAlertController(title: "Please confirm", message: "Call '\(alldealer.tdlName)' at \(phonenr)?", preferredStyle: UIAlertControllerStyle.Alert)
alert2.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.Default, handler: nil))
alert2.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.Default) { UIAlertAction in
self.callNumber(phonenr)
})
self.presentViewController(alert2, animated: true, completion: nil)
}
//action that opens the DealCustView. Pass data from this view to the next. ID is used in the next view.
let showcustomersAction: UIAlertAction = UIAlertAction(title: "Customers", style: .Default) { action -> Void in
let reportview = self.storyboard?.instantiateViewControllerWithIdentifier("dealcustList") as! DealCustView
reportview.id2 = alldealer.tdlSCode
reportview.sourceid = self.id
self.navigationController?.pushViewController(reportview, animated: true)
}
//add the actions to the messagebox
actionSheetController.addAction(cancelAction)
actionSheetController.addAction(showcustomersAction)
actionSheetController.addAction(callAction)
//present the messagebox
dispatch_async(dispatch_get_main_queue(), {
self.presentViewController(actionSheetController, animated: true, completion: nil)
})
}
}
}

Resources