I have a local alert set to fire off at a predesignated time (30 seconds). What I want to do is fire off an alert at 20 seconds. This is my relevant appDelegate code:
func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) {
// Pass the "firing" event onto the notification manager
timerNotificationManager.timerFired()
if application.applicationState == .Active {
//let alert = UIAlertController(title: "NotifyTimely", message: "Your time is up", preferredStyle: .Alert)
// Handler for each of the actions
let actionAndDismiss = {
(action: String?) -> ((UIAlertAction!) -> ()) in
return {
_ in
self.timerNotificationManager.handleActionWithIdentifier(action)
self.window?.rootViewController?.dismissViewControllerAnimated(true, completion: nil)
}
}
/*
alert.addAction(UIAlertAction(title: "Dismiss", style: .Cancel, handler: actionAndDismiss(nil)))
alert.addAction(UIAlertAction(title: "Restart", style: .Default, handler: actionAndDismiss(restartTimerActionString)))
alert.addAction(UIAlertAction(title: "Snooze", style: .Destructive, handler: actionAndDismiss(snoozeTimerActionString)))
window?.rootViewController?.presentViewController(alert, animated: true, completion: nil)
*/
var ourAlert = UIAlertView(title: "Time Alert", message: "You have been active for 20 seconds!", delegate: nil, cancelButtonTitle: "Dismiss")
ourAlert.show()
self.finalAlert()
}
}
func finalAlert() {
let alert = UIAlertView()
alert.title = "Final Timer Alert"
alert.message = "You have been active for 20 seconds. Your ride is now being charged."
alert.addButtonWithTitle("OK")
alert.show()
}
Now I have seen this answer How can I use NSTimer in Swift?
But I don't want the finalAlert function to kick off immediately. I want it to fire off 10s after the initial alert. How do I get NSTimer to wait 10 seconds to fire the alert or is there a better way to wait?
wait 10 seconds
It's unclear to me what you think is wrong with the behavior of NSTimer, but in any case the simplest way to express the notion "do this, 10 seconds from now" is to use GCD's dispatch_after. And the easiest way to do that is as I encapsulate it here: dispatch_after - GCD in swift?
NSTimer is literally meant to not fire immediately. You start the timer with a time interval of when you want it to fire, I guess in your case 10 seconds.
//first parameter is a time interval in seconds target is self and selector is
//finalAlert, which means after 10 seconds it will call self.finalAlert
//userInfo is nil, because you aren't passing any additional info
//and repeats is false, because you only want the timer to run once.
let timer = NSTimer.scheduledTimerWithTimeInterval(10, target: self, selector: "finalAlert", userInfo: nil, repeats: false)
Related
Struggling with the following code:
var connected = false
while !connected {
let msg = "Press cancel"
let alert = UIAlertController(title: "Test", message: msg, preferredStyle: .alert)
let action = UIAlertAction(title: "Cancel", style: .default) { (action:UIAlertAction) in
connected = true
}
alert.addAction(action)
print ("Hello")
present(alert, animated: true, completion: nil)
}
The UIAlertController is never shown, "Hello" is printed over and over again
If I insert "connected = true" after the while clause then the UIAlertController is shown, but I'm not able to show it again by changing the action to "connected = false"
What am I doing wrong?
First of all, as mentioned in the comments, its not a good idea to present your alert controller continuously in a while loop. I believe your intended functionality is to display an alert whenever the connected variable becomes false.
To accomplish this use NotificationCenter to respond as follows:
In viewDidLoad:
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.displayAlert), name: NSNotification.Name(rawValue: "connectionDropped"), object: nil)
Add a willSet property observer to connected:
var connected: Bool! {
willSet {
if newValue == false && oldValue != false {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "connectionDropped"), object: nil)
}
}
}
Then whenever you set self.connected = false, you will run this method:
#objc func displayAlert() {
let msg = "Press cancel"
let alert = UIAlertController(title: "Test", message: msg, preferredStyle: .alert)
let action = UIAlertAction(title: "Cancel", style: .default) { (action:UIAlertAction) in
self.connected = true
}
alert.addAction(action)
print ("Hello")
present(alert, animated: true, completion: nil)
}
Just make sure you set connected after the view hierarchy has been loaded e.g in viewDidAppear.
Once you're done with the view you can then remove the observer:
deinit {
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "connectionDropped"), object: nil)
}
EDIT:
The functionality you need is provided with the Reachability framework, in particular with the reachabilityChanged notification. You can then call the displayAlert using a similar approach that I outlined above; this is documented on their README document.
The UIAlertController is never shown, "Hello" is printed over and over again
It is inappropriate to keep presenting the alert in an endless while loop, probably, it leads to facing "AlertController is not in the window hierarchy" issue.
If I insert "connected = true" after the while clause then the UIAlertController is shown, but I'm not able to show it again by
changing the action to "connected = false"
Of course you won't be able to show it again by default, the chunk of code is already been executed.
Solution:
Presenting the alert should be related to triggering a specific condition, not in a while loop.
For instance, if you are aiming to notify the user that the device is unconnected, You could use Reachability and observe reachabilityChanged to present the alert, for more details you could check the library - Example - notifications section.
I managed to solve it using a recursive call to the function:
func showDlg(){
ssid = getWiFiSsid() ?? "AAA"
ssid = ssid[ssid.startIndex..<ssid.index(ssid.startIndex, offsetBy: 2)]
if ssid != "GP" {
print ("SSID: " + ssid)
let msg = "\nNot connected to GoPro camera\n\nPlease connect to camera wireless network and revert\n "
alert = UIAlertController(title: "GoPro Golfswing Analyser", message: msg, preferredStyle: .alert)
let action = UIAlertAction(title: "Try again", style: .default) { (action:UIAlertAction) in
print("Testing network again")
self.showDlg()
}
alert.addAction(action)
let action1 = UIAlertAction(title: "Cancel", style: .default) { (action:UIAlertAction) in
print("Cancel - exiting")
}
alert.addAction(action1)
present(alert, animated: true, completion: nil)
} else{
print("Connected to GoPro")
}
}
I make call on button click. My code:
if let phoneCallURL:NSURL = NSURL(string: "tel://\(phoneNumber)") {
let application:UIApplication = UIApplication.shared
if (application.canOpenURL(phoneCallURL as URL)) {
application.openURL(phoneCallURL as URL);
}
else {
let alertController = UIAlertController(title: NSLocalizedString("CALL_C_TITLE", comment: "Call disallowed"), message: NSLocalizedString("CALL_C_DESC", comment: "This device cannot call"), preferredStyle: UIAlertControllerStyle.actionSheet)
alertController.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "OK"), style: UIAlertActionStyle.default, handler: nil))
self.present(alertController, animated: true, completion: nil)
}
}
This code work fine, but i want to run some code after user end call. How I can do this?
When the call is ended and your application regains focus, it will receive the UIApplicationDidBecomeActive (docs) notification. You can register your ViewController as an observer for this and respond accordingly.
Keep in mind that you will receive this notification for other event sequences too (returning from background, dismissing notifications, etc.), so you may want to set a flag when starting the call and check for that flag in the notification handler if you only want to run code after having made the call.
I have an alert that pops up when the user runs out of time. Right now it just vibrates but I also want it to play an alarm sound. Is there a way to play whatever the user has set as the system default alarm sound is? Also, is it possible to have the alarm keep going until the user clicks the dismiss button?
Here is my code so far:
func dismissAlert(alert:UIAlertAction!)
{
self.dismissViewControllerAnimated(true, completion: nil)
}
let outOfTimeAlert = UIAlertController(title: "Out Of Time", message: "Better luck next time", preferredStyle: UIAlertControllerStyle.Alert)
let cancelAlert: UIAlertAction = UIAlertAction(title: "Dismiss", style: .Cancel, handler: dismissAlert)
outOfTimeAlert.addAction(cancelAlert)
presentViewController(outOfTimeAlert, animated: true, completion: nil)
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate)
Thanks for the help!
I have the following code:
/// Creates Alerts on screen for user.
func notifyUser(title: String, message: String) -> Void
{
let alert = UIAlertController(title: title,
message: message,
preferredStyle: UIAlertControllerStyle.Alert)
let cancelAction = UIAlertAction(title: "OK",
style: .Cancel, handler: nil)
alert.addAction(cancelAction)
UIApplication.sharedApplication().keyWindow?.rootViewController!.presentViewController(alert, animated: true,
completion: nil)
}
Which shows the following Alert:
I would prefer the Alert to appear for maybe 1-2 seconds and auto dismiss without having to click ok or dismiss. Is this possible?
Yes it's completely possible, I think the #Duncan C approach will work very well and it's self explanatory, so I going to explain you in code the #Duncan approach and another approach is using delays with the Grand Central Dispatch(GCD).
First Approach: Using the NSTimer class
// set the UIAlerController property
var alert: UIAlertController!
func notifyUser(title: String, message: String, timeToDissapear: Int) -> Void
{
alert = UIAlertController(title: title,
message: message,
preferredStyle: UIAlertControllerStyle.Alert)
let cancelAction = UIAlertAction(title: "OK",
style: .Cancel, handler: nil)
alert.addAction(cancelAction)
UIApplication.sharedApplication().keyWindow?.rootViewController!.presentViewController(alert, animated: true,
completion: nil)
// setting the NSTimer to close the alert after timeToDissapear seconds.
_ = NSTimer.scheduledTimerWithTimeInterval(Double(timeToDissapear), target: self, selector: Selector("dismissAlert"), userInfo: nil, repeats: false)
}
Second Approach: Using GCD
// set the UIAlerController property
var alert: UIAlertController!
func notifyUser(title: String, message: String, timeToDissapear: Int) -> Void
{
alert = UIAlertController(title: title,
message: message,
preferredStyle: UIAlertControllerStyle.Alert)
let cancelAction = UIAlertAction(title: "OK",
style: .Cancel, handler: nil)
alert.addAction(cancelAction)
UIApplication.sharedApplication().keyWindow?.rootViewController!.presentViewController(alert, animated: true,
completion: nil)
// Delay the dismissal by timeToDissapear seconds
let delay = Double(timeToDissapear) * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(time, dispatch_get_main_queue()) { [weak self] in
self!.alert.dismissViewControllerAnimated(true, completion: nil)
}
}
And then you can call it in anywhere you want like in the following way :
self.notifyUser("Hello", message: "World", timeToDissapear: 3)
I hope this help you.
Here Is the code for Swift 4 Please Refer...Thank you
let alert = UIAlertController(title: "Success", message: "Record Updated Successfully", preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { action in
switch action.style{
case .default:
print("default")
case .cancel:
print("cancel")
case .destructive:
print("destructive")
}}))
self.present(alert, animated: true, completion: nil)
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
alert.dismiss(animated: true, completion: nil)
}
Sure. A UIAlertController is a special type of UIViewController. You're displaying it using presentViewController:animated:completion:. Just save a pointer to the UIAlertController into an instance variable, start a timer, and when the timer fires, call dismissViewControllerAnimated:completion:. You might want to get rid of the OK button action in that case, and if you leave the OK button you'll need to test and make sure your code works if you click OK before the timer fires.
Try this code:
var timer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: "dismissAlert", userInfo: nil, repeats: true)
func dismissAlert()
{
// Dismiss the alert from here
alert.dismissViewControllerAnimated(false, completion: nil)
}
I tried it and this worked fine. You can set the timer inside
scheduledTimerWithTimeInterval
where the current time is set to 5.0 seconds
func alert2 (_ dictKey: String){
if self.presentedViewController == nil {
let alertController = UIAlertController(title: nil, message: dictKey, preferredStyle: .alert )
alertController.addAction(UIAlertAction(title: "START AGAIN", style: UIAlertActionStyle.default, handler: {(action:UIAlertAction!) in self.returnToStart()}))
alertController.addAction(UIAlertAction(title: "REQUEST PIN", style: UIAlertActionStyle.default, handler:{(action:UIAlertAction!) in self.pinCreate()
self.dismiss(animated: false, completion: nil)//This dismisses the alert
}))
self.present(alertController, animated: true,completion: nil)
}
}
This proved to be a simple solution
func notifyUser(message: String) -> Void {
let alert = UIAlertController(title: "", message: message, preferredStyle: UIAlertController.Style.alert)
present(alert, animated: true, completion: nil)
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [unowned self] in
self.dismiss(animated: true)
}
}
To use:
notifyUser(message: "Image Saved")
I have an app that has a countdown timer. I want it to be such that the faster a user completes the game, the more points they get. For example, the total amount of time given is 120 seconds, so a user who completes the game in 60 seconds gets 120-60=60 points, and a person who finishes the game in 100 seconds gets 120-100=20 points.
Here is a sample of the code I am using to do my countdown timer.
func setupGame() {
seconds = 120
timerLabel.text = "Time: \(seconds)"
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("subtractTime"), userInfo: nil, repeats: true)
}
func subtractTime() {
seconds--
timerLabel.text = "Time: \(seconds)"
if(seconds == 0) {
timer.invalidate()
let alertController = UIAlertController(title: "You're Done!", message: "What would you like to do now?", preferredStyle: .Alert)
let shareAction = UIAlertAction(title: "Share", style: UIAlertActionStyle.Default) {
UIAlertAction in
NSLog("Share Pressed")
}
let okAction = UIAlertAction(title: "Continue", style: UIAlertActionStyle.Cancel) {
UIAlertAction in
NSLog("Continue Pressed")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("singleViewController") as UIViewController
self.presentViewController(vc, animated: true, completion: nil)
}
alertController.addAction(okAction)
alertController.addAction(shareAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
}
As you can see, when the timer reaches 0, an alert pops up. When this happens, since the time left is 0, I want the score this person gets to be 0 as well. (If you're wondering then how do people stop the game so that they will get a score that's not 0 - I also have a Done button that stops the timer earlier and shows a similar alert)
Now all I need is a way to capture when the timer was stopped, do the math of 120 - user's time left = score so that I can display it in a label on the next ViewController.
Please advise!
Assuming there's no "pause" function in your game, a simple solution would be to create a date when the game begins and then check for the number of seconds since that date whenever you want the time transpired.