CocoaPods trunk is moving to be read-only. Read more on the blog, there are 11 months to go.

SweetNotifications 3.0.0

SweetNotifications 3.0.0

TestsTested
LangLanguage SwiftSwift
License MIT
ReleasedLast Release Aug 2017
SwiftSwift Version 3.0
SPMSupports SPM

Maintained by Allen Zeng.



  • By
  • Allen Zeng

SweetNotifications

The NotificationCenter is a very useful tool. But using the API in Foundation is verbose and driven entirely by strings and values typed Any. Using these values every time a notification is needed is just awkward.

Using generics in Swift, we can make this much nicer, so we can focus on using the contents of a strongly typed notification.

Quick Start

Install via CocoaPods

pod 'SweetNotifications'

UIKeyboard notifications

UIKeyboard notifications are incorporated under the subspec SweetNotifications/UIKeyboard. The 4 types of notifications are:

  • UIKeyboardWillShowNotification
  • UIKeyboardDidShowNotification
  • UIKeyboardWillHideNotification
  • UIKeyboardDidHideNotification

Take UIKeyboardWillShowNotification as an example, to register:

listener = NotificationCenter.default.watch { (notification: UIKeyboardWillShowNotification) in
    print(notification.frameBegin)
    print(notification.frameEnd)
    print(notification.animationDuration)
    print(notification.animationOption)
    print(notification.isCurrentApp)
}

Don’t forget to deregister later:

NotificationCenter.default.removeObserver(listener)

Note: Support for self registration coming soon

Listening for named events only

There are notifications that don’t contain a userInfo dictionary. In those situations we can simply watch for the named events:

listener = NotificationCenter.default.watch(for: Notification.Name.UIApplicationWillTerminate) {
    // save all the important things!
}

As of this moment, manual deregistration is still required.

Custom notification types

It’s easy to write your own notification types by adopting SweetNotification:

struct ValueChangedNotification: SweetNotification {
    let source: Source

    init(userInfo: [AnyHashable: Any]) throws {
        guard let sourceString = userInfo["source"] as? String else {
            throw SerializationError.missingSource
        }

        switch userInfo["source"] as? String {
        case "API"?:
            source = .api
        case "local"?:
            source = .local
        default:
            throw SerializationError.unknownSource(userInfo["source"] as? String ?? "<Not a string>")
        }
    }

    init(source: Source) {
        self.source = source
    }

    func toUserInfo() -> [AnyHashable: Any]? {
        switch source {
        case .api:
            return ["source": "API"]
        case .local
            return ["source": "local"]
        }
    }

    enum Source {
        case api, local
    }
}

Posting custom notifications

It’s all type safe again :)

let valueChangedNotification = ValueChangedNotification(source: .api)
NotificationCenter.default.post(valueChangedNotification)

Unit testing

Testing custom notifications is very straight forward:

func testInitWithUserInfo_sourceStringIsValid_sourceSetCorrectly() {
    let expectedPairs: [String: ValueChangedNotification.Source] = ["API": .api, "local": .local]

    for (sourceString, expectedSource) in expectedPairs {
        let userInfo: [String: String] = ["source": sourceString]
        
        do {
            let notification = try ValueChangedNotification(userInfo: userInfo)
            XCTAssertEqual(expectedSource, notification.source)
        } catch {
            XCTFail("Unexpected failure: \(error)")
        }
    }
}

Roadmap

  • [x] add global error handler
  • [x] add keyboard notifications types
  • [x] auto-deregistration of listeners
  • [x] cross platform support
  • [ ] CI
  • [ ] Carthage and SPM support(?)