{"action":"created","comment":{"url":"https://api.github.com/repos/Moya/Moya/pulls/comments/39936354","id":39936354,"diff_hunk":"@@ -2,68 +2,76 @@ import Foundation\n import ReactiveCocoa\n import Alamofire\n \n-/// Subclass of MoyaProvider that returns RACSignal instances when requests are made. Much better than using completion closures.\n+/// Subclass of MoyaProvider that returns SignalProducer<MoyaReponse, NSError> instances when requests are made. Much better than using completion closures.\n public class ReactiveCocoaMoyaProvider<T where T: MoyaTarget>: MoyaProvider<T> {\n     /// Current requests that have not completed or errored yet.\n     /// Note: Do not access this directly. It is public only for unit-testing purposes (sigh).\n-    public var inflightRequests = Dictionary<Endpoint<T>, RACSignal>()\n-\n+    public var inflightRequests = Dictionary<Endpoint<T>, Signal<MoyaResponse, NSError>>()\n+    \n     /// Initializes a reactive provider.\n     override public init(endpointClosure: MoyaEndpointsClosure = MoyaProvider.DefaultEndpointMapping, endpointResolver: MoyaEndpointResolution = MoyaProvider.DefaultEndpointResolution, stubBehavior: MoyaStubbedBehavior = MoyaProvider.NoStubbingBehavior, networkActivityClosure: Moya.NetworkActivityClosure? = nil, manager: Manager = Alamofire.Manager.sharedInstance) {\n         super.init(endpointClosure: endpointClosure, endpointResolver: endpointResolver, stubBehavior: stubBehavior, networkActivityClosure: networkActivityClosure, manager: manager)\n     }\n-\n+    \n     /// Designated request-making method.\n-    public func request(token: T) -> RACSignal {\n+    public func request(token: T) -> SignalProducer<MoyaResponse, NSError> {\n         let endpoint = self.endpoint(token)\n         \n-        // weak self just for best practices – RACSignal will take care of any retain cycles anyway,\n-        // and we're connecting immediately (below), so self in the block will always be non-nil\n-\n-        return RACSignal.`defer` { [weak self] () -> RACSignal! in\n-            \n-            if let weakSelf = self {\n-                objc_sync_enter(weakSelf)\n-                let inFlight = weakSelf.inflightRequests[endpoint]\n-                objc_sync_exit(weakSelf)\n-                if let existingSignal = inFlight {\n-                    return existingSignal\n-                }\n+        if let existingSignal = inflightRequests[endpoint] {\n+            /// returns a new producer which forwards all events of the already existing request signal\n+            return SignalProducer { sink, disposable in\n+                /// connect all events of the existing signal to the observer of this signal producer\n+                existingSignal.observe(sink)\n             }\n-            \n-            let signal = RACSignal.createSignal { (subscriber) -> RACDisposable! in\n-                let cancellableToken = self?.request(token) { data, statusCode, response, error in\n-                    if let error = error {\n-                        if let statusCode = statusCode {\n-                            subscriber.sendError(NSError(domain: MoyaErrorDomain, code: statusCode, userInfo: [NSUnderlyingErrorKey: error as NSError]))\n+        } else {\n+            /// returns a new producer which starts a new producer which invokes the requests. The created signal of the inner producer is saved for inflight request\n+            return SignalProducer { [weak self] outerSink, outerDisposable in\n+                \n+                let producer: SignalProducer<MoyaResponse, NSError> = SignalProducer { [weak self] requestSink, requestDisposable in\n+                    \n+                    let cancellableToken = self?.request(token) { data, statusCode, response, error in\n+                        if let error = error {\n+                            if let statusCode = statusCode {\n+                                sendError(requestSink, NSError(domain: MoyaErrorDomain, code: statusCode, userInfo: [NSUnderlyingErrorKey: error as NSError]))\n+                            } else {\n+                                sendError(requestSink, error as NSError)\n+                            }\n                         } else {\n-                            subscriber.sendError(error as NSError)\n+                            if let data = data {\n+                                sendNext(requestSink, MoyaResponse(statusCode: statusCode!, data: data, response: response))\n+                            }\n+                            sendCompleted(requestSink)\n                         }\n-                    } else {\n-                        if let data = data {\n-                            subscriber.sendNext(MoyaResponse(statusCode: statusCode!, data: data, response: response))\n+                    }\n+                    \n+                    requestDisposable.addDisposable {\n+                        if let weakSelf = self {\n+                            objc_sync_enter(weakSelf)\n+                            // Clear the inflight request\n+                            weakSelf.inflightRequests[endpoint] = nil\n+                            objc_sync_exit(weakSelf)\n+                            // Cancel the request\n+                            cancellableToken?.cancel()\n                         }\n-                        subscriber.sendCompleted()\n                     }\n                 }\n                 \n-                return RACDisposable { () -> Void in\n+                /// starts the inner signal producer and store the created signal.\n+                producer.startWithSignal { [weak self] signal, innerDisposable in\n                     if let weakSelf = self {\n                         objc_sync_enter(weakSelf)\n-                        weakSelf.inflightRequests[endpoint] = nil\n-                        cancellableToken?.cancel()\n+                        weakSelf.inflightRequests[endpoint] = signal\n                         objc_sync_exit(weakSelf)\n+                        /// connect all events of the signal to the observer of this signal producer\n+                        signal.observe(outerSink)\n+                        outerDisposable.addDisposable(innerDisposable)\n                     }\n                 }\n-            }.publish().autoconnect()\n-            \n-            if let weakSelf = self {\n-                objc_sync_enter(weakSelf)\n-                weakSelf.inflightRequests[endpoint] = signal\n-                objc_sync_exit(weakSelf)\n             }\n-            \n-            return signal\n         }\n     }\n+    \n+    public func request(token: T) -> RACSignal {","path":"Moya/ReactiveCocoa/Moya+ReactiveCocoa.swift","position":112,"original_position":112,"commit_id":"141db30b3f83db8eefff57df5bf0e3ce62e4a4f1","original_commit_id":"141db30b3f83db8eefff57df5bf0e3ce62e4a4f1","user":{"login":"petester42","id":296718,"avatar_url":"https://avatars.githubusercontent.com/u/296718?v=3","gravatar_id":"","url":"https://api.github.com/users/petester42","html_url":"https://github.com/petester42","followers_url":"https://api.github.com/users/petester42/followers","following_url":"https://api.github.com/users/petester42/following{/other_user}","gists_url":"https://api.github.com/users/petester42/gists{/gist_id}","starred_url":"https://api.github.com/users/petester42/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/petester42/subscriptions","organizations_url":"https://api.github.com/users/petester42/orgs","repos_url":"https://api.github.com/users/petester42/repos","events_url":"https://api.github.com/users/petester42/events{/privacy}","received_events_url":"https://api.github.com/users/petester42/received_events","type":"User","site_admin":false},"body":"It shouldn't be if the developer has their types set properly. For example if the developer just has something like this `let signal = provider.request(target)` then there will be an error. They would need to specify the type or chain it directly with a subscribe like so `provider.request(target).subscribeNext { _ in  }`. It's not really breaking but it might cause errors for some users.\r\n","created_at":"2015-09-20T23:30:11Z","updated_at":"2015-09-20T23:30:11Z","html_url":"https://github.com/Moya/Moya/pull/224#discussion_r39936354","pull_request_url":"https://api.github.com/repos/Moya/Moya/pulls/224","_links":{"self":{"href":"https://api.github.com/repos/Moya/Moya/pulls/comments/39936354"},"html":{"href":"https://github.com/Moya/Moya/pull/224#discussion_r39936354"},"pull_request":{"href":"https://api.github.com/repos/Moya/Moya/pulls/224"}}},"pull_request":{"url":"https://api.github.com/repos/Moya/Moya/pulls/224","id":45467728,"html_url":"https://github.com/Moya/Moya/pull/224","diff_url":"https://github.com/Moya/Moya/pull/224.diff","patch_url":"https://github.com/Moya/Moya/pull/224.patch","issue_url":"https://api.github.com/repos/Moya/Moya/issues/224","number":224,"state":"open","locked":false,"title":"Adds ReactiveCocoa 4 Support","user":{"login":"petester42","id":296718,"avatar_url":"https://avatars.githubusercontent.com/u/296718?v=3","gravatar_id":"","url":"https://api.github.com/users/petester42","html_url":"https://github.com/petester42","followers_url":"https://api.github.com/users/petester42/followers","following_url":"https://api.github.com/users/petester42/following{/other_user}","gists_url":"https://api.github.com/users/petester42/gists{/gist_id}","starred_url":"https://api.github.com/users/petester42/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/petester42/subscriptions","organizations_url":"https://api.github.com/users/petester42/orgs","repos_url":"https://api.github.com/users/petester42/repos","events_url":"https://api.github.com/users/petester42/events{/privacy}","received_events_url":"https://api.github.com/users/petester42/received_events","type":"User","site_admin":false},"body":"This should address #118. It is based on @justinmakaila's work for ReactiveCocoa 3 but with processing methods moved to an extension. I also added tests for the new `SignalProducer` code (kind of a duplication of the `RACSignal` tests).\r\n\r\nEverything should be :green_apple:  and ready to go!\r\n\r\nIf anyone has input on how to make [this](https://github.com/Moya/Moya/compare/Moya:master...petester42:reactive-cocoa-4?expand=1#diff-6e6eda96ca4cf5e24ec7f03907dbbbcbR15) nicer and keep the compiler happy it would be great. The force cast should never fail but I don't really like it.","created_at":"2015-09-19T02:05:44Z","updated_at":"2015-09-20T23:30:11Z","closed_at":null,"merged_at":null,"merge_commit_sha":"fb69b21cb5ce474156b9ce4bb1efe6d64f1349e1","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/Moya/Moya/pulls/224/commits","review_comments_url":"https://api.github.com/repos/Moya/Moya/pulls/224/comments","review_comment_url":"https://api.github.com/repos/Moya/Moya/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Moya/Moya/issues/224/comments","statuses_url":"https://api.github.com/repos/Moya/Moya/statuses/141db30b3f83db8eefff57df5bf0e3ce62e4a4f1","head":{"label":"petester42:reactive-cocoa-4","ref":"reactive-cocoa-4","sha":"141db30b3f83db8eefff57df5bf0e3ce62e4a4f1","user":{"login":"petester42","id":296718,"avatar_url":"https://avatars.githubusercontent.com/u/296718?v=3","gravatar_id":"","url":"https://api.github.com/users/petester42","html_url":"https://github.com/petester42","followers_url":"https://api.github.com/users/petester42/followers","following_url":"https://api.github.com/users/petester42/following{/other_user}","gists_url":"https://api.github.com/users/petester42/gists{/gist_id}","starred_url":"https://api.github.com/users/petester42/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/petester42/subscriptions","organizations_url":"https://api.github.com/users/petester42/orgs","repos_url":"https://api.github.com/users/petester42/repos","events_url":"https://api.github.com/users/petester42/events{/privacy}","received_events_url":"https://api.github.com/users/petester42/received_events","type":"User","site_admin":false},"repo":{"id":42729502,"name":"Moya","full_name":"petester42/Moya","owner":{"login":"petester42","id":296718,"avatar_url":"https://avatars.githubusercontent.com/u/296718?v=3","gravatar_id":"","url":"https://api.github.com/users/petester42","html_url":"https://github.com/petester42","followers_url":"https://api.github.com/users/petester42/followers","following_url":"https://api.github.com/users/petester42/following{/other_user}","gists_url":"https://api.github.com/users/petester42/gists{/gist_id}","starred_url":"https://api.github.com/users/petester42/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/petester42/subscriptions","organizations_url":"https://api.github.com/users/petester42/orgs","repos_url":"https://api.github.com/users/petester42/repos","events_url":"https://api.github.com/users/petester42/events{/privacy}","received_events_url":"https://api.github.com/users/petester42/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/petester42/Moya","description":"Network abstraction layer written in Swift.","fork":true,"url":"https://api.github.com/repos/petester42/Moya","forks_url":"https://api.github.com/repos/petester42/Moya/forks","keys_url":"https://api.github.com/repos/petester42/Moya/keys{/key_id}","collaborators_url":"https://api.github.com/repos/petester42/Moya/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/petester42/Moya/teams","hooks_url":"https://api.github.com/repos/petester42/Moya/hooks","issue_events_url":"https://api.github.com/repos/petester42/Moya/issues/events{/number}","events_url":"https://api.github.com/repos/petester42/Moya/events","assignees_url":"https://api.github.com/repos/petester42/Moya/assignees{/user}","branches_url":"https://api.github.com/repos/petester42/Moya/branches{/branch}","tags_url":"https://api.github.com/repos/petester42/Moya/tags","blobs_url":"https://api.github.com/repos/petester42/Moya/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/petester42/Moya/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/petester42/Moya/git/refs{/sha}","trees_url":"https://api.github.com/repos/petester42/Moya/git/trees{/sha}","statuses_url":"https://api.github.com/repos/petester42/Moya/statuses/{sha}","languages_url":"https://api.github.com/repos/petester42/Moya/languages","stargazers_url":"https://api.github.com/repos/petester42/Moya/stargazers","contributors_url":"https://api.github.com/repos/petester42/Moya/contributors","subscribers_url":"https://api.github.com/repos/petester42/Moya/subscribers","subscription_url":"https://api.github.com/repos/petester42/Moya/subscription","commits_url":"https://api.github.com/repos/petester42/Moya/commits{/sha}","git_commits_url":"https://api.github.com/repos/petester42/Moya/git/commits{/sha}","comments_url":"https://api.github.com/repos/petester42/Moya/comments{/number}","issue_comment_url":"https://api.github.com/repos/petester42/Moya/issues/comments{/number}","contents_url":"https://api.github.com/repos/petester42/Moya/contents/{+path}","compare_url":"https://api.github.com/repos/petester42/Moya/compare/{base}...{head}","merges_url":"https://api.github.com/repos/petester42/Moya/merges","archive_url":"https://api.github.com/repos/petester42/Moya/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/petester42/Moya/downloads","issues_url":"https://api.github.com/repos/petester42/Moya/issues{/number}","pulls_url":"https://api.github.com/repos/petester42/Moya/pulls{/number}","milestones_url":"https://api.github.com/repos/petester42/Moya/milestones{/number}","notifications_url":"https://api.github.com/repos/petester42/Moya/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/petester42/Moya/labels{/name}","releases_url":"https://api.github.com/repos/petester42/Moya/releases{/id}","created_at":"2015-09-18T15:09:26Z","updated_at":"2015-09-18T15:09:28Z","pushed_at":"2015-09-19T22:17:19Z","git_url":"git://github.com/petester42/Moya.git","ssh_url":"git@github.com:petester42/Moya.git","clone_url":"https://github.com/petester42/Moya.git","svn_url":"https://github.com/petester42/Moya","homepage":"","size":16030,"stargazers_count":0,"watchers_count":0,"language":"Swift","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"Moya:master","ref":"master","sha":"f97454abd7771f3665c0d8c5b0b49876c1bca2f3","user":{"login":"Moya","id":13662162,"avatar_url":"https://avatars.githubusercontent.com/u/13662162?v=3","gravatar_id":"","url":"https://api.github.com/users/Moya","html_url":"https://github.com/Moya","followers_url":"https://api.github.com/users/Moya/followers","following_url":"https://api.github.com/users/Moya/following{/other_user}","gists_url":"https://api.github.com/users/Moya/gists{/gist_id}","starred_url":"https://api.github.com/users/Moya/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Moya/subscriptions","organizations_url":"https://api.github.com/users/Moya/orgs","repos_url":"https://api.github.com/users/Moya/repos","events_url":"https://api.github.com/users/Moya/events{/privacy}","received_events_url":"https://api.github.com/users/Moya/received_events","type":"Organization","site_admin":false},"repo":{"id":23013268,"name":"Moya","full_name":"Moya/Moya","owner":{"login":"Moya","id":13662162,"avatar_url":"https://avatars.githubusercontent.com/u/13662162?v=3","gravatar_id":"","url":"https://api.github.com/users/Moya","html_url":"https://github.com/Moya","followers_url":"https://api.github.com/users/Moya/followers","following_url":"https://api.github.com/users/Moya/following{/other_user}","gists_url":"https://api.github.com/users/Moya/gists{/gist_id}","starred_url":"https://api.github.com/users/Moya/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Moya/subscriptions","organizations_url":"https://api.github.com/users/Moya/orgs","repos_url":"https://api.github.com/users/Moya/repos","events_url":"https://api.github.com/users/Moya/events{/privacy}","received_events_url":"https://api.github.com/users/Moya/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Moya/Moya","description":"Network abstraction layer written in Swift.","fork":false,"url":"https://api.github.com/repos/Moya/Moya","forks_url":"https://api.github.com/repos/Moya/Moya/forks","keys_url":"https://api.github.com/repos/Moya/Moya/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Moya/Moya/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Moya/Moya/teams","hooks_url":"https://api.github.com/repos/Moya/Moya/hooks","issue_events_url":"https://api.github.com/repos/Moya/Moya/issues/events{/number}","events_url":"https://api.github.com/repos/Moya/Moya/events","assignees_url":"https://api.github.com/repos/Moya/Moya/assignees{/user}","branches_url":"https://api.github.com/repos/Moya/Moya/branches{/branch}","tags_url":"https://api.github.com/repos/Moya/Moya/tags","blobs_url":"https://api.github.com/repos/Moya/Moya/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Moya/Moya/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Moya/Moya/git/refs{/sha}","trees_url":"https://api.github.com/repos/Moya/Moya/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Moya/Moya/statuses/{sha}","languages_url":"https://api.github.com/repos/Moya/Moya/languages","stargazers_url":"https://api.github.com/repos/Moya/Moya/stargazers","contributors_url":"https://api.github.com/repos/Moya/Moya/contributors","subscribers_url":"https://api.github.com/repos/Moya/Moya/subscribers","subscription_url":"https://api.github.com/repos/Moya/Moya/subscription","commits_url":"https://api.github.com/repos/Moya/Moya/commits{/sha}","git_commits_url":"https://api.github.com/repos/Moya/Moya/git/commits{/sha}","comments_url":"https://api.github.com/repos/Moya/Moya/comments{/number}","issue_comment_url":"https://api.github.com/repos/Moya/Moya/issues/comments{/number}","contents_url":"https://api.github.com/repos/Moya/Moya/contents/{+path}","compare_url":"https://api.github.com/repos/Moya/Moya/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Moya/Moya/merges","archive_url":"https://api.github.com/repos/Moya/Moya/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Moya/Moya/downloads","issues_url":"https://api.github.com/repos/Moya/Moya/issues{/number}","pulls_url":"https://api.github.com/repos/Moya/Moya/pulls{/number}","milestones_url":"https://api.github.com/repos/Moya/Moya/milestones{/number}","notifications_url":"https://api.github.com/repos/Moya/Moya/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Moya/Moya/labels{/name}","releases_url":"https://api.github.com/repos/Moya/Moya/releases{/id}","created_at":"2014-08-16T07:41:21Z","updated_at":"2015-09-20T19:00:42Z","pushed_at":"2015-09-19T22:20:02Z","git_url":"git://github.com/Moya/Moya.git","ssh_url":"git@github.com:Moya/Moya.git","clone_url":"https://github.com/Moya/Moya.git","svn_url":"https://github.com/Moya/Moya","homepage":"","size":16030,"stargazers_count":1307,"watchers_count":1307,"language":"Swift","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":99,"mirror_url":null,"open_issues_count":23,"forks":99,"open_issues":23,"watchers":1307,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Moya/Moya/pulls/224"},"html":{"href":"https://github.com/Moya/Moya/pull/224"},"issue":{"href":"https://api.github.com/repos/Moya/Moya/issues/224"},"comments":{"href":"https://api.github.com/repos/Moya/Moya/issues/224/comments"},"review_comments":{"href":"https://api.github.com/repos/Moya/Moya/pulls/224/comments"},"review_comment":{"href":"https://api.github.com/repos/Moya/Moya/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Moya/Moya/pulls/224/commits"},"statuses":{"href":"https://api.github.com/repos/Moya/Moya/statuses/141db30b3f83db8eefff57df5bf0e3ce62e4a4f1"}}}}