8

I want to implement a feature similar to WhatsApp's mute feature. So basically, user stops getting notifications (in my case, using Location Manager) for some time. After that time, notifications (Location Manager) is turned on automatically. How can I schedule such an event (Turning on location manager automatically) for example 1 week after I click a button?

jscs
  • 63,694
  • 13
  • 151
  • 195
Arda Keskiner
  • 772
  • 7
  • 23
  • 2
    You can't really schedule this sort of thing - you just need to store the date at which you want things to happen and check that date against the current/date time. If you want to schedule things for a week in advance then you need the user to relaunch your app at that point or you can use a push notification in which case you need to manage the schedule on a server somewhere. – Paulw11 Aug 27 '15 at 11:52

2 Answers2

6

I would suggest a hybrid approach using both NSTimers and a check whenever the app launches or comes to the foreground.

When the user disables notifications store this time in NSUserDefaults as notificationsDisabledTime.

// Declare this constant somewhere
const NSString *kNotificationDisableTime=@"disable_notifications_time"

[[NSUserDefaults sharedUserDefaults] setObject:[NSDate date] forKey:kNotificationDisableTime];

Now whenever the app is launched or comes to the foreground , check whether duration between notificationsDisabledTime and current time is greater than one week. If so re-enable the notifications. Wrap this up in a nice reusable function. Call this function in app delegate , applicationDidBecomeActive :

-(void)reenableNotificationsIfNecessary {

    if ( notifications are already enabled ... ) {
            return;
    }

    NSDate *disabledDate = [[NSUserDefaults sharedUserDefaults] objectForKey:kNotificationDisableTime]

    NSCalendar *gregorian = [[NSCalendar alloc]
             initWithCalendarIdentifier:NSGregorianCalendar];

    NSUInteger unitFlags =  NSDayCalendarUnit;

    NSDateComponents *components = [gregorian components:unitFlags
                                      fromDate:disabledDate
                                      toDate:[NSDate date] options:0];

    NSInteger days = [components day];

    if(days >7) {
        // re-enable notifications
    }
}

As a backup , have an NSTimer that fires about once every hour performing the same check , ie calling this function. This is to handle the case where the user spends a lot of time in your app. This way after one week it will be re-enabled eventually , though not necessarily at EXACTLY the right time but that's alright usually.

Samhan Salahuddin
  • 2,140
  • 1
  • 17
  • 24
  • 1
    Nicely put. Note that, when you say "every hour" for the timer ... it would be utterly OK to do it, say, every second. The amount of processing power used is absolutely tiny, so it's no problem. – Fattie Aug 27 '15 at 12:19
  • Yeah thats true , but having them immediately re-enable is not a priority here – Samhan Salahuddin Aug 27 '15 at 12:22
  • 1
    Well, sure, but I'm just pointing out that there is absolutely no need to do it only "every hour". Do it every minute, say. – Fattie Aug 27 '15 at 16:30
  • Note that, further on your explanation of how to do it, if (for some reason) you want it at an **exact time** - the approach is simply this: each time the app awakens, if the event is within (say) 12 hours, just schedule a timer for that exact time. Essentially just schedule a timer for the correct time (even if "ridiculously far in the future") and very simply, so to speak, reset, "fix", that timer each time the app is tickled. – Fattie Aug 27 '15 at 16:32
2

1. Approach I suggest to use NSTimer Class and set a timer to get call to function which will unmute. And also Background Task for using method in the background and it could be done by adding

var bgTask = UIBackgroundTaskIdentifier
var app = UIApplication.sharedApplication()
app.beginBackgroundTaskWithExpirationHandler { () -> Void in
    app.endBackgroundTask(bgTask)
}

before calling schedule.

For example I wanted to mute for 8 hours, than you need to call

NSTimer.scheduledTimerWithTimeInterval(60*8, target:(self), selector: Selector("stopper"), userInfo: nil, repeats: no);

and add your stopper

func stopper(){
   //unmute
}

also you can send specific info about the object which will be muted by adding userInfo to timer..

2. Approach

You can look to time differences between applicationDidEnterBackground and applicationDidEnterForeground

let date = NSDate.date() and difference let difference NSDate.timeIntervalSinceDate(date)

mert
  • 1,090
  • 13
  • 26
  • 2
    This won't really work because as soon as the app moves into the background the NSTimer will stop – Paulw11 Aug 27 '15 at 11:50
  • Yes you're right forgot to mention background mode I'm editting comment by using the answer again.. http://stackoverflow.com/a/9623490/2103088 sorry :) – mert Aug 27 '15 at 11:57