diff --git a/Noted.xcodeproj/project.pbxproj b/Noted.xcodeproj/project.pbxproj index efbfb5e..62e376c 100644 --- a/Noted.xcodeproj/project.pbxproj +++ b/Noted.xcodeproj/project.pbxproj @@ -9,11 +9,8 @@ /* Begin PBXBuildFile section */ 0135E62C1C7B5A6F007982E1 /* Noted.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0135E6281C7B5A6F007982E1 /* Noted.swift */; }; 0135E62E1C7B5A6F007982E1 /* Noted.h in Headers */ = {isa = PBXBuildFile; fileRef = 0135E62B1C7B5A6F007982E1 /* Noted.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 0159B06D1D8D862800467CC4 /* NoteObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0159B06C1D8D862800467CC4 /* NoteObserver.swift */; }; - 0159B06F1D8D863900467CC4 /* NoteType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0159B06E1D8D863900467CC4 /* NoteType.swift */; }; - 0159B0711D8D864300467CC4 /* NoteFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0159B0701D8D864300467CC4 /* NoteFilter.swift */; }; - 017E1C871D89AE0C00034114 /* TestNote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017E1C861D89AE0C00034114 /* TestNote.swift */; }; - 017E1C891D89AE1200034114 /* TestObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017E1C881D89AE1200034114 /* TestObserver.swift */; }; + 017E1C801D89A56F00034114 /* TestNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017E1C7F1D89A56F00034114 /* TestNotification.swift */; }; + 017E1C841D89A5DC00034114 /* TestObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017E1C831D89A5DC00034114 /* TestObserver.swift */; }; 272F1E1D1C6A4A250098F620 /* Noted.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 272F1E121C6A4A250098F620 /* Noted.framework */; }; 272F1E221C6A4A250098F620 /* NotedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 272F1E211C6A4A250098F620 /* NotedTests.swift */; }; /* End PBXBuildFile section */ @@ -32,11 +29,8 @@ 0135E6281C7B5A6F007982E1 /* Noted.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Noted.swift; sourceTree = ""; }; 0135E62A1C7B5A6F007982E1 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 0135E62B1C7B5A6F007982E1 /* Noted.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Noted.h; sourceTree = ""; }; - 0159B06C1D8D862800467CC4 /* NoteObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoteObserver.swift; sourceTree = ""; }; - 0159B06E1D8D863900467CC4 /* NoteType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoteType.swift; sourceTree = ""; }; - 0159B0701D8D864300467CC4 /* NoteFilter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoteFilter.swift; sourceTree = ""; }; - 017E1C861D89AE0C00034114 /* TestNote.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNote.swift; sourceTree = ""; }; - 017E1C881D89AE1200034114 /* TestObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestObserver.swift; sourceTree = ""; }; + 017E1C7F1D89A56F00034114 /* TestNotification.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNotification.swift; sourceTree = ""; }; + 017E1C831D89A5DC00034114 /* TestObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestObserver.swift; sourceTree = ""; }; 272F1E121C6A4A250098F620 /* Noted.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Noted.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 272F1E1C1C6A4A250098F620 /* NotedTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NotedTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 272F1E211C6A4A250098F620 /* NotedTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotedTests.swift; sourceTree = ""; }; @@ -66,9 +60,6 @@ isa = PBXGroup; children = ( 0135E6281C7B5A6F007982E1 /* Noted.swift */, - 0159B06C1D8D862800467CC4 /* NoteObserver.swift */, - 0159B06E1D8D863900467CC4 /* NoteType.swift */, - 0159B0701D8D864300467CC4 /* NoteFilter.swift */, ); path = Classes; sourceTree = ""; @@ -82,12 +73,19 @@ path = "Supporting Files"; sourceTree = ""; }; - - 017E1C851D89AE0300034114 /* Test Objects */ = { + 017E1C811D89A59500034114 /* Supporting Files */ = { isa = PBXGroup; children = ( - 017E1C861D89AE0C00034114 /* TestNote.swift */, - 017E1C881D89AE1200034114 /* TestObserver.swift */, + 272F1E231C6A4A250098F620 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 017E1C821D89A59D00034114 /* Test Objects */ = { + isa = PBXGroup; + children = ( + 017E1C7F1D89A56F00034114 /* TestNotification.swift */, + 017E1C831D89A5DC00034114 /* TestObserver.swift */, ); path = "Test Objects"; sourceTree = ""; @@ -122,10 +120,9 @@ 272F1E201C6A4A250098F620 /* NotedTests */ = { isa = PBXGroup; children = ( - - 017E1C851D89AE0300034114 /* Test Objects */, + 017E1C821D89A59D00034114 /* Test Objects */, 272F1E211C6A4A250098F620 /* NotedTests.swift */, - 272F1E231C6A4A250098F620 /* Info.plist */, + 017E1C811D89A59500034114 /* Supporting Files */, ); path = NotedTests; sourceTree = ""; @@ -187,7 +184,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 0730; ORGANIZATIONNAME = Nodes; TargetAttributes = { 272F1E111C6A4A250098F620 = { @@ -240,10 +237,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 0159B06F1D8D863900467CC4 /* NoteType.swift in Sources */, 0135E62C1C7B5A6F007982E1 /* Noted.swift in Sources */, - 0159B06D1D8D862800467CC4 /* NoteObserver.swift in Sources */, - 0159B0711D8D864300467CC4 /* NoteFilter.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -251,9 +245,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 017E1C891D89AE1200034114 /* TestObserver.swift in Sources */, 272F1E221C6A4A250098F620 /* NotedTests.swift in Sources */, - 017E1C871D89AE0C00034114 /* TestNote.swift in Sources */, + 017E1C801D89A56F00034114 /* TestNotification.swift in Sources */, + 017E1C841D89A5DC00034114 /* TestObserver.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -281,10 +275,8 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -307,7 +299,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -331,10 +323,8 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -351,10 +341,9 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -367,20 +356,18 @@ buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = "$(SRCROOT)/Noted/Supporting Files/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.nodes.Noted; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 2.3; }; name = Debug; }; @@ -389,43 +376,39 @@ buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = "$(SRCROOT)/Noted/Supporting Files/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.nodes.Noted; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 2.3; }; name = Release; }; 272F1E2A1C6A4A250098F620 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CLANG_ENABLE_CODE_COVERAGE = NO; INFOPLIST_FILE = NotedTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.nodes.NotedTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 2.3; }; name = Debug; }; 272F1E2B1C6A4A250098F620 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CLANG_ENABLE_CODE_COVERAGE = NO; INFOPLIST_FILE = NotedTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.nodes.NotedTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 2.3; }; name = Release; }; diff --git a/Noted.xcodeproj/xcshareddata/xcschemes/Noted.xcscheme b/Noted.xcodeproj/xcshareddata/xcschemes/Noted.xcscheme index b552a0f..20bc3a6 100644 --- a/Noted.xcodeproj/xcshareddata/xcschemes/Noted.xcscheme +++ b/Noted.xcodeproj/xcshareddata/xcschemes/Noted.xcscheme @@ -1,6 +1,6 @@ Bool -} - -internal struct PassthroughNoteFilter: NoteFilter { - internal func shouldFilter(note: NoteType) -> Bool { - return false - } -} diff --git a/Noted/Classes/NoteObserver.swift b/Noted/Classes/NoteObserver.swift deleted file mode 100644 index 4faad3b..0000000 --- a/Noted/Classes/NoteObserver.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// NoteObserver.swift -// Noted -// -// Created by Dominik Hádl on 17/09/16. -// Copyright © 2016 Nodes. All rights reserved. -// - -import Foundation - -public protocol NoteObserver: AnyObject { - func didReceive(note: NoteType) - var noteFilter: NoteFilter { get } -} - -extension NoteObserver { - public var noteFilter: NoteFilter { - return Noted.passthroughFilter - } -} diff --git a/Noted/Classes/NoteType.swift b/Noted/Classes/NoteType.swift deleted file mode 100644 index 2bd637f..0000000 --- a/Noted/Classes/NoteType.swift +++ /dev/null @@ -1,11 +0,0 @@ -// -// NoteType.swift -// Noted -// -// Created by Dominik Hádl on 17/09/16. -// Copyright © 2016 Nodes. All rights reserved. -// - -import Foundation - -public protocol NoteType { } diff --git a/Noted/Classes/Noted.swift b/Noted/Classes/Noted.swift index 4e3349a..7ab6500 100644 --- a/Noted/Classes/Noted.swift +++ b/Noted/Classes/Noted.swift @@ -7,45 +7,36 @@ import Foundation +public protocol Notification { + func trigger(receiver: AnyObject) +} + public class Noted { public static let defaultInstance = Noted() - - private let notedQueue = DispatchQueue(label: "com.nodes.noted", attributes: .concurrent) - internal var _observers = NSHashTable(options: .weakMemory) - internal static let passthroughFilter = PassthroughNoteFilter() + private let notedQueue = dispatch_queue_create("com.nodes.queue", DISPATCH_QUEUE_CONCURRENT) + internal var receivers = NSHashTable(options: .WeakMemory) - public var observers: [NoteObserver] { - var values: [AnyObject] = [] - notedQueue.sync { - values = self._observers.allObjects - } - return values.flatMap({ $0 as? NoteObserver }) - } - private init() {} - public func add(observer: NoteObserver, filter: NoteFilter = PassthroughNoteFilter()) { - notedQueue.async(group: nil, qos: .default, flags: .barrier) { - self._observers.add(observer) + public func addObserver(observer: AnyObject) { + dispatch_barrier_async(notedQueue) { [weak self] in + self?.receivers.addObject(observer) } } - public func remove(observer: NoteObserver) { - notedQueue.async(group: nil, qos: .default, flags: .barrier) { - if let foundEntry = (self._observers.allObjects).first(where: {$0 === observer}) { - self._observers.remove(foundEntry) - } + public func removeObserver(observer: AnyObject) { + dispatch_barrier_async(notedQueue) { [weak self] in + self?.receivers.removeObject(observer) } } - - public func post(note: NoteType) { - notedQueue.async { - for receiver in self.observers.filter({ !$0.noteFilter.shouldFilter(note: note) }) { - DispatchQueue.main.async { - receiver.didReceive(note: note) + public func postNotification(notification: Notification) { + dispatch_async(notedQueue) { + for receiver in self.receivers.allObjects { + dispatch_async(dispatch_get_main_queue()) { + notification.trigger(receiver) } } } diff --git a/NotedTests/NotedTests.swift b/NotedTests/NotedTests.swift index d00bd84..df95e9b 100644 --- a/NotedTests/NotedTests.swift +++ b/NotedTests/NotedTests.swift @@ -13,57 +13,62 @@ class NotedTests: XCTestCase { // Used for having strong reference to objects var receiverStore: [TestObserver] = [] - + override func tearDown() { - Noted.defaultInstance._observers.removeAllObjects() + Noted.defaultInstance.receivers.removeAllObjects() receiverStore = [] + TestNotification.testTriggerAction = nil super.tearDown() } - func testAddRemoveObserver() { + func testAddObserver() { let observer = TestObserver() - receiverStore.append(observer) + XCTAssertEqual(Noted.defaultInstance.receivers.count, 0, + "Noted shouldn't contain any receivers by default.") - let expect = expectation(description: "Noted should finish adding and removing receiver.") + Noted.defaultInstance.addObserver(observer) - XCTAssertEqual(Noted.defaultInstance.observers.count, 0, - "Noted shouldn't contain any receivers by default.") + let expectation = expectationWithDescription("Noted should contain a receiver after adding it.") + let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(2 * Double(NSEC_PER_SEC))) + + dispatch_after(delayTime, dispatch_get_main_queue()) { + XCTAssertEqual(Noted.defaultInstance.receivers.count, 1, "Noted should contain a receiver after adding it.") + expectation.fulfill() + } - Noted.defaultInstance.add(observer: observer) + waitForExpectationsWithTimeout(10, handler: nil) + } - DispatchQueue.main.asyncAfter(deadline: DispatchTime(secondsFromNow: 0.5)) { - XCTAssertEqual(Noted.defaultInstance.observers.count, 1, - "Noted should contain a receiver after adding it.") + func testRemoveObserver() { + let observer = TestObserver() - Noted.defaultInstance.remove(observer: observer) + Noted.defaultInstance.addObserver(observer) + Noted.defaultInstance.removeObserver(observer) - DispatchQueue.main.asyncAfter(deadline: DispatchTime(secondsFromNow: 0.5)) { - XCTAssertEqual(Noted.defaultInstance.observers.count, 0, - "Noted shouldn't contain a receiver after removing it.") - expect.fulfill() - } - } + let expectation = expectationWithDescription("Noted shouldn't contain a receiver after removing it.") + let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(2 * Double(NSEC_PER_SEC))) - waitForExpectations(timeout: 10, handler: nil) + dispatch_after(delayTime, dispatch_get_main_queue()) { + XCTAssertEqual(Noted.defaultInstance.receivers.count, 0, + "Noted shouldn't contain a receiver after removing it.") + expectation.fulfill() + } + waitForExpectationsWithTimeout(10, handler: nil) } func testPostNotification() { let observer = TestObserver() - let expect = expectation(description: "A notification should be triggered.") + let expectation = expectationWithDescription("A notification should be triggered.") - observer.noteAction = { note in - let test = note as? TestNote - XCTAssert(test == TestNote.Test, - "The receiver of the notification should be the observer.") - expect.fulfill() + TestNotification.testTriggerAction = { receiver in + XCTAssert(observer === receiver, "The receiver of the notification should be the observer.") + expectation.fulfill() } - receiverStore.append(observer) - - Noted.defaultInstance.add(observer: observer) - Noted.defaultInstance.post(note: TestNote.Test) + Noted.defaultInstance.addObserver(observer) + Noted.defaultInstance.postNotification(TestNotification.Test) - waitForExpectations(timeout: 20, handler: nil) + waitForExpectationsWithTimeout(20, handler: nil) } func testThreadSafety() { @@ -71,23 +76,14 @@ class NotedTests: XCTestCase { let controller = TestObserver() receiverStore.append(controller) - let queue = DispatchQueue(label: "com.noted.queue.\(index)") + let queue = dispatch_queue_create("com.noted.queue.\(index)", nil) - queue.async { - Noted.defaultInstance.add(observer: controller) - Noted.defaultInstance.post(note: TestNote.Test) - } + dispatch_async(queue, { + Noted.defaultInstance.addObserver(controller) + Noted.defaultInstance.postNotification(TestNotification.Test) + }) } - - XCTAssert(true) - } -} - -extension DispatchTime { - init(secondsFromNow seconds: Double) { - let now = DispatchTime.now().uptimeNanoseconds - let delay = UInt64(seconds * Double(NSEC_PER_SEC)) - self.init(uptimeNanoseconds: now + delay) + XCTAssert(true) } } diff --git a/NotedTests/Test Objects/TestNote.swift b/NotedTests/Test Objects/TestNote.swift deleted file mode 100644 index 372362f..0000000 --- a/NotedTests/Test Objects/TestNote.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// TestNote.swift -// Noted -// -// Created by Dominik Hádl on 14/09/16. -// Copyright © 2016 Nodes. All rights reserved. -// - -import Foundation -import Noted - -enum TestNote: NoteType { - case Test -} diff --git a/NotedTests/Test Objects/TestObserver.swift b/NotedTests/Test Objects/TestObserver.swift index b1e3bcd..3d731ad 100644 --- a/NotedTests/Test Objects/TestObserver.swift +++ b/NotedTests/Test Objects/TestObserver.swift @@ -9,12 +9,5 @@ import Foundation import Noted - -class TestObserver: NoteObserver { - var noteAction: ((NoteType) -> Void)? - - func didReceive(note: NoteType) { - noteAction?(note) - } -} - +class TestObserver { +} \ No newline at end of file diff --git a/README.md b/README.md index 4eac3f7..9957806 100644 --- a/README.md +++ b/README.md @@ -1,147 +1,20 @@ -# Noted - -A minimalistic and effective replacement for `NSNotificationCenter`, that promotes the observer pattern and keeps weak references to it's observers. - -**Features:** - -* Simple Setup -* Use `enum` As Notification -* Weak References -* No Unregister Necessary -* OSS, Free, Maintained, No Dependencies - +The observer pattern made Swiftier and easy to use. ## 📝 Requirements * iOS 8.0+ -* Swift 3.0+ +* Swift 2.0+ ## 📦 Installation ### Carthage ~~~ -# Swift 3 -github "nodes-ios/Noted" ~> 2.0 - -# Swift 2 -github "nodes-ios/Noted" ~> 1.0 +github "nodes-ios/Noted" ~~~ ## 💻 Usage -Noted itself is a singleton that you can access from anywhere in your app, and might be especially useful for easily sending messages to your router and/or any other class. - -Start with: - -```swift -import Noted -``` - -### Protocols - -There are two protocols you need to implement in order for *Noted* to work. One for the notification (object/structure/enum) a.k.a `Note` and second for each observer you want to add. - -**Note Type** - -Just make your object conform to it and that's it! - -We recommend using `enum`s as you get most out of Swift and you can associate values without wrapping them in some ugly dictionary with string keys. - -```swift -enum Note: NoteType { - case ShowLoginFlow - case SignupForPush(userId: Int) -} -``` - -**Note Observer** - -The observer protocol requires you to implement a function `didReceive(note: NoteType)` that will be called each time a notification is sent and your observer is add as and observer. - -> **NOTE:** This function will be executed on the main thread. - -```swift -class ViewController: UIViewController, NoteObserver { - // MARK: - Note Observer - - func didReceive(note: NoteType) { - switch note { - case .SingupForPush(let userId): - print(userId) - } - } -} -``` - -### Actions - -There are three actions Noted supports: - -* Add Observer -* Remove Observer* -* Post Note - -> *All observers have a weak reference in Noted, so you are not required to manually remove observers if you want them to disappear on deinit. - -#### Adding Observer - -```swift -func viewDidLoad() { - super.viewDidLoad() - Noted.defaultInstance.add(observer: self) -} - -``` - -> **NOTE:** You need to keep a strong reference to the observer, otherwise it will get removed immediately after adding. - -#### Removing Observer - -```swift -func viewWillDisappear() { - super.viewWillDisappear() - Noted.defaultInstance.remove(observer: self) -} - -``` - -#### Posting Notes - -Posting notes is as simple as it could get, simply call `post(note: note)` and it will be send momentarily. - -```swift -func buttonPressed() { - Noted.defaultInstance.post(note: Note.SignupForPush(userId: 1)) -} -``` - - -> **NOTE:** Be advised that Noted uses a background thread and synchronizes post action with addition and removal of observers. - -### Advanced Features - -If you send a lot of notifications and have many observers, this section might be useful for you. - -#### Filtering - -Noted offers an option to filter which observers will receive a notification and by default uses a `PassthroughNoteFilter` that let's all notifications come through. - -You can override this behaviour by providing your own `NoteFilter` on the observer. - -```swift -struct RandomFilter: NoteFilter { - func shouldFilter(note: NoteType) -> Bool { - return arc4random() % 10 < 5 - } -} - -class TestObserver: NoteObserver { - let noteFilter: NoteFilter = RandomFilter() - - func didReceive(note: NoteType) { } -} -``` - -> **NOTE:** Do not use the filter provided above unless you have #courage. +> TODO: Add usage instructions ## 👥 Credits Made with ❤️ at [Nodes](http://nodesagency.com).