i am trying to make an alarm app by setting new local notifications every X seconds when a Set button is pressed and stopping when the user taps a Stop button.
using Timer(), i am currently able to set the local notification but it doesn't repeat as I would like. it only repeats when i go into the app and back to the previous screen via the Home button. also, it only repeats once by doing that.
is there any way to have the user press the Set button once and have the notifications keep firing no matter if you're in the app/outside the app and only stopping when the user presses the Stop button?
my code as follows:
class LocalNotificationViewController: UIViewController {
var timer = Timer()
func runTimer() {
timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: (#selector(self.setLocalNotification)), userInfo: nil, repeats: true)
}
#objc func setLocalNotification() {
// timeEntered = time.text!
// let hrMin = timeEntered.components(separatedBy: ":");
let content = UNMutableNotificationContent()
content.title = "Test Local Notification"
content.subtitle = "Testing..."
content.body = "Testing..."
content.badge = 1
content.sound = UNNotificationSound(named: "alarm.aiff");
trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false);
let request = UNNotificationRequest(identifier: "timerDone", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
var timeEntered: String = "";
var trigger: UNTimeIntervalNotificationTrigger? = nil;
#IBOutlet var time: UITextField!;
#IBAction func setNotification(_ sender: Any) {
runTimer()
}
#IBAction func stopRepeat(_ sender: Any) {
timer.invalidate()
}
Related
The code below works as follows:
If a "Like" button is pressed a pop up notification is displayed while the app is in the foreground
func ButtonPressed(index: Int, buttonName: String) {
print(buttonName)
if buttonName == "DisLike" {
guard let indexPath = CardsCollection.indexPathsForVisibleItems.first.flatMap({
IndexPath(item: index + 1, section: $0.section)
}), CardsCollection.cellForItem(at: indexPath) != nil else {
return
}
CardsCollection.scrollToItem(at: indexPath, at: .left, animated: true)
}
else {
showLocalNotification()
}
}
When the "dislike" button is pressed I want to hide any previous notifications that are still displayed because its default expiry time has not yet occurred.
Here’s the showNotification function
func showLocalNotification() {
// create notification content
let content = UNMutableNotificationContent()
content.title = "Image Got Liked!"
content.body = "Awsome You Like An Image!"
content.sound = UNNotificationSound.default
// triger the notification
let triger = UNTimeIntervalNotificationTrigger(timeInterval: 0.2, repeats: false)
// make a request for notification
let request = UNNotificationRequest(identifier: "Homyt", content: content, trigger: triger)
// make the request
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
I have a function with notification with the time interval trigger, which shows the notification once a minute
func addNotificationWithTimeIntervalTrigger(){
callApi()
let content = UNMutableNotificationContent()
print("PresentTitle",AppDelegate.titleNotification,"\(Date())")
content.title = AppDelegate.titleNotification
//content.subtitle = subTitle
//content.body = body
content.badge = 1
content.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 60, repeats:true)
let reguest = UNNotificationRequest(identifier: "identifier", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(reguest) { (error) in}
}
But it shows only one, the old value once a minute, although the data in API has already changed.
To see the new value, i need to press the button again, but I do not want that, i want to know how to rewrite this func that this (timeInterval: 60, repeats:true) includes callApi() or smth like that.
You can use NStimer for this .
var timer = NSTimer.scheduledTimerWithTimeInterval(60.0,
target: self,
selector: Selector("addNotificationWithTimeIntervalTrigger"),
userInfo: nil,
repeats: true)
I am working on a timer application that should terminate if the user leaves the app. I want a notification to be sent to the user when they leave the application. This notification WARNS the user that the timer will terminate if they do not return to the app immediately
I have look at UNNotficationTrigger's but not of what i have tried repeats the notification if the user is to be warned more than once.
How to i detect when the user is outside the application, then send a notification warning them to return to the app??
Thank you in advance
Code:
#IBAction func start(_ sender: Any) {
startTimer()
let content = UNMutableNotificationContent()
content.title = "WARNING: Return to 4ocus"
content.subtitle = ""
content.body = "Go back to 4ocus or risk losing 4ocus points"
content.badge = 1
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let request = UNNotificationRequest(identifier: "timerDone", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
#IBAction func start(_ sender: Any) {
startTimer()
let content = UNMutableNotificationContent()
content.title = "WARNING: Return to 4ocus"
content.subtitle = ""
content.body = "Go back to 4ocus or risk losing 4ocus points"
content.badge = 1
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let request = UNNotificationRequest(identifier: "timerDone", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
func applicationWillTerminate(_ application: UIApplication) {
let content = UNMutableNotificationContent()
//adding title, subtitle, body and badge
content.title = "Hey if you will not come back"
content.subtitle = "your timer will be killed"
content.body = ""
content.badge = 1
//getting the notification trigger
//it will be called after 5 seconds
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
//getting the notification request
let request = UNNotificationRequest(identifier: "SimplifiedIOSNotification", content: content, trigger: trigger)
//adding the notification to notification center
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
and also put the same code in willforeground method of appdelegate to get know if the user is about to leave application
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
put this method in your appdelegate and if there is alredy func applicationWillTerminate(_ application: UIApplication) is defined then put only code :)
i am working on simulating an alarm.
in order to do so, i am trying to send a new local notification every X seconds while some condition is true and stopping while some condition is false (when the user cancels the alarm)
i have a Set button and a Stop button.
the following code is for when the Set button is pressed:
#IBAction func setNotification(_ sender: Any) {
// timeEntered = time.text!
// let hrMin = timeEntered.components(separatedBy: ":");
let content = UNMutableNotificationContent()
content.title = "How many days are there in one year"
content.subtitle = "Do you know?"
content.body = "Do you really know?"
content.badge = 1
content.sound = UNNotificationSound(named: "alarm.aiff");
while (repeatNotifications) {
trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false);
let request = UNNotificationRequest(identifier: "timerDone", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
}
when the Stop button is pressed:
#IBAction func stopRepeat(_ sender: Any) {
repeatNotifications = false
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
UNUserNotificationCenter.current().removeAllDeliveredNotifications()
}
right now, when i press the Set button, it is stuck in pressed mode (its color changes) and i can't press anything else (i.e.: Stop button) besides the home button. also, no local notifications is being set.
any ideas how to accomplish this?
tl;dr: how to set new local notifications every X seconds until some button is pressed
Your while condition is running more quickly then you think. It might be chocking your notification class by creating number of objects. Please use a timer to run every 5 seconds to push a notification.
You can use Instruments Tool to see the problem.
I already know how to save things and I can automatically load them when opening the app. But I have no idea how to save them as it closes! I have a button for now. I am trying to save just one value, StreakNumber. However, whenever I try, I fail.
When in app delegate I try saying ViewController.AppSave(ViewController). I get an error:
Editor placeholder in source file
Expression resolves to an unused function
and if I use ViewController.AppSave()
I get the following error:
Instance member 'SaveApp' cannot be used on type 'ViewController'; did you mean to use a value of this type instead?
import UIKit
import UserNotifications
class ViewController: UIViewController {
//TEST PLAY AREA//
#IBAction func SaveButton(_ sender: Any) {
SaveApp()
}
#IBAction func LoadButton(_ sender: Any) {
LoadApp()
}
///TEST PLAY AREA ENDS
public var streakNumber = 0
public var streakNumberString = ""
public var activated = false
let defaults = UserDefaults.standard
//Labels
#IBOutlet var streakNumberLabel: UILabel!
#IBOutlet var remainingTimeTextLabel: UILabel!
#IBOutlet var remainingTimeNumberLabel: UILabel!
//Buttons
#IBAction func startButton(_ sender: Any) {
Activate()
}
#IBAction func stopButton(_ sender: Any) {
Deactivate()
seconds = 59
minutes = 59
hours = 47
}
//Timer
var timer = Timer()
var seconds = 0
var minutes = 0
var hours = 0
// Nitifications
//END
override func viewDidLoad() {
super.viewDidLoad()
LoadApp()
// this enables notifications
UNUserNotificationCenter.current().requestAuthorization(options:[.alert , .sound , .badge], completionHandler:{ didAllow, error in
})
}
func Activate (){
if activated == false {
streakNumber += 1
}
activated = true
streakNumberLabel.text = String(streakNumber)
}
func Deactivate (){
if activated == true{
activated = false
ActivTimer()
// Notification
let content = UNMutableNotificationContent()
content.title = " 10 secodns are up "
content.subtitle = " yep time passed"
content.body = " The 10 seconds are really up!!"
content.badge = 1
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 600, repeats:false)
let request = UNNotificationRequest(identifier: "timerDone", content: content , trigger: trigger)
UNUserNotificationCenter.current().add(request,withCompletionHandler:nil)
}
}
#objc func Clock(){
seconds = seconds-1
if seconds == -1{
seconds = 59
minutes = minutes-1
}
if minutes == -1{
minutes = 59
hours = hours-1
}
remainingTimeNumberLabel.text = (String(hours) + ":" + String(minutes) + ":" + String(seconds))
if seconds == 0 && hours == 0 && minutes == 0 {
timer.invalidate()
}
}
func ActivTimer(){
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.Clock), userInfo: nil, repeats: true)
}//SAVING STUFF DOESNT WORK
//
func SaveApp(){
streakNumberString = String(streakNumber)
defaults.set(streakNumberString, forKey: "streakNumbers")
print("Saved" + String(defaults.integer(forKey: "streakNumbers")))
}
func LoadApp(){
streakNumberString = defaults.string(forKey: "streakNumbers")!
print (defaults.integer(forKey: "streakNumbers") )
streakNumber = Int(streakNumberString)!
streakNumberLabel.text = String(streakNumber)
}//
}
The error says it all. You can't invoke SaveApp() on ViewController. You actually need an instance of the ViewController to invoke SaveApp() on itself.
If you wish your ViewController instance to save its data on App termination, you could post a Notification from the AppDelegate's applicationDidEnterBackground method, which is called whenever the app is being minimized and before termination as well:
func applicationDidEnterBackground(_ application: UIApplication) {
NotificationCenter.default.post(Notification(name: Notification.Name("AppAboutToTerminateOrMinimize")))
}
Then you could subscribe to that notification in your ViewController's viewDidLoad():
NotificationCenter.default.addObserver(self,
selector: #selector(AppSave),
name: Notification.Name("AppAboutToTerminateOrMinimize"),
object: nil)
Or as rmaddy mentioned in the comments, you can just put the below code in ViewController's viewDidLoad() and skip the AppDelegate part:
NotificationCenter.default.addObserver(self,
selector: #selector(AppSave),
name: Notification(name: UIApplicationDidEnterBackgroundNotification,
object: nil)
This way when the app minimizes/terminates the AppDelegate will send notification, the ViewController instance (if alive) will receive it and will call AppSave()
You'd have to annotate AppSave() method as #objc
And it's a good practice to use lowerCamelCase for naming of properties and methods /i.e appSave() instead of AppSave()