I am using GCDAsyncSocket
(CocoaAsyncSocket
) for the socket communication in my app. Due to the asynchronous nature of GCDAsyncSocket
, my network request (submitMessage
below) is decoupled from the callback block that runs when data is received (socket:didReadData
).
- (void)submitMessage:(NSDictionary *)messageObject onCompletion:(completionBlock)block {
...
[_socket writeData:requestData withTimeout:self.timeout tag:0];
[_socket readDataToLength:4 withTimeout:self.timeout tag:TAG_HEADER];
}
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
...
NSDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
if (self.completionBlock != nil)
self.completionBlock(responseObject);
}
}
This approach works fine for one-off exchanges. But there are some cases when I need to post a request, then using the received data, post another request. I can't get this to work properly. Basically, I need something like this:
[self submitMessage:request1 onCompletion:^(NSDictionary *response1) {
(...callback 1...)
}];
[self submitMessage:request2 onCompletion:^(NSDictionary *response2) {
(...callback 2...)
}];
}];
or
[self submitMessage:request1 onCompletion:^(NSDictionary *response1) {
(...callback 1...)
}];
[self submitMessage:request2 onCompletion:^(NSDictionary *response2) {
(...callback 2...)
}];
where the order is strictly request1 - callback1 - request2 - callback2.
So the question is, how can I block the second request to run after the callback of the first request? Would GCD
(dispatch_sync
?) be the way to go?
Edit
I ended up using a solution similar to what @tigloo suggested (hence accepting his answer), but using NSCondition
instead of GCD
(if anyone's interested in details, I followed this great discussion). I am already running multiple threads (UI in main, high-level socket comms in another thread, and the socket operations in a third thread). Setting a class property and using NSCondition
to lock the GCDAsyncSocket
delegate until the response arrive seems the cleanest approach.