Skip to content

Commit

Permalink
add library
Browse files Browse the repository at this point in the history
  • Loading branch information
allen-zeng committed Dec 23, 2016
1 parent 4c0fca0 commit b70d8c9
Show file tree
Hide file tree
Showing 9 changed files with 791 additions and 0 deletions.
433 changes: 433 additions & 0 deletions SwiftNotifications.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0810"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "9FBE0F541E095EB600604C8F"
BuildableName = "SwiftNotifications.framework"
BlueprintName = "SwiftNotifications"
ReferencedContainer = "container:SwiftNotifications.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "9FBE0F5D1E095EB600604C8F"
BuildableName = "SwiftNotificationsTests.xctest"
BlueprintName = "SwiftNotificationsTests"
ReferencedContainer = "container:SwiftNotifications.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "9FBE0F541E095EB600604C8F"
BuildableName = "SwiftNotifications.framework"
BlueprintName = "SwiftNotifications"
ReferencedContainer = "container:SwiftNotifications.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "9FBE0F541E095EB600604C8F"
BuildableName = "SwiftNotifications.framework"
BlueprintName = "SwiftNotifications"
ReferencedContainer = "container:SwiftNotifications.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "9FBE0F541E095EB600604C8F"
BuildableName = "SwiftNotifications.framework"
BlueprintName = "SwiftNotifications"
ReferencedContainer = "container:SwiftNotifications.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
24 changes: 24 additions & 0 deletions SwiftNotifications/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
44 changes: 44 additions & 0 deletions SwiftNotifications/NotificationCenter+Serialization.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
public extension NotificationCenter {
public func watch<T: SerializableNotification>(
_ object: AnyObject? = nil,
queue: OperationQueue = OperationQueue.main,
handler: @escaping (T) -> Void) -> NSObjectProtocol
{
return addObserver(
forName: T.notificationName,
object: object,
queue: queue,
using: { notification in
guard let userInfo = notification.userInfo else {
fatalError("Serializable notifications require userInfo")
}

do {
let serializedNotification = try T(userInfo: userInfo as [NSObject : AnyObject])

handler(serializedNotification)
} catch {
fatalError("Error during deserialization of notification: \(error)")
}
})
}

public func post<T: SerializableNotification>(_ notification: T, object: AnyObject? = nil) {
self.post(name: T.notificationName, object: object, userInfo: notification.toUserInfo())
}

public func post(_ name: Notification.Name, object: AnyObject? = nil) {
self.post(name: name, object: object, userInfo: nil)
}

public func watch(
for name: Notification.Name,
object: AnyObject? = nil,
queue: OperationQueue = OperationQueue.main,
handler: @escaping (Void) -> Void) -> NSObjectProtocol
{
return addObserver(forName: name, object: object, queue: queue) { _ in
handler()
}
}
}
17 changes: 17 additions & 0 deletions SwiftNotifications/SerializableNotification.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
public protocol SerializableNotification {
init(userInfo: [AnyHashable: Any]) throws

static var notificationName: Notification.Name { get }

func toUserInfo() -> [AnyHashable: Any]?
}

public extension SerializableNotification {
public static var notificationName: Notification.Name {
return Notification.Name("\(Self.self)")
}
}

public enum NotificationSerializationError: Error {
case noUserInfo, missingRequiredInfo
}
19 changes: 19 additions & 0 deletions SwiftNotifications/SwiftNotifications.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// SwiftNotifications.h
// SwiftNotifications
//
// Created by Allen on 20/12/16.
// Copyright © 2016 Allen. All rights reserved.
//

#import <UIKit/UIKit.h>

//! Project version number for SwiftNotifications.
FOUNDATION_EXPORT double SwiftNotificationsVersionNumber;

//! Project version string for SwiftNotifications.
FOUNDATION_EXPORT const unsigned char SwiftNotificationsVersionString[];

// In this header, you should import all the public headers of your framework using statements like #import <SwiftNotifications/PublicHeader.h>


22 changes: 22 additions & 0 deletions SwiftNotificationsTests/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
126 changes: 126 additions & 0 deletions SwiftNotificationsTests/SwiftNotificationsTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import XCTest

@testable import SwiftNotifications

class SerializableNotificationTests: XCTestCase {
private var listener: NSObjectProtocol?

private let notificationName = Notification.Name("test")

override func tearDown() {
if let listener = listener {
NotificationCenter.default.removeObserver(listener)
}

super.tearDown()
}

func testWatchForName_notificationObserverEstablished() {
runAsyncTest { expectation in
listener = NotificationCenter.default.watch(for: notificationName) {
expectation.fulfill()
}

NotificationCenter.default.post(name: notificationName, object: nil, userInfo: nil)
}
}

func testPostName_notificationDelivered() {
runAsyncTest { expectation in
listener = NotificationCenter.default.addObserver(
forName: notificationName,
object: nil,
queue: OperationQueue.main,
using: { _ in
expectation.fulfill()
})

NotificationCenter.default.post(notificationName)
}
}

func testWatchForSerializableNotification_notificationObserverEstablished() {
runAsyncTest { expectation in
let expectedString = "alsdkjfaldkjf"
let expectedNumber = 84
listener = NotificationCenter.default.watch { (notification: TestNotification) in
XCTAssertEqual(expectedString, notification.string)
XCTAssertEqual(expectedNumber, notification.number)

expectation.fulfill()
}

NotificationCenter.default.post(
name: TestNotification.notificationName,
object: nil,
userInfo: [
"number": expectedNumber,
"string": expectedString])
}
}

func testPostSerializableNotification_notificationDelivered() {
runAsyncTest { expectation in
let expectedString = "sljkt"
let expectedNumber = 432

listener = NotificationCenter.default.addObserver(
forName: TestNotification.notificationName,
object: nil,
queue: OperationQueue.main,
using: { notification in
guard let userInfo = notification.userInfo else {
XCTFail("missing userInfo")
return
}

XCTAssertEqual(expectedString, userInfo["string"] as? String)
XCTAssertEqual(expectedNumber, userInfo["number"] as? Int)
XCTAssertEqual(2, userInfo.count)
expectation.fulfill()
})

NotificationCenter.default.post(TestNotification(string: expectedString, number: expectedNumber))
}
}

private func runAsyncTest(testBody: (XCTestExpectation) -> Void) {
let expectation = self.expectation(description: #function)

testBody(expectation)

waitForExpectations(timeout: 1) {
if let error = $0 {
XCTFail(error.localizedDescription)
}
}
}

private struct TestNotification: SerializableNotification {
let string: String
let number: Int

init(string: String, number: Int) {
self.string = string
self.number = number
}

init(userInfo: [AnyHashable: Any]) throws {
guard
let string = userInfo["string"] as? String,
let number = userInfo["number"] as? Int else
{
throw NotificationSerializationError.missingRequiredInfo
}

self.string = string
self.number = number
}

func toUserInfo() -> [AnyHashable: Any]? {
return [
"string": string,
"number": number]
}
}
}

0 comments on commit b70d8c9

Please sign in to comment.