From 3c9f09b9595699d148c8e8461d57b9cd542086c5 Mon Sep 17 00:00:00 2001 From: Patrick Hernandez Date: Sun, 8 Apr 2012 18:18:13 -0500 Subject: [PATCH 01/15] commiting the .gitignore file --- .gitignore | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f9f28d5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +.DS_Store +*.swp +*~.nib + +build/ + +*.pbxuser +*.perspective +*.perspectivev3 + +*.mode1v3 +*.mode2v3 + +xcuserdata \ No newline at end of file From 57da89896c61eb8c6d3d2adb9a44f7e211fbfdc1 Mon Sep 17 00:00:00 2001 From: Patrick Hernandez Date: Sun, 8 Apr 2012 22:31:35 -0500 Subject: [PATCH 02/15] Update to support batch completion block firing after all dependent completion blocks. - Added dispatch group property to AFHTTPRequestOperation - Modified all request objects to call dispatch_group_async in completion blocks - Added a dispatch semaphore for thread safety of the dispatch group property - Added dispatch_group_enter and dispatch_group_leave calls to ensure requests are always in the group until the completion block finishes. - Added an override for setCompletionBlock to call dispatch_group_leave so that subclasses do not need the call in each completion block. - Modified enqueueBatchOfHTTPRequestOperations to now dispatch_group_notify in the NSBlockOperation completion block --- AFNetworking/AFHTTPClient.m | 9 ++- AFNetworking/AFHTTPRequestOperation.h | 4 ++ AFNetworking/AFHTTPRequestOperation.m | 60 ++++++++++++++++++- AFNetworking/AFImageRequestOperation.m | 6 +- AFNetworking/AFJSONRequestOperation.m | 8 +-- AFNetworking/AFPropertyListRequestOperation.m | 8 +-- AFNetworking/AFXMLRequestOperation.m | 6 +- 7 files changed, 83 insertions(+), 18 deletions(-) diff --git a/AFNetworking/AFHTTPClient.m b/AFNetworking/AFHTTPClient.m index 60b44a4..a5e2b2c 100644 --- a/AFNetworking/AFHTTPClient.m +++ b/AFNetworking/AFHTTPClient.m @@ -515,9 +515,11 @@ static void AFReachabilityCallback(SCNetworkReachabilityRef __unused target, SCN progressBlock:(void (^)(NSUInteger numberOfCompletedOperations, NSUInteger totalNumberOfOperations))progressBlock completionBlock:(void (^)(NSArray *operations))completionBlock { + dispatch_group_t dispatchGroup = dispatch_group_create(); + NSBlockOperation *batchedOperation = [NSBlockOperation blockOperationWithBlock:^{ if (completionBlock) { - dispatch_async(dispatch_get_main_queue(), ^{ + dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{ completionBlock(operations); }); } @@ -529,9 +531,10 @@ static void AFReachabilityCallback(SCNetworkReachabilityRef __unused target, SCN for (AFHTTPRequestOperation *operation in operations) { AFCompletionBlock originalCompletionBlock = [[operation.completionBlock copy] autorelease]; + operation.dispatchGroup = dispatchGroup; operation.completionBlock = ^{ if (progressBlock) { - dispatch_async(dispatch_get_main_queue(), ^{ + dispatch_group_async(dispatchGroup, dispatch_get_main_queue(), ^{ progressBlock([[batchedOperation.dependencies filteredArrayUsingPredicate:finishedOperationPredicate] count], [batchedOperation.dependencies count]); }); } @@ -544,6 +547,8 @@ static void AFReachabilityCallback(SCNetworkReachabilityRef __unused target, SCN [batchedOperation addDependency:operation]; [self enqueueHTTPRequestOperation:operation]; } + + dispatch_release(dispatchGroup); } #pragma mark - diff --git a/AFNetworking/AFHTTPRequestOperation.h b/AFNetworking/AFHTTPRequestOperation.h index 122099e..c43c8ca 100644 --- a/AFNetworking/AFHTTPRequestOperation.h +++ b/AFNetworking/AFHTTPRequestOperation.h @@ -83,6 +83,10 @@ */ @property (nonatomic) dispatch_queue_t failureCallbackQueue; +/** + The dispatch group on which to call the completion/failure block + */ +@property (nonatomic) dispatch_group_t dispatchGroup; /** A Boolean value determining whether or not the class can process the specified request. For example, `AFJSONRequestOperation` may check to make sure the content type was `application/json` or the URL path extension was `.json`. diff --git a/AFNetworking/AFHTTPRequestOperation.m b/AFNetworking/AFHTTPRequestOperation.m index 871cb18..cb96e36 100644 --- a/AFNetworking/AFHTTPRequestOperation.m +++ b/AFNetworking/AFHTTPRequestOperation.m @@ -56,6 +56,8 @@ static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { @interface AFHTTPRequestOperation () @property (readwrite, nonatomic, retain) NSError *HTTPError; +@property (nonatomic) dispatch_once_t onceToken; +@property (atomic) dispatch_semaphore_t dispatchSemaphore; @end @implementation AFHTTPRequestOperation @@ -64,6 +66,9 @@ static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { @synthesize HTTPError = _HTTPError; @synthesize successCallbackQueue = _successCallbackQueue; @synthesize failureCallbackQueue = _failureCallbackQueue; +@synthesize dispatchGroup = _dispatchGroup; +@synthesize onceToken = _onceToken; +@synthesize dispatchSemaphore = _dispatchSemaphore; - (id)initWithRequest:(NSURLRequest *)request { @@ -73,6 +78,7 @@ static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { } self.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)]; + self.dispatchSemaphore = dispatch_semaphore_create(1); return self; } @@ -92,6 +98,16 @@ static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { _failureCallbackQueue = NULL; } + if (_dispatchGroup) { + dispatch_release(_dispatchGroup); + _dispatchGroup = NULL; + } + + if (_dispatchSemaphore) { + dispatch_release(_dispatchSemaphore); + _dispatchSemaphore = NULL; + } + [super dealloc]; } @@ -157,6 +173,46 @@ static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { } } +- (void)setDispatchGroup:(dispatch_group_t)dispatchGroup { + dispatch_semaphore_wait(self.dispatchSemaphore, DISPATCH_TIME_FOREVER); + if (dispatchGroup != _dispatchGroup) { + if (_dispatchGroup) { + dispatch_group_leave(_dispatchGroup); + dispatch_release(_dispatchGroup); + _dispatchGroup = NULL; + } + + if (dispatchGroup) { + dispatch_retain(dispatchGroup); + _dispatchGroup = dispatchGroup; + dispatch_group_enter(_dispatchGroup); + } + } + dispatch_semaphore_signal(self.dispatchSemaphore); +} + +- (dispatch_group_t)dispatchGroup { + dispatch_semaphore_wait(self.dispatchSemaphore, DISPATCH_TIME_FOREVER); + if(_dispatchGroup == NULL) { + _dispatchGroup = dispatch_group_create(); + dispatch_group_enter(_dispatchGroup); + } + dispatch_semaphore_signal(self.dispatchSemaphore); + return _dispatchGroup; +} + +- (void)setCompletionBlock:(void (^)(void))block { + [super setCompletionBlock:^{ + if(block) { + block(); + } + // Dispatch once is used to ensure that setting the block with this block will not cause multiple calls to 'dispatch_group_leave' + dispatch_once(&_onceToken, ^{ + dispatch_group_leave(self.dispatchGroup); + }); + }]; +} + - (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure { @@ -167,13 +223,13 @@ static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { if (self.error) { if (failure) { - dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_group_async(self.dispatchGroup, self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ failure(self, self.error); }); } } else { if (success) { - dispatch_async(self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_group_async(self.dispatchGroup, self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ success(self, self.responseData); }); } diff --git a/AFNetworking/AFImageRequestOperation.m b/AFNetworking/AFImageRequestOperation.m index 971cd14..6f629e4 100644 --- a/AFNetworking/AFImageRequestOperation.m +++ b/AFNetworking/AFImageRequestOperation.m @@ -228,10 +228,10 @@ static dispatch_queue_t image_request_operation_processing_queue() { return; } - dispatch_async(image_request_operation_processing_queue(), ^(void) { + dispatch_group_async(self.dispatchGroup, image_request_operation_processing_queue(), ^(void) { if (self.error) { if (failure) { - dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_group_async(self.dispatchGroup, self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ failure(self, self.error); }); } @@ -245,7 +245,7 @@ static dispatch_queue_t image_request_operation_processing_queue() { image = self.responseImage; - dispatch_async(self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_group_async(self.dispatchGroup, self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ success(self, image); }); } diff --git a/AFNetworking/AFJSONRequestOperation.m b/AFNetworking/AFJSONRequestOperation.m index 9046dd0..dacacd9 100644 --- a/AFNetworking/AFJSONRequestOperation.m +++ b/AFNetworking/AFJSONRequestOperation.m @@ -125,23 +125,23 @@ static dispatch_queue_t json_request_operation_processing_queue() { if (self.error) { if (failure) { - dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_group_async(self.dispatchGroup, self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ failure(self, self.error); }); } } else { - dispatch_async(json_request_operation_processing_queue(), ^(void) { + dispatch_group_async(self.dispatchGroup, json_request_operation_processing_queue(), ^(void) { id JSON = self.responseJSON; if (self.JSONError) { if (failure) { - dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_group_async(self.dispatchGroup, self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ failure(self, self.error); }); } } else { if (success) { - dispatch_async(self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_group_async(self.dispatchGroup, self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ success(self, JSON); }); } diff --git a/AFNetworking/AFPropertyListRequestOperation.m b/AFNetworking/AFPropertyListRequestOperation.m index ea9d216..e529a74 100644 --- a/AFNetworking/AFPropertyListRequestOperation.m +++ b/AFNetworking/AFPropertyListRequestOperation.m @@ -125,23 +125,23 @@ static dispatch_queue_t property_list_request_operation_processing_queue() { if (self.error) { if (failure) { - dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_group_async(self.dispatchGroup, self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ failure(self, self.error); }); } } else { - dispatch_async(property_list_request_operation_processing_queue(), ^(void) { + dispatch_group_async(self.dispatchGroup, property_list_request_operation_processing_queue(), ^(void) { id propertyList = self.responsePropertyList; if (self.propertyListError) { if (failure) { - dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_group_async(self.dispatchGroup, self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ failure(self, self.error); }); } } else { if (success) { - dispatch_async(self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_group_async(self.dispatchGroup, self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ success(self, propertyList); }); } diff --git a/AFNetworking/AFXMLRequestOperation.m b/AFNetworking/AFXMLRequestOperation.m index 79c5272..d4f4268 100644 --- a/AFNetworking/AFXMLRequestOperation.m +++ b/AFNetworking/AFXMLRequestOperation.m @@ -170,18 +170,18 @@ static dispatch_queue_t xml_request_operation_processing_queue() { return; } - dispatch_async(xml_request_operation_processing_queue(), ^(void) { + dispatch_group_async(self.dispatchGroup, xml_request_operation_processing_queue(), ^(void) { NSXMLParser *XMLParser = self.responseXMLParser; if (self.error) { if (failure) { - dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_group_async(self.dispatchGroup, self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ failure(self, self.error); }); } } else { if (success) { - dispatch_async(self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_group_async(self.dispatchGroup, self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ success(self, XMLParser); }); } From e47fc50903ba4700fafa2ff1d83eb14e242daf91 Mon Sep 17 00:00:00 2001 From: Patrick Hernandez Date: Sun, 8 Apr 2012 23:04:09 -0500 Subject: [PATCH 03/15] removing the .gitignore --- .gitignore | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index f9f28d5..0000000 --- a/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -.DS_Store -*.swp -*~.nib - -build/ - -*.pbxuser -*.perspective -*.perspectivev3 - -*.mode1v3 -*.mode2v3 - -xcuserdata \ No newline at end of file From 8b94ef8e442e56d5bd59e65421090d61008e001e Mon Sep 17 00:00:00 2001 From: Patrick Hernandez Date: Mon, 9 Apr 2012 00:19:28 -0500 Subject: [PATCH 04/15] Optimized how enqueueing operations works - Removed the NSBlockOperation as it was not longer needed for completion block to be fired appropriately - Added a safety call to setCompletionBlock in AFHTTPRequestOperation to ensure that dispatch_group_leave would be called --- AFNetworking/AFHTTPClient.m | 20 +++++++------------- AFNetworking/AFHTTPRequestOperation.m | 1 + 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/AFNetworking/AFHTTPClient.m b/AFNetworking/AFHTTPClient.m index a5e2b2c..3d51efb 100644 --- a/AFNetworking/AFHTTPClient.m +++ b/AFNetworking/AFHTTPClient.m @@ -517,16 +517,6 @@ static void AFReachabilityCallback(SCNetworkReachabilityRef __unused target, SCN { dispatch_group_t dispatchGroup = dispatch_group_create(); - NSBlockOperation *batchedOperation = [NSBlockOperation blockOperationWithBlock:^{ - if (completionBlock) { - dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{ - completionBlock(operations); - }); - } - }]; - - [self.operationQueue addOperation:batchedOperation]; - NSPredicate *finishedOperationPredicate = [NSPredicate predicateWithFormat:@"isFinished == YES"]; for (AFHTTPRequestOperation *operation in operations) { @@ -535,7 +525,7 @@ static void AFReachabilityCallback(SCNetworkReachabilityRef __unused target, SCN operation.completionBlock = ^{ if (progressBlock) { dispatch_group_async(dispatchGroup, dispatch_get_main_queue(), ^{ - progressBlock([[batchedOperation.dependencies filteredArrayUsingPredicate:finishedOperationPredicate] count], [batchedOperation.dependencies count]); + progressBlock([[operations filteredArrayUsingPredicate:finishedOperationPredicate] count], [operations count]); }); } @@ -543,11 +533,15 @@ static void AFReachabilityCallback(SCNetworkReachabilityRef __unused target, SCN originalCompletionBlock(); } }; - - [batchedOperation addDependency:operation]; [self enqueueHTTPRequestOperation:operation]; } + if (completionBlock) { + dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{ + completionBlock(operations); + }); + } + dispatch_release(dispatchGroup); } diff --git a/AFNetworking/AFHTTPRequestOperation.m b/AFNetworking/AFHTTPRequestOperation.m index cb96e36..c9f2dad 100644 --- a/AFNetworking/AFHTTPRequestOperation.m +++ b/AFNetworking/AFHTTPRequestOperation.m @@ -79,6 +79,7 @@ static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { self.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)]; self.dispatchSemaphore = dispatch_semaphore_create(1); + self.completionBlock = NULL; return self; } From dec3c9a03b3b69657ac04c3bd86444074d2c3e7d Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 10 Apr 2012 19:32:30 -0700 Subject: [PATCH 05/15] The cache policy set here was from the WRONG enum. So NSURLCacheStorgeNotAllowed has the value 2, which maps to NSURLRequestReturnCacheDataElseLoad. I'm not sure why this is here in the first place, but the correct enum is of the type NSURLRequestCachePolicy. --- AFNetworking/AFHTTPClient.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AFNetworking/AFHTTPClient.m b/AFNetworking/AFHTTPClient.m index 60b44a4..b304642 100644 --- a/AFNetworking/AFHTTPClient.m +++ b/AFNetworking/AFHTTPClient.m @@ -693,7 +693,7 @@ static inline NSString * AFMultipartFormFinalBoundary() { } NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:fileURL]; - [request setCachePolicy:NSURLCacheStorageNotAllowed]; + [request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData]; NSURLResponse *response = nil; NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:error]; From 1e78a5b2f976dc66db6673a98f4cb358dc65dc5e Mon Sep 17 00:00:00 2001 From: Patrick Hernandez Date: Wed, 11 Apr 2012 18:37:53 -0500 Subject: [PATCH 06/15] Fixed crash in special case for custom callback queues - Added a line for setting _successCallbackQueue to NULL when releasing the call back queue in the setter - Added a line for setting _failureCallbackQueue to NULL when releasing the call back queue in the setter --- AFNetworking/AFHTTPRequestOperation.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AFNetworking/AFHTTPRequestOperation.m b/AFNetworking/AFHTTPRequestOperation.m index 871cb18..5e1dce9 100644 --- a/AFNetworking/AFHTTPRequestOperation.m +++ b/AFNetworking/AFHTTPRequestOperation.m @@ -135,6 +135,7 @@ static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { if (successCallbackQueue != _successCallbackQueue) { if (_successCallbackQueue) { dispatch_release(_successCallbackQueue); + _successCallbackQueue = NULL; } if (successCallbackQueue) { @@ -148,6 +149,7 @@ static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { if (failureCallbackQueue != _failureCallbackQueue) { if (_failureCallbackQueue) { dispatch_release(_failureCallbackQueue); + _failureCallbackQueue = NULL; } if (failureCallbackQueue) { From ec3b9222887b574349676e027d64592cc88b9879 Mon Sep 17 00:00:00 2001 From: John Wu Date: Fri, 13 Apr 2012 11:04:13 -0700 Subject: [PATCH 07/15] since there is no guarantee that cancelling a request => success/fail block will not be called, you shouldn't nil out a request unless it corresponds to the correct URL. Essentially, this fixes the problem where images are sometimes not loaded. --- AFNetworking/UIImageView+AFNetworking.m | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/AFNetworking/UIImageView+AFNetworking.m b/AFNetworking/UIImageView+AFNetworking.m index 5310e71..341eec3 100644 --- a/AFNetworking/UIImageView+AFNetworking.m +++ b/AFNetworking/UIImageView+AFNetworking.m @@ -115,6 +115,7 @@ static char kAFImageRequestOperationObjectKey; [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { if ([[urlRequest URL] isEqual:[[self.af_imageRequestOperation request] URL]]) { self.image = responseObject; + self.af_imageRequestOperation = nil; } if (success) { @@ -123,13 +124,16 @@ static char kAFImageRequestOperationObjectKey; [[[self class] af_sharedImageCache] cacheImage:responseObject forRequest:urlRequest]; - self.af_imageRequestOperation = nil; + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if ([[urlRequest URL] isEqual:[[self.af_imageRequestOperation request] URL]]) { + self.af_imageRequestOperation = nil; + } + if (failure) { failure(operation.request, operation.response, error); } - self.af_imageRequestOperation = nil; }]; self.af_imageRequestOperation = requestOperation; From 3263f06edb9d8d48da7003867fe2accf1e2e4fa8 Mon Sep 17 00:00:00 2001 From: Patrick Hernandez Date: Sat, 14 Apr 2012 15:16:14 -0500 Subject: [PATCH 08/15] Fixed a leak of AFHTTPRequestOperation in setCompletionBlock: - Added a block object to reference self in the completion block - Added a pointer to the onceToken to be used in the completion block --- AFNetworking/AFHTTPRequestOperation.m | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/AFNetworking/AFHTTPRequestOperation.m b/AFNetworking/AFHTTPRequestOperation.m index c9f2dad..1b766c2 100644 --- a/AFNetworking/AFHTTPRequestOperation.m +++ b/AFNetworking/AFHTTPRequestOperation.m @@ -203,13 +203,16 @@ static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { } - (void)setCompletionBlock:(void (^)(void))block { + __block AFHTTPRequestOperation *blockSelf = self; + dispatch_once_t *blockOnceToken = &_onceToken; + [super setCompletionBlock:^{ if(block) { block(); } // Dispatch once is used to ensure that setting the block with this block will not cause multiple calls to 'dispatch_group_leave' - dispatch_once(&_onceToken, ^{ - dispatch_group_leave(self.dispatchGroup); + dispatch_once(blockOnceToken, ^{ + dispatch_group_leave(blockSelf.dispatchGroup); }); }]; } From da7d1c8c11829f9410f330ffb79e74d9bd93cb0f Mon Sep 17 00:00:00 2001 From: Mattt Thompson Date: Sat, 14 Apr 2012 21:42:18 -0700 Subject: [PATCH 09/15] [Issue #296] Dispatching image processing asynchronously to background queue --- AFNetworking/AFImageRequestOperation.m | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/AFNetworking/AFImageRequestOperation.m b/AFNetworking/AFImageRequestOperation.m index 39ecd52..a27c5b6 100644 --- a/AFNetworking/AFImageRequestOperation.m +++ b/AFNetworking/AFImageRequestOperation.m @@ -82,12 +82,17 @@ static dispatch_queue_t image_request_operation_processing_queue() { [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { if (success) { UIImage *image = responseObject; - if (imageProcessingBlock) { - image = imageProcessingBlock(image); + dispatch_async(image_request_operation_processing_queue(), ^(void) { + UIImage *processedImage = imageProcessingBlock(image); + + dispatch_async(dispatch_get_main_queue(), ^(void) { + success(operation.request, operation.response, processedImage); + }); + }); + } else { + success(operation.request, operation.response, image); } - - success(operation.request, operation.response, image); } } failure:^(AFHTTPRequestOperation *operation, NSError *error) { if (failure) { @@ -109,12 +114,17 @@ static dispatch_queue_t image_request_operation_processing_queue() { [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { if (success) { NSImage *image = responseObject; - if (imageProcessingBlock) { - image = imageProcessingBlock(image); + dispatch_async(image_request_operation_processing_queue(), ^(void) { + NSImage *processedImage = imageProcessingBlock(image); + + dispatch_async(dispatch_get_main_queue(), ^(void) { + success(operation.request, operation.response, processedImage); + }); + }); + } else { + success(operation.request, operation.response, image); } - - success(operation.request, operation.response, image); } } failure:^(AFHTTPRequestOperation *operation, NSError *error) { if (failure) { From 9adb586a82bba2592df1f40f3c8c73d192b3d0fd Mon Sep 17 00:00:00 2001 From: Mattt Thompson Date: Thu, 19 Apr 2012 10:31:45 -0500 Subject: [PATCH 10/15] [Issue #308] Fixing crash caused by attempting to cache invalid or nil image --- AFNetworking/UIImageView+AFNetworking.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/AFNetworking/UIImageView+AFNetworking.m b/AFNetworking/UIImageView+AFNetworking.m index 341eec3..ac1f708 100644 --- a/AFNetworking/UIImageView+AFNetworking.m +++ b/AFNetworking/UIImageView+AFNetworking.m @@ -172,7 +172,9 @@ static inline NSString * AFImageCacheKeyFromURLRequest(NSURLRequest *request) { - (void)cacheImage:(UIImage *)image forRequest:(NSURLRequest *)request { - [self setObject:image forKey:AFImageCacheKeyFromURLRequest(request)]; + if (image && request) { + [self setObject:image forKey:AFImageCacheKeyFromURLRequest(request)]; + } } @end From c0bdc5db95310317d0720b79b6ef4c1c2b48c1d0 Mon Sep 17 00:00:00 2001 From: "Charles T. Ahn" Date: Thu, 19 Apr 2012 13:17:56 -0700 Subject: [PATCH 11/15] Try-catch in Objective-C should not be used to recover from exceptions http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/Exceptions/Articles/ExceptionsAndCocoaFrameworks.html#//apple_ref/doc/uid/TP40009045-SW1 Relevant Quote: "The Cocoa frameworks are generally not exception-safe. The general pattern is that exceptions are reserved for programmer error only, and the program catching such an exception should quit soon afterwards." More discussion here: http://stackoverflow.com/questions/324284/how-to-throw-an-exception-in-objective-c-cocoa Given all this, prefer a crash on the background thread. --- AFNetworking/AFURLConnectionOperation.m | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/AFNetworking/AFURLConnectionOperation.m b/AFNetworking/AFURLConnectionOperation.m index fe520e2..f84674f 100644 --- a/AFNetworking/AFURLConnectionOperation.m +++ b/AFNetworking/AFURLConnectionOperation.m @@ -128,18 +128,9 @@ static inline BOOL AFStateTransitionIsValid(AFOperationState fromState, AFOperat + (void)networkRequestThreadEntryPoint:(id)__unused object { do { - NSAutoreleasePool *exceptionPool = [[NSAutoreleasePool alloc] init]; - NSException *caughtException = nil; - @try { - NSAutoreleasePool *runLoopPool = [[NSAutoreleasePool alloc] init]; - [[NSRunLoop currentRunLoop] run]; - [runLoopPool drain]; - } - @catch(NSException *e) { caughtException = e; } - if(caughtException) { - NSLog(NSLocalizedString(@"Unhandled exception on %@ networking thread: %@, userInfo: %@", nil), NSStringFromClass([self class]), caughtException, [caughtException userInfo]); - } - [exceptionPool drain]; + NSAutoreleasePool *runLoopPool = [[NSAutoreleasePool alloc] init]; + [[NSRunLoop currentRunLoop] run]; + [runLoopPool drain]; } while (YES); } From 3124db42cd6434f7c110251d2acd0b4ca377b38d Mon Sep 17 00:00:00 2001 From: Mattt Thompson Date: Mon, 23 Apr 2012 20:58:14 -0700 Subject: [PATCH 12/15] Stashing first attempt to simplify dispatching --- AFNetworking/AFHTTPClient.m | 50 +++++++++++++-------- AFNetworking/AFHTTPRequestOperation.m | 60 +------------------------- AFNetworking/AFImageRequestOperation.m | 6 +-- AFNetworking/AFJSONRequestOperation.m | 4 +- 4 files changed, 39 insertions(+), 81 deletions(-) diff --git a/AFNetworking/AFHTTPClient.m b/AFNetworking/AFHTTPClient.m index 75a2876..5fcb4e1 100644 --- a/AFNetworking/AFHTTPClient.m +++ b/AFNetworking/AFHTTPClient.m @@ -41,6 +41,14 @@ NSString * const AFNetworkingReachabilityDidChangeNotification = @"com.alamofire static NSString * const kAFMultipartFormLineDelimiter = @"\r\n"; // CRLF static NSString * const kAFMultipartFormBoundary = @"Boundary+0xAbCdEfGbOuNdArY"; +@interface AFBatchedOperation : NSBlockOperation +@property (readwrite, nonatomic, assign) dispatch_group_t dispatchGroup; +@end + +@implementation AFBatchedOperation +@synthesize dispatchGroup = _dispatchGroup; +@end + @interface AFMultipartFormData : NSObject { @private NSStringEncoding _stringEncoding; @@ -515,34 +523,40 @@ static void AFReachabilityCallback(SCNetworkReachabilityRef __unused target, SCN progressBlock:(void (^)(NSUInteger numberOfCompletedOperations, NSUInteger totalNumberOfOperations))progressBlock completionBlock:(void (^)(NSArray *operations))completionBlock { - dispatch_group_t dispatchGroup = dispatch_group_create(); + AFBatchedOperation *batchedOperation = [[[AFBatchedOperation alloc] init] autorelease]; + batchedOperation.dispatchGroup = dispatch_group_create(); + [batchedOperation addExecutionBlock:^{ + if (completionBlock) { + dispatch_group_notify(batchedOperation.dispatchGroup, dispatch_get_main_queue(), ^{ + completionBlock(operations); + }); + } + }]; NSPredicate *finishedOperationPredicate = [NSPredicate predicateWithFormat:@"isFinished == YES"]; for (AFHTTPRequestOperation *operation in operations) { AFCompletionBlock originalCompletionBlock = [[operation.completionBlock copy] autorelease]; - operation.dispatchGroup = dispatchGroup; operation.completionBlock = ^{ - if (progressBlock) { - dispatch_group_async(dispatchGroup, dispatch_get_main_queue(), ^{ + dispatch_group_async(batchedOperation.dispatchGroup, dispatch_get_main_queue(), ^{ + if (originalCompletionBlock) { + originalCompletionBlock(); + } + + if (progressBlock) { progressBlock([[operations filteredArrayUsingPredicate:finishedOperationPredicate] count], [operations count]); - }); - } - - if (originalCompletionBlock) { - originalCompletionBlock(); - } + } + + dispatch_group_leave(batchedOperation.dispatchGroup); + }); }; + + dispatch_group_enter(batchedOperation.dispatchGroup); + [batchedOperation addDependency:operation]; + [self enqueueHTTPRequestOperation:operation]; } - - if (completionBlock) { - dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{ - completionBlock(operations); - }); - } - - dispatch_release(dispatchGroup); + [self.operationQueue addOperation:batchedOperation]; } #pragma mark - diff --git a/AFNetworking/AFHTTPRequestOperation.m b/AFNetworking/AFHTTPRequestOperation.m index 0d399c7..3d61013 100644 --- a/AFNetworking/AFHTTPRequestOperation.m +++ b/AFNetworking/AFHTTPRequestOperation.m @@ -56,8 +56,7 @@ static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { @interface AFHTTPRequestOperation () @property (readwrite, nonatomic, retain) NSError *HTTPError; -@property (nonatomic) dispatch_once_t onceToken; -@property (atomic) dispatch_semaphore_t dispatchSemaphore; +@property (readwrite, nonatomic, assign) dispatch_semaphore_t dispatchSemaphore; @end @implementation AFHTTPRequestOperation @@ -67,10 +66,8 @@ static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { @synthesize successCallbackQueue = _successCallbackQueue; @synthesize failureCallbackQueue = _failureCallbackQueue; @synthesize dispatchGroup = _dispatchGroup; -@synthesize onceToken = _onceToken; @synthesize dispatchSemaphore = _dispatchSemaphore; - - (id)initWithRequest:(NSURLRequest *)request { self = [super initWithRequest:request]; if (!self) { @@ -98,17 +95,7 @@ static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { dispatch_release(_failureCallbackQueue); _failureCallbackQueue = NULL; } - - if (_dispatchGroup) { - dispatch_release(_dispatchGroup); - _dispatchGroup = NULL; - } - - if (_dispatchSemaphore) { - dispatch_release(_dispatchSemaphore); - _dispatchSemaphore = NULL; - } - + [super dealloc]; } @@ -176,49 +163,6 @@ static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { } } -- (void)setDispatchGroup:(dispatch_group_t)dispatchGroup { - dispatch_semaphore_wait(self.dispatchSemaphore, DISPATCH_TIME_FOREVER); - if (dispatchGroup != _dispatchGroup) { - if (_dispatchGroup) { - dispatch_group_leave(_dispatchGroup); - dispatch_release(_dispatchGroup); - _dispatchGroup = NULL; - } - - if (dispatchGroup) { - dispatch_retain(dispatchGroup); - _dispatchGroup = dispatchGroup; - dispatch_group_enter(_dispatchGroup); - } - } - dispatch_semaphore_signal(self.dispatchSemaphore); -} - -- (dispatch_group_t)dispatchGroup { - dispatch_semaphore_wait(self.dispatchSemaphore, DISPATCH_TIME_FOREVER); - if(_dispatchGroup == NULL) { - _dispatchGroup = dispatch_group_create(); - dispatch_group_enter(_dispatchGroup); - } - dispatch_semaphore_signal(self.dispatchSemaphore); - return _dispatchGroup; -} - -- (void)setCompletionBlock:(void (^)(void))block { - __block AFHTTPRequestOperation *blockSelf = self; - dispatch_once_t *blockOnceToken = &_onceToken; - - [super setCompletionBlock:^{ - if(block) { - block(); - } - // Dispatch once is used to ensure that setting the block with this block will not cause multiple calls to 'dispatch_group_leave' - dispatch_once(blockOnceToken, ^{ - dispatch_group_leave(blockSelf.dispatchGroup); - }); - }]; -} - - (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure { diff --git a/AFNetworking/AFImageRequestOperation.m b/AFNetworking/AFImageRequestOperation.m index a27c5b6..3ff2fd0 100644 --- a/AFNetworking/AFImageRequestOperation.m +++ b/AFNetworking/AFImageRequestOperation.m @@ -236,10 +236,10 @@ static dispatch_queue_t image_request_operation_processing_queue() { return; } - dispatch_group_async(self.dispatchGroup, image_request_operation_processing_queue(), ^(void) { + dispatch_async(image_request_operation_processing_queue(), ^(void) { if (self.error) { if (failure) { - dispatch_group_async(self.dispatchGroup, self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ failure(self, self.error); }); } @@ -253,7 +253,7 @@ static dispatch_queue_t image_request_operation_processing_queue() { image = self.responseImage; - dispatch_group_async(self.dispatchGroup, self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_async(self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ success(self, image); }); } diff --git a/AFNetworking/AFJSONRequestOperation.m b/AFNetworking/AFJSONRequestOperation.m index dacacd9..2f513c9 100644 --- a/AFNetworking/AFJSONRequestOperation.m +++ b/AFNetworking/AFJSONRequestOperation.m @@ -130,7 +130,7 @@ static dispatch_queue_t json_request_operation_processing_queue() { }); } } else { - dispatch_group_async(self.dispatchGroup, json_request_operation_processing_queue(), ^(void) { + dispatch_async(json_request_operation_processing_queue(), ^{ id JSON = self.responseJSON; if (self.JSONError) { @@ -141,7 +141,7 @@ static dispatch_queue_t json_request_operation_processing_queue() { } } else { if (success) { - dispatch_group_async(self.dispatchGroup, self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_async(self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ success(self, JSON); }); } From 8a93284ca46ef3df7f3853acec3285eeec0d5bb3 Mon Sep 17 00:00:00 2001 From: Mattt Thompson Date: Mon, 23 Apr 2012 21:14:27 -0700 Subject: [PATCH 13/15] Ah, the wonderful feeling of deleting significant chunks of code --- AFNetworking/AFHTTPClient.m | 31 +++++++------------ AFNetworking/AFHTTPRequestOperation.h | 5 --- AFNetworking/AFHTTPRequestOperation.m | 8 ++--- AFNetworking/AFJSONRequestOperation.m | 4 +-- AFNetworking/AFPropertyListRequestOperation.m | 8 ++--- AFNetworking/AFXMLRequestOperation.m | 6 ++-- 6 files changed, 23 insertions(+), 39 deletions(-) diff --git a/AFNetworking/AFHTTPClient.m b/AFNetworking/AFHTTPClient.m index 5fcb4e1..a97aec9 100644 --- a/AFNetworking/AFHTTPClient.m +++ b/AFNetworking/AFHTTPClient.m @@ -41,14 +41,6 @@ NSString * const AFNetworkingReachabilityDidChangeNotification = @"com.alamofire static NSString * const kAFMultipartFormLineDelimiter = @"\r\n"; // CRLF static NSString * const kAFMultipartFormBoundary = @"Boundary+0xAbCdEfGbOuNdArY"; -@interface AFBatchedOperation : NSBlockOperation -@property (readwrite, nonatomic, assign) dispatch_group_t dispatchGroup; -@end - -@implementation AFBatchedOperation -@synthesize dispatchGroup = _dispatchGroup; -@end - @interface AFMultipartFormData : NSObject { @private NSStringEncoding _stringEncoding; @@ -523,22 +515,23 @@ static void AFReachabilityCallback(SCNetworkReachabilityRef __unused target, SCN progressBlock:(void (^)(NSUInteger numberOfCompletedOperations, NSUInteger totalNumberOfOperations))progressBlock completionBlock:(void (^)(NSArray *operations))completionBlock { - AFBatchedOperation *batchedOperation = [[[AFBatchedOperation alloc] init] autorelease]; - batchedOperation.dispatchGroup = dispatch_group_create(); - [batchedOperation addExecutionBlock:^{ - if (completionBlock) { - dispatch_group_notify(batchedOperation.dispatchGroup, dispatch_get_main_queue(), ^{ + __block dispatch_group_t dispatchGroup = dispatch_group_create(); + dispatch_retain(dispatchGroup); + NSBlockOperation *batchedOperation = [NSBlockOperation blockOperationWithBlock:^{ + dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{ + if (completionBlock) { completionBlock(operations); - }); - } + } + }); + dispatch_release(dispatchGroup); }]; - + NSPredicate *finishedOperationPredicate = [NSPredicate predicateWithFormat:@"isFinished == YES"]; for (AFHTTPRequestOperation *operation in operations) { AFCompletionBlock originalCompletionBlock = [[operation.completionBlock copy] autorelease]; operation.completionBlock = ^{ - dispatch_group_async(batchedOperation.dispatchGroup, dispatch_get_main_queue(), ^{ + dispatch_group_async(dispatchGroup, dispatch_get_main_queue(), ^{ if (originalCompletionBlock) { originalCompletionBlock(); } @@ -547,11 +540,11 @@ static void AFReachabilityCallback(SCNetworkReachabilityRef __unused target, SCN progressBlock([[operations filteredArrayUsingPredicate:finishedOperationPredicate] count], [operations count]); } - dispatch_group_leave(batchedOperation.dispatchGroup); + dispatch_group_leave(dispatchGroup); }); }; - dispatch_group_enter(batchedOperation.dispatchGroup); + dispatch_group_enter(dispatchGroup); [batchedOperation addDependency:operation]; [self enqueueHTTPRequestOperation:operation]; diff --git a/AFNetworking/AFHTTPRequestOperation.h b/AFNetworking/AFHTTPRequestOperation.h index 7104c41..5aa8407 100644 --- a/AFNetworking/AFHTTPRequestOperation.h +++ b/AFNetworking/AFHTTPRequestOperation.h @@ -76,11 +76,6 @@ */ @property (nonatomic) dispatch_queue_t failureCallbackQueue; -/** - The dispatch group on which to call the completion/failure block - */ -@property (nonatomic) dispatch_group_t dispatchGroup; - /** A Boolean value determining whether or not the class can process the specified request. For example, `AFJSONRequestOperation` may check to make sure the content type was `application/json` or the URL path extension was `.json`. diff --git a/AFNetworking/AFHTTPRequestOperation.m b/AFNetworking/AFHTTPRequestOperation.m index 3d61013..b229fb7 100644 --- a/AFNetworking/AFHTTPRequestOperation.m +++ b/AFNetworking/AFHTTPRequestOperation.m @@ -56,7 +56,6 @@ static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { @interface AFHTTPRequestOperation () @property (readwrite, nonatomic, retain) NSError *HTTPError; -@property (readwrite, nonatomic, assign) dispatch_semaphore_t dispatchSemaphore; @end @implementation AFHTTPRequestOperation @@ -65,8 +64,6 @@ static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { @synthesize HTTPError = _HTTPError; @synthesize successCallbackQueue = _successCallbackQueue; @synthesize failureCallbackQueue = _failureCallbackQueue; -@synthesize dispatchGroup = _dispatchGroup; -@synthesize dispatchSemaphore = _dispatchSemaphore; - (id)initWithRequest:(NSURLRequest *)request { self = [super initWithRequest:request]; @@ -75,7 +72,6 @@ static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { } self.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)]; - self.dispatchSemaphore = dispatch_semaphore_create(1); self.completionBlock = NULL; return self; @@ -173,13 +169,13 @@ static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { if (self.error) { if (failure) { - dispatch_group_async(self.dispatchGroup, self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ failure(self, self.error); }); } } else { if (success) { - dispatch_group_async(self.dispatchGroup, self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_async(self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ success(self, self.responseData); }); } diff --git a/AFNetworking/AFJSONRequestOperation.m b/AFNetworking/AFJSONRequestOperation.m index 2f513c9..24ed254 100644 --- a/AFNetworking/AFJSONRequestOperation.m +++ b/AFNetworking/AFJSONRequestOperation.m @@ -125,7 +125,7 @@ static dispatch_queue_t json_request_operation_processing_queue() { if (self.error) { if (failure) { - dispatch_group_async(self.dispatchGroup, self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ failure(self, self.error); }); } @@ -135,7 +135,7 @@ static dispatch_queue_t json_request_operation_processing_queue() { if (self.JSONError) { if (failure) { - dispatch_group_async(self.dispatchGroup, self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ failure(self, self.error); }); } diff --git a/AFNetworking/AFPropertyListRequestOperation.m b/AFNetworking/AFPropertyListRequestOperation.m index e529a74..ea9d216 100644 --- a/AFNetworking/AFPropertyListRequestOperation.m +++ b/AFNetworking/AFPropertyListRequestOperation.m @@ -125,23 +125,23 @@ static dispatch_queue_t property_list_request_operation_processing_queue() { if (self.error) { if (failure) { - dispatch_group_async(self.dispatchGroup, self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ failure(self, self.error); }); } } else { - dispatch_group_async(self.dispatchGroup, property_list_request_operation_processing_queue(), ^(void) { + dispatch_async(property_list_request_operation_processing_queue(), ^(void) { id propertyList = self.responsePropertyList; if (self.propertyListError) { if (failure) { - dispatch_group_async(self.dispatchGroup, self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ failure(self, self.error); }); } } else { if (success) { - dispatch_group_async(self.dispatchGroup, self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_async(self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ success(self, propertyList); }); } diff --git a/AFNetworking/AFXMLRequestOperation.m b/AFNetworking/AFXMLRequestOperation.m index d4f4268..79c5272 100644 --- a/AFNetworking/AFXMLRequestOperation.m +++ b/AFNetworking/AFXMLRequestOperation.m @@ -170,18 +170,18 @@ static dispatch_queue_t xml_request_operation_processing_queue() { return; } - dispatch_group_async(self.dispatchGroup, xml_request_operation_processing_queue(), ^(void) { + dispatch_async(xml_request_operation_processing_queue(), ^(void) { NSXMLParser *XMLParser = self.responseXMLParser; if (self.error) { if (failure) { - dispatch_group_async(self.dispatchGroup, self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ failure(self, self.error); }); } } else { if (success) { - dispatch_group_async(self.dispatchGroup, self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ + dispatch_async(self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ success(self, XMLParser); }); } From bbacf3d7c6b3699fa62d0d8c6d4207f0efeceec6 Mon Sep 17 00:00:00 2001 From: Mattt Thompson Date: Tue, 24 Apr 2012 20:06:47 -0700 Subject: [PATCH 14/15] Removing unnecessary initialization of completionBlock in init --- AFNetworking/AFHTTPRequestOperation.m | 1 - 1 file changed, 1 deletion(-) diff --git a/AFNetworking/AFHTTPRequestOperation.m b/AFNetworking/AFHTTPRequestOperation.m index b229fb7..c1bff7d 100644 --- a/AFNetworking/AFHTTPRequestOperation.m +++ b/AFNetworking/AFHTTPRequestOperation.m @@ -72,7 +72,6 @@ static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { } self.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)]; - self.completionBlock = NULL; return self; } From 77837c48def096f89f1552b63c041a6259122fef Mon Sep 17 00:00:00 2001 From: Mattt Thompson Date: Tue, 24 Apr 2012 20:24:21 -0700 Subject: [PATCH 15/15] Run batch callbacks on success dispatch queue, falling back on main --- AFNetworking/AFHTTPClient.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AFNetworking/AFHTTPClient.m b/AFNetworking/AFHTTPClient.m index a97aec9..919c46f 100644 --- a/AFNetworking/AFHTTPClient.m +++ b/AFNetworking/AFHTTPClient.m @@ -531,7 +531,8 @@ static void AFReachabilityCallback(SCNetworkReachabilityRef __unused target, SCN for (AFHTTPRequestOperation *operation in operations) { AFCompletionBlock originalCompletionBlock = [[operation.completionBlock copy] autorelease]; operation.completionBlock = ^{ - dispatch_group_async(dispatchGroup, dispatch_get_main_queue(), ^{ + dispatch_queue_t queue = operation.successCallbackQueue ? operation.successCallbackQueue : dispatch_get_main_queue(); + dispatch_group_async(dispatchGroup, queue, ^{ if (originalCompletionBlock) { originalCompletionBlock(); }