{"issue":{"title":"AFNetworking + Reachability","user":{"login":"kcharwood","id":198768,"url":"https://api.github.com/users/kcharwood","avatar_url":"https://secure.gravatar.com/avatar/a892465144b53062338d0086d2139bcb?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","gravatar_id":"a892465144b53062338d0086d2139bcb"},"created_at":"2011-12-20T21:32:43Z","milestone":null,"state":"open","updated_at":"2011-12-28T22:15:51Z","labels":[],"id":2618476,"closed_at":null,"html_url":"https://github.com/AFNetworking/AFNetworking/issues/157","pull_request":{"patch_url":"https://github.com/AFNetworking/AFNetworking/pull/157.patch","html_url":"https://github.com/AFNetworking/AFNetworking/pull/157","diff_url":"https://github.com/AFNetworking/AFNetworking/pull/157.diff"},"body":"One missing piece in AFNetworking when comparing to ASI is the ability to leverage `Reachability` when making a request. If the host is not reachable, the request should immediately fail instead of waiting for the timeout.  This is especially important for POST requests, since Apple for some [unknown reason](https://devforums.apple.com/message/108292#108292) decided it would be in everyones best interest to set a minimum timeout value of 240 seconds with no way to change it. Waiting for a request to fail for 4 minutes is ridiculous.\r\n\r\nWith that in mind, I wanted to take a stab at adding in `Reachability`. My initial design is setup to be more of an extension to AFNetworking than a piece that lives inside of the main branch (Similar to `AFHTTPRequestOperationLogger`, `AFOAuth2Client`, etc). There are a couple of advantages to this approach, namely being AFNetworking can continue to be a light weight library that requires no other additions, while users can choose to extend the base functionality by bringing in other various extensions. In the case of this extension I have created, you would need to bring in Reachability and SystemConfiguration.framework in addition to `AFReachableClient`. This is actually probably a larger discussion on whats the best way to extend functionality of AFNetworking and provide that to the community. I would love to here @Mattt's thoughts on that.\r\n\r\nNow, on to what I have actually implemented.  I set out with a few goals here:\r\n\r\n 1.  Leverage Apple's `Reachability` class to cancel operations when a network connection is lost\r\n 2.  Create a drop-in subclass of `AFHTTPClient`\r\n 3.  Don't touch or modify anything upstream in AFNetworking\r\n\r\n**The Approach**\r\nI have created a subclass of `AFHTTPClient` called `AFReachableClient`. This object is responsible for maintaining a `Reachability` object for a specific host URL, as well as canceling operations if a network connection is lost. In `AFReachableClient`, I do this in two places. In enqueueHTTPRequestOperation:, I check the reachability status of the connection, and if is not available, I fail this operation and do not enqueue it. This handles all new operations that are enqueued after the network connection is lost. For operations that are in the operationQueue, I use the reachabilityChanged callback to grab all the operations and properly cancel them. I have also included a test project to demonstrate the proper behavior.\r\n\r\n**Things I need changed in AFNetworking**\r\nThis leads me to goal 3 above as I was ALMOST able to achieve this, but in the end had to make a few minor changes.  I would really love feedback on these in particular just to make sure I have not broken something else. The biggest change is in the setCompletionBlock method for all the `AFHTTPRequestOperations`. In the current AFNetworking implementation, if an operation was cancelled it will immediately return and not call the fail block or the success block. This obviously isn't ideal for what I am trying to achieve since the `AFReachableClient` can cancel the request, and the caller would need to get feedback that it did in fact fail with error. I went through each `AFHTTPRequestOperation`, and modified the setCompletionBlock to return immediately if it has been cancelled AND its' error is nil. **@Mattt - any major problem adding the additional check to ensure a failure block gets called if a request is cancelled and its' error is not nil?** It seems to me that if there was an error, the caller should get the failureBlock called with that error.  Existing behavior should continue to work the same since when people cancel the request without manually setting an error, it will return without calling the failure block or successBlock.  Below is the new method:\r\n\r\n```objective-c\r\n- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success\r\n                              failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure\r\n{\r\n    self.completionBlock = ^ {\r\n        if ([self isCancelled] &&\r\n            self.error == nil) {\r\n            return;\r\n        }\r\n        \r\n        if (self.error) {\r\n            if (failure) {\r\n                dispatch_async(dispatch_get_main_queue(), ^(void) {\r\n                    failure(self, self.error);\r\n                });\r\n            }\r\n        } else {\r\n            if (success) {\r\n                dispatch_async(dispatch_get_main_queue(), ^{\r\n                    success(self, self.responseData);\r\n                });\r\n            }\r\n        }\r\n    };\r\n}\r\n```\r\n\r\nIn addition, I needed a way to manually set an error on an operation from outside the operation. For now, I have simply exposed HTTP error on `AFHTTPRequestOperation`. This gets me the behavior I need, but I am guessing that error was private for a reason so it may not be the best long term solution. **Should we have a user error that can be manually set on the operation?**\r\n\r\n**Example**\r\nI have also included an example that hits Yahoo's weather API.  Every time you press the button, 30 operations are queued up and executed one at a time. This gives you time to kill a network connection in the middle of the operationQueue, and see the resulting behavior.\r\n\r\n**Feedback**\r\nWould love feedback/suggestions on the best way to implement this. I would really like to see a place for developers to contribute AFNetworking extensions.","number":157,"url":"https://api.github.com/repos/AFNetworking/AFNetworking/issues/157","comments":3,"assignee":null},"comment":{"user":{"login":"zbowling","id":245886,"url":"https://api.github.com/users/zbowling","avatar_url":"https://secure.gravatar.com/avatar/ba78b57d00a1ed5c2dd21c1feba778d6?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","gravatar_id":"ba78b57d00a1ed5c2dd21c1feba778d6"},"created_at":"2011-12-28T22:15:51Z","updated_at":"2011-12-28T22:15:51Z","id":3295793,"body":"We solved some of your problems in our fork with completion blocks in the @seatme fork. We took a different approach to how to handle all that and we have been merging up our changes over versions. We go back to simple single callback and an error flag for all the issues. We use reachabilty but we check for isCancelled and error flags to know if we have to retry.  ","url":"https://api.github.com/repos/AFNetworking/AFNetworking/issues/comments/3295793"},"action":"created"}