diff --git a/ExampleApp/ExampleApp.xcodeproj/project.pbxproj b/ExampleApp/ExampleApp.xcodeproj/project.pbxproj index 7268da5..a2bb636 100644 --- a/ExampleApp/ExampleApp.xcodeproj/project.pbxproj +++ b/ExampleApp/ExampleApp.xcodeproj/project.pbxproj @@ -14,9 +14,12 @@ A26EB6C922B0397C006A57F9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A26EB6C822B0397C006A57F9 /* Assets.xcassets */; }; A26EB6CC22B0397C006A57F9 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A26EB6CA22B0397C006A57F9 /* LaunchScreen.storyboard */; }; A2838BCA22B03AA500808FB2 /* Example.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2838BC922B03AA500808FB2 /* Example.swift */; }; + D05F8BFD40E02065595EE0E6 /* Pods_ExampleApp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 710D17345D7BA7F2C2F65DF7 /* Pods_ExampleApp.framework */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 3D31EBDA20881EAE4B234A2B /* Pods-ExampleApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ExampleApp.debug.xcconfig"; path = "Target Support Files/Pods-ExampleApp/Pods-ExampleApp.debug.xcconfig"; sourceTree = ""; }; + 710D17345D7BA7F2C2F65DF7 /* Pods_ExampleApp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ExampleApp.framework; sourceTree = BUILT_PRODUCTS_DIR; }; A26EB6BC22B0397A006A57F9 /* ExampleApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ExampleApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; A26EB6BF22B0397A006A57F9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; A26EB6C122B0397A006A57F9 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -26,6 +29,7 @@ A26EB6CB22B0397C006A57F9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; A26EB6CD22B0397C006A57F9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; A2838BC922B03AA500808FB2 /* Example.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Example.swift; sourceTree = ""; }; + CC6F4F242D0CE56B720366EE /* Pods-ExampleApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ExampleApp.release.xcconfig"; path = "Target Support Files/Pods-ExampleApp/Pods-ExampleApp.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -33,18 +37,28 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D05F8BFD40E02065595EE0E6 /* Pods_ExampleApp.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 074F796A9E8F54AB348D4E6D /* Frameworks */ = { + isa = PBXGroup; + children = ( + 710D17345D7BA7F2C2F65DF7 /* Pods_ExampleApp.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; A26EB6B322B0397A006A57F9 = { isa = PBXGroup; children = ( A26EB6BE22B0397A006A57F9 /* ExampleApp */, A26EB6BD22B0397A006A57F9 /* Products */, B389CCE8590A639BECE24C62 /* Pods */, + 074F796A9E8F54AB348D4E6D /* Frameworks */, ); sourceTree = ""; }; @@ -74,6 +88,8 @@ B389CCE8590A639BECE24C62 /* Pods */ = { isa = PBXGroup; children = ( + 3D31EBDA20881EAE4B234A2B /* Pods-ExampleApp.debug.xcconfig */, + CC6F4F242D0CE56B720366EE /* Pods-ExampleApp.release.xcconfig */, ); path = Pods; sourceTree = ""; @@ -85,9 +101,11 @@ isa = PBXNativeTarget; buildConfigurationList = A26EB6D022B0397C006A57F9 /* Build configuration list for PBXNativeTarget "ExampleApp" */; buildPhases = ( + 756B27761A008CCF857B7B14 /* [CP] Check Pods Manifest.lock */, A26EB6B822B0397A006A57F9 /* Sources */, A26EB6B922B0397A006A57F9 /* Frameworks */, A26EB6BA22B0397A006A57F9 /* Resources */, + 48A742840FDB8C03CE8DB6C9 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -144,6 +162,48 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 48A742840FDB8C03CE8DB6C9 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ExampleApp/Pods-ExampleApp-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ExampleApp/Pods-ExampleApp-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ExampleApp/Pods-ExampleApp-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 756B27761A008CCF857B7B14 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-ExampleApp-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ A26EB6B822B0397A006A57F9 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -294,6 +354,7 @@ }; A26EB6D122B0397C006A57F9 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 3D31EBDA20881EAE4B234A2B /* Pods-ExampleApp.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; @@ -312,6 +373,7 @@ }; A26EB6D222B0397C006A57F9 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = CC6F4F242D0CE56B720366EE /* Pods-ExampleApp.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; diff --git a/ExampleApp/ExampleApp/Example.swift b/ExampleApp/ExampleApp/Example.swift index 72210e6..5bd0a36 100644 --- a/ExampleApp/ExampleApp/Example.swift +++ b/ExampleApp/ExampleApp/Example.swift @@ -59,10 +59,7 @@ private extension Example { } func publisherAsObservable(with textView: UITextView) { - let publisher = AnyPublisher { subscriber in - (0...100).forEach { _ = subscriber.receive($0) } - subscriber.receive(completion: .finished) - } + let publisher = PassthroughSubject() let id = "Publisher as Observable" @@ -85,6 +82,9 @@ private extension Example { textView.append(line: "\(id) -> completed") } } + + (0...100).forEach { publisher.send($0) } + publisher.send(completion: .finished) } func relaysZippedInCombine(with textView: UITextView) { @@ -113,18 +113,18 @@ private extension Example { } ) - let p1 = AnyPublisher { subscriber in - (0...50).forEach { _ = subscriber.receive($0) } - subscriber.receive(completion: .finished) - } - - let p2 = AnyPublisher { subscriber in - (0...50).reversed().forEach { _ = subscriber.receive($0) } - subscriber.receive(completion: .finished) - } + let p1 = PassthroughSubject() + let p2 = PassthroughSubject() _ = p1.asObservable().bind(to: relay1) _ = p2.asObservable().bind(to: relay2) + + + (0...50).forEach { p1.send($0) } + p1.send(completion: .finished) + + (0...50).reversed().forEach { p2.send($0) } + p2.send(completion: .finished) subscription.cancel() } diff --git a/ExampleApp/Podfile.lock b/ExampleApp/Podfile.lock index a048b59..9217ae6 100644 --- a/ExampleApp/Podfile.lock +++ b/ExampleApp/Podfile.lock @@ -1,5 +1,5 @@ PODS: - - RxCombine (1.0.0): + - RxCombine (1.1.0): - RxRelay (~> 5) - RxSwift (~> 5) - RxRelay (5.0.0): @@ -19,10 +19,10 @@ EXTERNAL SOURCES: :path: "../" SPEC CHECKSUMS: - RxCombine: f1acdf170c51b7e074a02d88657b8154440c281f + RxCombine: 795d180ad238505f7957a545266a590462499eea RxRelay: 4f7409406a51a55cd88483f21ed898c234d60f18 RxSwift: 8b0671caa829a763bbce7271095859121cbd895f PODFILE CHECKSUM: 27ab59783b75a3dbb4fec21bad1cf7a4348abaa3 -COCOAPODS: 1.7.2 +COCOAPODS: 1.7.3 diff --git a/RxCombine.podspec b/RxCombine.podspec index 3082d45..f127c50 100644 --- a/RxCombine.podspec +++ b/RxCombine.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "RxCombine" - s.version = "1.1.0" + s.version = "1.2.0" s.summary = "RxSwift is a Swift implementation of Reactive Extensions" s.description = <<-DESC Bi-directional type conversions between RxSwift and Apple's Combine framework. diff --git a/Sources/Rx+Combine/Observable+Combine.swift b/Sources/Rx+Combine/Observable+Combine.swift index 474deda..8301061 100644 --- a/Sources/Rx+Combine/Observable+Combine.swift +++ b/Sources/Rx+Combine/Observable+Combine.swift @@ -13,14 +13,7 @@ public extension ObservableConvertibleType { /// An `AnyPublisher` of the underlying Observable's Element type /// so the Observable pushes events to the Publisher. var publisher: AnyPublisher { - AnyPublisher { subscriber in - let disposable = SingleAssignmentDisposable() - subscriber.receive( - subscription: RxSubscription(disposable: disposable) - ) - disposable.setDisposable(self.asObservable() - .subscribe(subscriber.pushRxEvent)) - } + RxPublisher(upstream: self).eraseToAnyPublisher() } /// Returns a `AnyPublisher` of the underlying Observable's Element type @@ -32,3 +25,21 @@ public extension ObservableConvertibleType { publisher } } + +/// A Publisher pushing RxSwift events to a Downstream Combine subscriber. +public class RxPublisher: Publisher { + public typealias Output = Upstream.Element + public typealias Failure = Swift.Error + + let upstream: Upstream + + init(upstream: Upstream) { + self.upstream = upstream + } + + public func receive(subscriber: S) where Failure == S.Failure, Output == S.Input { + let disposable = SingleAssignmentDisposable() + subscriber.receive(subscription: RxSubscription(disposable: upstream.asObservable().subscribe(subscriber.pushRxEvent))) + disposable.setDisposable(disposable) + } +} diff --git a/Sources/Rx+Combine/Subscription+Rx.swift b/Sources/Rx+Combine/Subscription+Rx.swift index ad0d80e..a7db459 100644 --- a/Sources/Rx+Combine/Subscription+Rx.swift +++ b/Sources/Rx+Combine/Subscription+Rx.swift @@ -10,7 +10,7 @@ import Combine import RxSwift /// A Combine Subscription wrapping a RxSwift Disposable. -/// Upon cancellation, the underlying Disposable is diposed of. +/// Upon cancellation, the underlying Disposable is disposed of. class RxSubscription: Subscription { private let disposable: Disposable