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
})
Related
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()
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
}
I am creating a rss reader in xcode using swift. I am follwing this tut https://www.youtube.com/watch?v=jootsUaCvAU but in the tut he doesnt go over adding multiple feeds of your own for the user. Their is a slide out menu, but their is only a "add feed" button that the user can add their own feed.I have taken that out, and have put other feeds names on the slide out menu using "feedNames.append()", but all i need now is that the feed will open up after the user hits one of the feed names on the slide out menu. I think i know where the code goes, but i dont know what to put. Here is the code, for the slide out menu with the items. The code still has the "Add feed" implemented but just ignore that, cuz i am going to take that out.
func sideBarDidSelectMenuButtonAtIndex(index: Int) {
if index == 0{ // ADD FEED BUTTON
let alert = UIAlertController(title: "Add new feed", message: "Enter feed name and URL", preferredStyle: UIAlertControllerStyle.Alert)
alert.addTextFieldWithConfigurationHandler({ (textField:UITextField!) -> Void in
textField.placeholder = "Feed name"
})
alert.addTextFieldWithConfigurationHandler({ (textField:UITextField!) -> Void in
textField.placeholder = "Feed URL"
})
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil))
alert.addAction(UIAlertAction(title: "Save", style: UIAlertActionStyle.Default, handler: { (alertAction:UIAlertAction!) -> Void in
let textFields = alert.textFields
let feedNameTextField = textFields?.first as UITextField
let feedURLTextField = textFields?.last as UITextField
if feedNameTextField.text != "" && feedURLTextField.text != "" {
let moc = SwiftCoreDataHelper.managedObjectContext()
let feed = SwiftCoreDataHelper.insertManagedObject(NSStringFromClass(Feed), managedObjectConect: moc) as Feed
feed.name = feedNameTextField.text
feed.url = feedURLTextField.text
SwiftCoreDataHelper.saveManagedObjectContext(moc)
self.loadSavedFeeds()
}
}))
So i'm sure, the code goes here, but i am not for sure what to put. Thanks for your help!
func sideBarDidSelectMenuButtonAtIndex(index: Int)
if index == 0{
let url = NSURL(string: "http://www.widadclub.tk/feed")
let feedParser = MWFeedParser(feedURL: url)
feedParser.delegate = self
feedParser.parse()
}
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.
I need to get the text from the text fields in my alert view when the Input button is pressed.
func inputMsg() {
var points = ""
var outOf = ""
var alertController = UIAlertController(title: "Input View", message: "Please Input Your Grade", preferredStyle: UIAlertControllerStyle.Alert)
let actionCancle = UIAlertAction(title: "Cancle", style: UIAlertActionStyle.Cancel) { ACTION in
println("Cacle")
}
let actionInput = UIAlertAction(title: "Input", style: UIAlertActionStyle.Default) { ACTION in
println("Input")
println(points)
println(outOf)
}
alertController.addAction(actionCancle)
alertController.addAction(actionInput)
alertController.addTextFieldWithConfigurationHandler({(txtField: UITextField!) in
txtField.placeholder = "I got"
txtField.keyboardType = UIKeyboardType.NumberPad
points = txtField.text
})
alertController.addTextFieldWithConfigurationHandler({(txtField: UITextField!) in
txtField.placeholder = "Out Of"
txtField.keyboardType = UIKeyboardType.NumberPad
outOf = txtField.text
})
presentViewController(alertController, animated: true, completion: nil)
}
As requested here is an implementation solution.
alertController.addAction(UIAlertAction(title: "Submit", style: UIAlertActionStyle.Default,handler: {
(alert: UIAlertAction!) in
if let textField = alertController.textFields?.first as? UITextField{
println(textField.text)
}
}))
As stated above, the alertController has a property called textFields. You can conditionally unwrap that property to safely access a text field if you have added one. In this case since there is only one text field I just did the unwrap using the first property. Hope it helps.
The UIAlertController has a textFields property. That's its text fields. Any of your handlers can examine it and thus can get the text from any of the text fields.