From 0dbff8387b0f2137bff9e868790a14ef9718eb25 Mon Sep 17 00:00:00 2001 From: Jon Parise Date: Wed, 30 Jan 2013 12:25:22 -0800 Subject: [PATCH] Serialize calls to responseJSON using a lock. AFJSONRequestOperation's completion path calls `responseJSON` from a processing queue. Because `responseJSON` "lazily" deserializes the response data into a JSON object, it needs to be protected against concurrent access from other queues (threads). For example, `AFNetworkingOperationDidFinishNotification` is posted when the operation finishes but perhaps before that processing queue has finishing executing. Notification observers who also access `responseJSON` end up in a race with that queue that often leads to a crash. We reuse the existing lock from our AFURLConnectionOperation base class. --- AFNetworking/AFJSONRequestOperation.m | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/AFNetworking/AFJSONRequestOperation.m b/AFNetworking/AFJSONRequestOperation.m index bb893b5..c46a8f0 100644 --- a/AFNetworking/AFJSONRequestOperation.m +++ b/AFNetworking/AFJSONRequestOperation.m @@ -31,6 +31,10 @@ static dispatch_queue_t json_request_operation_processing_queue() { return af_json_request_operation_processing_queue; } +@interface AFURLConnectionOperation () +@property (readwrite, nonatomic, strong) NSRecursiveLock *lock; +@end + @interface AFJSONRequestOperation () @property (readwrite, nonatomic, strong) id responseJSON; @property (readwrite, nonatomic, strong) NSError *JSONError; @@ -61,6 +65,7 @@ static dispatch_queue_t json_request_operation_processing_queue() { - (id)responseJSON { + [self.lock lock]; if (!_responseJSON && [self.responseData length] > 0 && [self isFinished] && !self.JSONError) { NSError *error = nil; @@ -77,6 +82,7 @@ static dispatch_queue_t json_request_operation_processing_queue() { self.JSONError = error; } + [self.lock unlock]; return _responseJSON; }