Local Notifications

Episode #174 | 23 minutes | published on June 18, 2015
In this episode we cover local notifications in iOS 8. We cover the difference between count-down style notifications and time-zone based notifications. We also discuss how to add actions to the notifications and handle those in your application.

Episode Links

Creating a Timed Button class

This game features time-based actions that can only be performed after a timeout, so to accomplish this we're using a subclass of UIButton called TimedButton:

import UIKit

@objc protocol TimedButtonDelegate {
    func timedButtonDidBecomeReady(timedButton: TimedButton)
}

@IBDesignable
class TimedButton : UIButton {

    @IBInspectable
    var timeoutInSeconds: Int = 10

    @IBOutlet
    var delegate: TimedButtonDelegate?

    var timeLeft: Int?

    var originalText: String!
    var timer: NSTimer?

    override func awakeFromNib() {
        super.awakeFromNib()

        originalText = titleForState(.Normal)
        addTarget(self, action: Selector("onTap:"), forControlEvents: .TouchUpInside)
    }

    func triggerWait() {
        enabled = false

        timeLeft = timeoutInSeconds
        tick()
        timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("tick"), userInfo: nil, repeats: true)
    }

    func onTap(sender: UIButton) {
        triggerWait()
    }

    func tick() {
        if !enabled && timeLeft != nil {
            timeLeft!--
            let title: String
            if timeLeft <= 0 {
                title = originalText
                timer?.invalidate()
                timer = nil
                enabled = true
                delegate?.timedButtonDidBecomeReady(self)
            } else {
                title = "\(originalText) (\(timeLeft!))"
            }

            UIView.performWithoutAnimation { [weak self] in
                self?.setTitle(title, forState: .Normal)
                self?.layoutIfNeeded()
            }
        }
    }
}

Registering to receive notifications

  // AppDelegate.swift
  func registerForNotifications(application: UIApplication) {

        let action = UIMutableUserNotificationAction()
        action.title = "Mine Again"
        action.identifier = Notifications.Actions.MineAgain.rawValue

        let category = UIMutableUserNotificationCategory()
        category.identifier = Notifications.Categories.JobCompleted.rawValue
        category.setActions([action], forContext: .Default)
        category.setActions([action], forContext: .Minimal)

        let categories = NSSet(object: category) as! Set<UIUserNotificationCategory>

        let settings = UIUserNotificationSettings(
            forTypes:.Alert | .Badge | .Sound,
            categories: categories)
        application.registerUserNotificationSettings(settings)
    }

Scheduling a local notification

    func mineResource(resource: String, message: String, timeout: Int) {
        let reminder = UILocalNotification()
        reminder.alertBody = message
        reminder.fireDate = NSDate(timeIntervalSinceNow: NSTimeInterval(timeout))
        reminder.category = Notifications.Categories.JobCompleted.rawValue
        reminder.userInfo = [ "resource" : resource ]
        UIApplication.sharedApplication().scheduleLocalNotification(reminder)
    }

Handling notification actions


    func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forLocalNotification notification: UILocalNotification, completionHandler: () -> Void) {
        if identifier == Notifications.Actions.MineAgain.rawValue {
            NSNotificationCenter.defaultCenter().postNotificationName("MineNotification",
                object: notification,
                userInfo: notification.userInfo)
        }

        completionHandler()
    }
blog comments powered by Disqus