UIAlertController gone crazy, point to settings when it should cancel - xcode

Anyone ever had an alert controller with a "cancel" action and just a return in the handler that does something?
Mine goes to the app settings....
I have another alert controller in another viewcontroller that does that. But that shouldn't affect this one????
alertControl.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: { (alertAction) -> Void in
return
}))
update:
Commented all other alertController out. (They were all in other view controller) now it doesn't do it anymore. What is this??
These are also only declared in a function when something goes wrong. When there is no connection,... They shouldn't even exist, unless the function gets called.
update 2 :
func checkAllSettingsForLocation() {
if isTest != true {
//println("should show this")
let alertController = UIAlertController(title: "Scenix can't use your location", message: "Check Location Services under Privacy in the Settings App", preferredStyle: UIAlertControllerStyle.Alert)
let goToSettingsAction = UIAlertAction(title: "Go to Settings", style: .Default, handler: {
action in
UIApplication.sharedApplication().openURL(NSURL(string:UIApplicationOpenSettingsURLString)!)
return
}
)
alertController.addAction(goToSettingsAction)
let ignoreNoCamAction = UIAlertAction(title: "Cancel", style: .Default, handler: {
action in
self.launch = self.launch - 1
return
}
)
alertController.addAction(ignoreNoCamAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
}
Update 3:
Looks more and more like an Xcode Bug.
Building for release / through test flight and the bug is there.
Do a normal debug build and all is fine....
dirty fix =>
Wrap the action from any alert controller in an if statement that checks the alert controller title. Can never throw an exception or result in finding a nil and fixed my problem.

Try using nil instead of return,
let cancel = UIAlertAction(title: "Ok", style: .Cancel, handler: nil)
alertController.addAction(cancel)
I also have some other setting destination alert controllers, and this has worked fine for me.

Related

Attempt to present alertcontroller whose view is not in window hierarchy

I'm getting the following error in Swift 3:
Attempt to present alertcontroller whose view is not in window hierarchy
I have already referred to other posts on this topic to no avail. More specifically, I've implemented the change suggested in this post: AlertController is not in the window hierarchy
and I'm still receiving the same error.
What I've done is:
Create an AlertHelper.swift helper class:
class AlertHelper {
func showAlert(fromController controller: UIViewController) {
let alert = UIAlertController(title: "Please Try Again", message: "Email Already In Use", preferredStyle: .alert)
controller.present(alert, animated: true, completion: nil)
}
}
In my View Controller, under a function which is called when a button is pressed, I check to see if an email address entered by a user is already stored in my Firebase database, and if so, I try to present an "Email already in use" alert from the AlertHelper class:
Auth.auth().createUser(withEmail: email, password: password) { (user, error) in
if error != nil {
if let errCode = AuthErrorCode(rawValue: error!._code) {
switch errCode {
case .emailAlreadyInUse:
let alert = AlertHelper()
alert.showAlert(fromController: self)
return
default:
print("other error")
}
}
}
else {
// Inputs user email into database
self.ref.child("Users").child((user?.uid)!).setValue(["Email": email, "Location": ""])
self.performSegue(withIdentifier: "todorm", sender: self)
}
}
The database stuff works, the only thing that isn't appearing is the alert. Any ideas? Thanks!!
It's sort of a strange practice to subclass your alert into a separate class.
You should try making a method in your ViewController class
func showAlert() {
let alert = UIAlertController(title: "Please Try Again", message: "Email Already In Use", preferredStyle: .alert)
self.present(alert, animated: true, completion: nil)
}
Call the method using:
self.showAlert()

How to know if user rejected the Location Services in Swift 2

I'm trying to make location service app and i have the following code so when the user goes to that view controller he will get an alert of getting the current location.
This is the code
override func viewDidLoad() {
super.viewDidLoad()
// 1. status is not determined
if CLLocationManager.authorizationStatus() == .NotDetermined {
locationManager.requestAlwaysAuthorization()
}
// 2. authorization were denied
else if CLLocationManager.authorizationStatus() == .Denied {
SwiftSpinner.hide()
let alert = UIAlertController(title: "Error with Your Location" , message: "Location services were previously denied. Please enable location services for this app in Settings.", preferredStyle: UIAlertControllerStyle.Alert)
let ok = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default) {
UIAlertAction in
UIApplication.sharedApplication().openURL(NSURL(string: UIApplicationOpenSettingsURLString)!)
}
alert.addAction(ok)
let cancel = UIAlertAction(title: "Back", style: UIAlertActionStyle.Default) {
UIAlertAction in
self.movenav("arxiki")
}
alert.addAction(cancel)
self.presentViewController(alert, animated: true, completion: nil)
}
// 3. we do have authorization
else if CLLocationManager.authorizationStatus() == .AuthorizedAlways {
locationManager.startUpdatingLocation()
}
self.navigationController?.setNavigationBarHidden(false, animated: true)
self.eventsTable.backgroundColor = UIColor.lightGrayColor()
// self.locationManager.requestAlwaysAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
}
My question is the following.
If the user pushes "Do not authorise" How can i get his option so i can send him back to the previous view controller or to alert him with the message that i have?
In order to catch the user selection you need to declare a CLLocationManager object and implement its delegate (CLLocationManagerDelegate) and use the following method for catching it.
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if status == .Denied || status == .NotDetermined{
// User selected Not authorized
}
}
I assume you have already configured the info.plist with the suitable locations parameters.
Hope it helps!

Swift 2/Xcode 7: unrecognized selector sent to instance

My function is this and it is called with a "done" UIBarButtonItem.
#IBAction func done(sender: UIBarButtonItem) {
dismissViewControllerAnimated(true, completion: nil)
}
I have read multiple other questions/answers about a deleted instance or an old/extra connection in the Interface Builder or in the View Controller code. However, I only have this one function all properly connected without any extra lingering connections. How do I get rid of the "unrecognized selector sent to instance" error
Thanks in advance!
With the information provided in the question I suspect
There is unwanted connection left. To see that you can do:
1) Go to the IB and select the button.
2) Right click on the button and see all the actions. If you see any unwanted action delete it and try running again.
You can also do it programmatically
Set the target for UIBarButtonItem like this
var b = UIBarButtonItem(
title: "Continue",
style: .Plain,
target: self,
action: "sayHello:"
)
func sayHello(sender: UIBarButtonItem) {
}
If you dont want any parameters in the sayHello function, you can do it
var b = UIBarButtonItem(
title: "Continue",
style: .Plain,
target: self,
action: "sayHello"// Remove the colon
)
func sayHello() {
}
Let me know if it works for you

Do something on button click inside of footer in a tableView

I have a tableView that has a header, a footer and a prototype cell for dynamic purposes. I have a Sign Out button in the footer but can't figure out how to get it linked up with a function. I setup a segue to go back to a login page but I want an alert box to ask for confirmation first so I need to somehow call a function.
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerCell = tableView.dequeueReusableCellWithIdentifier("Footer") as! MenuTableViewCell
footerCell.logout.targetForAction("logOutButtonClicked", withSender: self)
return footerCell
}
This is what I have now, but upon click it crashes and gives me
'NSInvalidArgumentException', reason: '-[.MenuTableViewCell logOutButtonClick:]: unrecognized selector sent to instance 0x7ffce28615d0'
I have a function called logOutButtonClicked that looks like this...
func logOutButtonClicked(){
let alertView = UIAlertController(title: "Log Out?", message: "Are you sure you want to Log Out?", preferredStyle: .Alert)
alertView.addAction(UIAlertAction(title: "Cancel", style: .Default, handler: nil))
alertView.addAction(UIAlertAction(title: "Log Out", style: .Default, handler: {(alertAction) -> Void in
self.logOut()}))
presentViewController(alertView, animated: true, completion: nil)
}
func logOut(){
performSegueWithIdentifier("goHome", sender: self)
}
Edit:
I've also tried footerCell.logout.addTarget(self, action: "logOutButtonClicked", forControlEvents: .TouchUpInside)
but that gives the same error as well.
You have to create a function called "logOutButtonClicked" since you specified by adding the targetForAction, it would look something like this:
func logOutButtonClicked() {
}
I managed to fix this problem by erasing all of the events and outlets corresponding to the button (the ones you find when you right click on it) and then rewriting the function like so...
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerCell = tableView.dequeueReusableCellWithIdentifier("Footer") as! MenuTableViewCell
footerCell.logout.addTarget(self, action: "logOutButtonClicked", forControlEvents: .TouchUpInside)
return footerCell
}

Swift - UIAlertAction - could not find member named Default?

I'm trying to add an action sheet. From what I have read, UIActionSheet is depreciated in IOS 8, and one should use an Alert Controller instead. Here is my code snippet:
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .ActionSheet)
let takePhoto = UIAlertAction(title: "Take Photo", style: .Default, handler: { (alert: UIAlertAction) -> Void in
//action goes here
})
However. I am getting an error which reads "Could not find member 'Default'". From what I understand it there are 3 styles possible for UIAlertAction: Default, Cancel & Destructive. What am I doing wrong?
Many thanks :)
The problem is actually with the closure, rather than with .Default, but that's what the compiler is complaining about. The type on alert is incorrect (just barely). You can change the closure definition to one of these to make it work:
... handler: { (alert: UIAlertAction!) -> Void in
... handler: { alert -> Void in
... handler: { _ -> Void in //Use this if you don't care about the alert object
Shameless plug: You could also use something like LKAlertController to make the action sheet creation really easy. It would turn into something like
ActionSheet().addAction(title: "Take Photo", style: .Default) {
//Action
}.addAction(/* Your other actions */).show()
This compiles but you have more to do like add the .addAction, etc.. Note that the preferred style in optionMenu is .Alert. There is an excellent explanation in IOS 8 Swift Cookbook by Vandad Nahavandipoor
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .Alert)
let takePhoto = UIAlertAction(title: "Take Photo",
style: UIAlertActionStyle.Default,
handler: {[weak self] (paramAction:UIAlertAction!) in
})

Resources