diff --git a/.gitignore b/.gitignore index 9724b3c..ebeae7d 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,6 @@ Carthage/Build fastlane/report.xml fastlane/screenshots + +# AppCode +.idea/ diff --git a/README.md b/README.md index fd635d8..ea5afbe 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ ![](Logo/Logo.png) +[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) +[![Swift Package Manager compatible](https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager) +![macOS](https://img.shields.io/badge/macOS-10.9-lightgrey.svg) + # Reactor Reactor is a framework for making more reactive applications inspired by [Elm](https://github.com/evancz/elm-architecture-tutorial), [Redux](http://redux.js.org/docs/basics/index.html), and recent work on [ReSwift](https://github.com/ReSwift/ReSwift). It's small and simple (just one file), so you can either use Carthage to stay up to date, or just drag and drop into your project and go. Or you can look through it and roll your own. diff --git a/Reactor.xcodeproj/project.pbxproj b/Reactor.xcodeproj/project.pbxproj index bc6426e..7f6cc48 100644 --- a/Reactor.xcodeproj/project.pbxproj +++ b/Reactor.xcodeproj/project.pbxproj @@ -28,7 +28,7 @@ OBJ_15 /* Reactor.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Reactor.framework; sourceTree = BUILT_PRODUCTS_DIR; }; OBJ_16 /* ReactorTests.xctest */ = {isa = PBXFileReference; lastKnownFileType = file; path = ReactorTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; OBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; - OBJ_9 /* Reactor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reactor.swift; sourceTree = ""; }; + OBJ_9 /* Reactor.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = Reactor.swift; sourceTree = ""; tabWidth = 4; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -153,6 +153,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, ); mainGroup = OBJ_5; @@ -212,7 +213,7 @@ SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "macosx iphoneos appletvos watchos appletvsimulator iphonesimulator watchsimulator"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFT_PACKAGE; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 5.0; TARGET_NAME = Reactor; }; name = Debug; @@ -235,7 +236,7 @@ SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "macosx iphoneos appletvos watchos appletvsimulator iphonesimulator watchsimulator"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFT_PACKAGE; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 5.0; TARGET_NAME = Reactor; }; name = Release; @@ -284,7 +285,7 @@ ENABLE_NS_ASSERTIONS = YES; GCC_OPTIMIZATION_LEVEL = 0; IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 10.9; ONLY_ACTIVE_ARCH = YES; OTHER_SWIFT_FLAGS = "-DXcode"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -305,7 +306,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; GCC_OPTIMIZATION_LEVEL = s; IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 10.9; OTHER_SWIFT_FLAGS = "-DXcode"; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; diff --git a/Reactor.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Reactor.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Reactor.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Sources/Reactor.swift b/Sources/Reactor.swift index f81374b..f287e63 100644 --- a/Sources/Reactor.swift +++ b/Sources/Reactor.swift @@ -41,6 +41,7 @@ extension Middleware { } public struct Middlewares { + let id: UInt64 private(set) var middleware: AnyMiddleware } @@ -80,13 +81,31 @@ public struct Subscription { } } +extension String { + static func random(length: Int = 20) -> String { + let base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + return String((0.. UInt64 { + return queue.sync(execute: { () -> UInt64 in + value += 1 + return value + }) + } +} // MARK: - Core public class Core { - private let jobQueue:DispatchQueue = DispatchQueue(label: "reactor.core.queue", qos: .userInitiated, attributes: []) + private var middlewareCounter = Counter() + private let jobQueue:DispatchQueue private let subscriptionsSyncQueue = DispatchQueue(label: "reactor.core.subscription.sync") private var _subscriptions = [Subscription]() @@ -103,7 +122,7 @@ public class Core { } } - private let middlewares: [Middlewares] + private var middlewares: [Middlewares] public private (set) var state: StateType { didSet { subscriptions = subscriptions.filter { $0.subscriber != nil } @@ -115,7 +134,16 @@ public class Core { public init(state: StateType, middlewares: [AnyMiddleware] = []) { self.state = state - self.middlewares = middlewares.map(Middlewares.init) + var tempMiddlewares = [Middlewares]() + for m in middlewares { + tempMiddlewares.append(Middlewares(id: middlewareCounter.increment(), middleware: m)) + } + self.middlewares = tempMiddlewares + if #available(macOS 10.10, *) { + self.jobQueue = DispatchQueue(label: "reactor.core.queue", qos: .userInitiated, attributes: []) + } else { + self.jobQueue = DispatchQueue(label: "reactor.core.queue", qos: .unspecified, attributes: []) + } } @@ -149,5 +177,19 @@ public class Core { command.execute(state: self.state, core: self) } } + + public func observe(with middleware: AnyMiddleware) -> () -> () { + let wrapper = Middlewares(id: middlewareCounter.increment(), middleware: middleware) + jobQueue.async { + self.middlewares.append(wrapper) + } + return { + self.jobQueue.sync { + if let index = self.middlewares.firstIndex(where: { $0.id == wrapper.id }) { + self.middlewares.remove(at: index) + } + } + } + } }