UILocalNotification with action button - ios

I create a UILocationNotification with two action button one call sleep and wake up now. So once the user sees the notification if they pressed wake up now the app will launch and execute some code for some reason the app launches then refuse to execute the codes.
FYI : The code for the UILocalNotification were implement and they are working, the only problem is when I pressed the wake up now button.
func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forLocalNotification notification: UILocalNotification, completionHandler: () -> Void) {
if notification.category == "options" {
if identifier == "Sleep"{
println("sleep more lazy bumm")
}
else if identifier == "wakeup"{
var object = ViewController()
object.wakeupnow()
}
}
Second Approach I took but it still not working
func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forLocalNotification notification: UILocalNotification, completionHandler: () -> Void) {
if notification.category == "options" {
if identifier == "Sleep"{
println("sleep more lazy bumm")
}
else if identifier == "wakeup"{
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("wake"), name: UIApplicationWillEnterForegroundNotification, object: nil)
}
}
fun wake(){
var alertview = UIAlertView()
alert.message = "Good job you are up now, so lets get to work"
alert.addButtonWithTitle("ok")
alert.cancelButtonIndex = 0
alert.show()
}

Remember that application:handleActionWithIdentifer:forLocalNotification:completionHandler: gets called in a background thread. If you're doing anything in the UI you'll need to do it on the main queue.
Also, you have to call the completionHandler block as soon as you can, or the system will kill your app.
Please see the Apple documentation about this: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/#//apple_ref/occ/intfm/UIApplicationDelegate/application:handleActionWithIdentifier:forLocalNotification:completionHandler:
Also, in your first example you are instantiating a view controller and calling a function on it but you aren't actually presenting the view controller - what do you want to happen with that view controller? You'll need to do something to make it appear, which will depend on how your app is structured. You may want to present it modally over your root navigation controller, for example. Or maybe you mean to be calling that function on your already-existing ViewController, in which case you need to keep a reference to it somewhere instead of instantiating a new one when the notification action is triggered.
In your second example, you are adding yourself as an observer to the NSNotificationCenter instead of actually posting a notification, so of course your function will never get called. If you want to take that approach, you need to call addObserver sometime earlier - in applicationDidFinishLaunching:, for example:
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("wake"), name: "wakeup", object: nil)
Then, in your handleActionWithIdentifier: function, call:
NSNotificationCenter.defaultCenter().postNotificationName("wakeup", object: nil)
That should result in your wake function being called. You still have the problem of trying to show an alert view from a background thread, though, so you would need to wrap your call in a dispatch_async:
func wake(){
var alertview = UIAlertView()
alert.message = "Good job you are up now, so lets get to work"
alert.addButtonWithTitle("ok")
alert.cancelButtonIndex = 0
dispatch_async(dispatch_get_main_queue(),{
alert.show()
})
}
Incidentally, UIAlertView is deprecated and should be replaced by UIAlertController for iOS 8 and up.

Related

SkScene update method interrupted by push notifications, how can i detect the interruption

I have a simple game app, which is programmed with SpriteKit. The Problem is, when a push notifications (SMS,iMessage etc) appears, the game stutters because the update:forScene: method is not called.
To avoid this i want to implement a simple pause menu, which will be shown as soon as a push message comes in.
How can i detect if a push message interrupts the app? In AppDelegate application:willResignActive is also not called.
It would be the best if the game continues when the message comes in, if there is another solution to force the update method to be called.
Had anybody the same Problem?
You should not try to resume your game when an interruption is happening, you should pause it, otherwise its not a good user experience.
For iMessages, phone calls etc you usually use the method you said doesn't work.
I use NSNotificationCenter to pause my games, you can google about it, there is plenty tutorials.
Essentially in your game scene add a NSNotificationCenter observer.
Also create a property for that observers name to avoid typos later on.
let pauseGameKey = "PauseGameKey" // above class so you can access it anywhere in project
class GameScene: SKScene {
// add this in didMoveToView
// in #selector add the method you want to get called
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(yourPauseGameMethod), name: pauseGameKey, object: nil)
}
Than create the willMoveFromView method so you can remove the observer when you transition to another scene (good practice).
override func willMoveFromView(view: SKView) {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
Than in app delegate post the notification when the application will resign.
func applicationWillResignActive(application: UIApplication) {
NSNotificationCenter.defaultCenter().postNotificationName(pauseGameKey, object: nil)
}
For local and remote UINotifications you can additional use these 2 methods in app delegate.
/// Local notification
func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) {
}
/// Remote notification
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
}
Hope this helps

table view not getting refreshed on opening app

When the app is open or in background, I am using notification in appdelegate to update the message box table and then it is working.
Appdelegate (in didFinishLaunchingWithOptions and didReceiveRemoteNotification):
NSNotificationCenter.defaultCenter().postNotificationName("changeMessageBox", object: nil)
MessageViewController:
in viewdidload:
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector (MessagesViewController.reloadtable), name: "changeMessageBox", object: nil)
func reloadtable()
{
clearArrays()
if (PFUser.currentUser()!["firebaseUID"] !== nil)
{
self.updateResultArray(PFUser.currentUser()!["firebaseUID"] as! String)
resultsTable.reloadData()
}
}
and data is refreshed in the message box.
But when the app is closed and i recieve a chat, the message box ( the window with messages from all the people not the individual chat) does not get updated.
I have to open the app, go to message box ,then back to main page and go back to message box again only then the table view gets refreshed.
Do you guys know what am i missing?
Try below code for post notification,
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), { () -> Void in
NSNotificationCenter.defaultCenter().postNotificationName("changeMessageBox", object: nil)
})
I was having same issue and resolved like this. Hope this will help you.
Receiving Notification while app in closed or in suspended state will trigger
application:handleActionWithIdentifier:forRemoteNotification:completionHandler:
Try to post notification in this method. i guess it will update your view.
Additionally Refer this document if you have query with Notifiacation
http://samwize.com/2015/08/07/how-to-handle-remote-notification-with-background-mode-enabled/

Scheduled NSNotification (Instead of UILocalNotification)... Swift solutions?

My app (prefix "AAS") is basically a game where users lose points every day they don't play. I use UILocalNotifications to alert the user that they've lost points, and invite them back to play. One of my view controllers displays when the points have changed, and it's pretty simple to send out an NSNotification when a UILocalNotification is fired while the app is open).
func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) {
if notification.userInfo != nil {
if let notificationName = notification.userInfo![AASNotification.ActionKey] as? String {
NSNotificationCenter.defaultCenter().postNotificationName(notificationName, object: nil, userInfo: nil)
}
}
}
When the app is reopened after being inactive, one of the classes calculates how many points are lost. Great. Bulletproof, except when the user disallows my app to use NotificationCenter, the app will not be updated if it's open when the notification is supposed to fire. For this case, I wrote my own implementation of a timed notification queue that would mimic UILocalNotification to a certain extent while my app is open. But I thought, someone must have had this problem before, and maybe there is a cocoapod for it.
So my question to the community is, does someone know of a library that dispatches timed NSNotifications? Or a different approach to this problem? Here's my solution, which is barebones and works for the purpose I need:
https://github.com/JamesPerlman/JPScheduledNotificationCenter
I'd love to use one that was coded by a professional and is well tested and feature rich. (I was made aware that this request is off topic for SO.)
Edits:
I want to be able to queue up any amount of NSNotifications to be fired at arbitrary dates. Obviously the NSNotifications can only be received by my app while it is open, that's fine. I do not know the expense of using one NSTimer for each NSNotification (could be hundreds of NSTimers all on the run loop), so my solution only uses one NSTimer at a time. I want the ability to schedule and cancel NSNotifications just like you can do with UINotifications.
You could try NSTimer (NSTimer class reference). In your AppDelegate you can create a method similar to your didReceiveLocalNotification method to execute when the timer is triggered. Also, create an NSUserDefault to store the next time you need to trigger the timer. Finally, at the point where you want to begin the countdown, get the time interval from the current time until the time you want to trigger the event, and set the timer.
So in your AppDelegate, register the default and implement the notifyPlayer:
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
{
let userDefaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.registerDefaults(["alertTime": NSDate()]) //initial value
return true
}
func notifyPlayer() {
// Calculate points and notify relevant viewcontroller to alert player.
let defaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
let lastNotificationTime = defaults.objectForKey("alertTime") as! NSDate
let nextNotificationTime = lastNotificationTime.dateByAddingTimeInterval(86400)
defaults.setObject(nextNotificationTime, forKey: "alertTime")
}
}
Now set the timer wherever it makes sense, probably in your app's initial view controller.
class InitialVewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let defaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
let savedTime = defaults.objectForKey("alertTime") as! NSDate
let countDownTime = savedTime.timeIntervalSinceNow
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
NSTimer.scheduledTimerWithTimeInterval(countDownTime,
target: appDelegate,
selector: #selector(AppDelegate.notifyPlayer()),
userInfo: nil,
repeats: false)
}
}
It's not perfect, as I haven't tested it, but I think the concept will work for you.
Edit: Just to clarify, this would solve your problem of alerting the user while he is using the app, but won't do anything when the app is not in use. I don't know of any way to send users notification center notifications when permission hasn't been granted.

iOS 9 Quick Actions (3D Touch)

I am trying to understand doing Quick Actions (3D Touch) for iOS 9.
I wanted the user to select 1 of 4 filter to be applied to image, so if I select item 1, I will set the NSUserDefaults.standardUserDefaults() to the filter, then show the correct picture with the applied filter.
In AppDelete.swift:
func application(application: UIApplication, performActionForShortcutItem shortcutItem: UIApplicationShortcutItem, completionHandler: (Bool) -> Void) {
var filterType:Int
switch (shortcutItem.type) {
...set filterType
}
NSUserDefaults.standardUserDefaults().setInteger(filterType, forKey:"filterType")
NSUserDefaults.standardUserDefaults().synchronize()
}
In ViewController.swift:
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector:"setDefaultFilter", name: UIApplicationWillEnterForegroundNotification, object:nil) // Handle enter from background
setDefaultFilter()
}
func setDefaultFilter() {
filterType = defaults.integerForKey("filterType")
...
imageView.image = filterImage(defaultImage!, filter:filters[filterType])
}
However, when enter the app from the menu, it will always show the last selection (not the current selection). If I select item 1, nothing happened. I select item 3, item 1 will appeared.
I have also try passing parameters via appDelegate and the result is the same. I believe there are some issues with life cycle.
Any ideas?
NSUserDefaults write data on flash, which may not be so fast.
You can wait a little longer, like observe UIApplicationDidBecomeActiveNotification other than UIApplicationWillEnterForegroundNotification.
Or you can use other ways to pass params, e.g., as an instance variable in AppDelegate.
didFinishLaunchingWithOptions method is always called before calling performActionForShortcutItem method to response to the quick action.
So, I think that you need to check what kind of quick action is selected in didFinishLaunchingWithOptions method. If the app is not launched from quick action, you just continue to your normal app launching process.(default filter)
And if you decide to handle quick action in didFinishLaunchingWithOptions, you have to return NO in didFinishLaunchingWithOptions.
You could get more idea from my demo project:
https://github.com/dakeshi/3D_Touch_HomeQuickAction

Schedule notification to fire every day at X h:Y s and redirect to specific View

I'm in trouble with creating an app that fires it's notification every day at the same time.
In my case this time should be 9:00 Ante Meridiem (AM)
I'd like to fire this notification when the application is not present in the foreground, so it was killed before or just simply moved to background.
I can redirect the user to my page with this method from AppDelegate:
func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) {
var storyboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
var dvc:UINavigationController = (storyboard.instantiateViewControllerWithIdentifier("xyzID") as? UINavigationController)!
self.window!.rootViewController = dvc
}
Thanks in advance
When you receive a local notification, your app delegate's application(..., didReceiveLocalNotification ...) method is called.
In response to that call, you could write code to navigate to the desired view controller. I don't know what your "Reveal view controller" is, but I assume it's something like this, which has methods for revealing the hidden VC.

Resources