Episode #174

Local Notifications

23 minutes
Published on June 18, 2015

This video is only available to subscribers. Get access to this video and 584 others.

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()
    }