diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 304fb17cca5..48f4514a06f 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -157,10 +157,10 @@ extern id const kGRPCTrailersKey; - (void)receivedInitialMetadata:(NSDictionary *)initialMetadata; /** - * Issued when a message is received from the server. The message may be raw data from the server - * (when using \a GRPCCall2 directly) or deserialized proto object (when using \a ProtoRPC). + * Issued when a message is received from the server. The message is the raw data received from the + * server, with decompression and without proto deserialization. */ -- (void)receivedMessage:(id)message; +- (void)receivedRawMessage:(id)message; /** * Issued when a call finished. If the call finished successfully, \a error is nil and \a diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 36cb71399ca..eb9b21eccb0 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -236,9 +236,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)issueMessage:(id)message { id handler = self->_handler; - if ([handler respondsToSelector:@selector(receivedMessage:)]) { + if ([handler respondsToSelector:@selector(receivedRawMessage:)]) { dispatch_async(handler.dispatchQueue, ^{ - [handler receivedMessage:message]; + [handler receivedRawMessage:message]; }); } } diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index a045ef10a6c..d20098ce8c9 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -23,6 +23,39 @@ @class GPBMessage; +/** An object can implement this protocol to receive responses from server from a call. */ +@protocol GRPCProtoResponseHandler + +@optional + +/** Issued when initial metadata is received from the server. */ +- (void)receivedInitialMetadata:(NSDictionary *)initialMetadata; + +/** + * Issued when a message is received from the server. The message is the deserialized proto object. + */ +- (void)receivedProtoMessage:(id)message; + +/** + * Issued when a call finished. If the call finished successfully, \a error is nil and \a + * trainingMetadata consists any trailing metadata received from the server. Otherwise, \a error + * is non-nil and contains the corresponding error information, including gRPC error codes and + * error descriptions. + */ +- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error; + +@required + +/** + * All the responses must be issued to a user-provided dispatch queue. This property specifies the + * dispatch queue to be used for issuing the notifications. A serial queue should be provided if + * the order of responses (initial metadata, message, message, ..., message, trailing metadata) + * needs to be maintained. + */ +@property(atomic, readonly) dispatch_queue_t dispatchQueue; + +@end + /** A unary-request RPC call with Protobuf. */ @interface GRPCUnaryProtoCall : NSObject @@ -36,7 +69,7 @@ */ - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions message:(GPBMessage *)message - responseHandler:(id)handler + responseHandler:(id)handler callOptions:(GRPCCallOptions *)callOptions responseClass:(Class)responseClass NS_DESIGNATED_INITIALIZER; @@ -57,7 +90,7 @@ * returned to users by methods of the generated service. */ - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions - responseHandler:(id)handler + responseHandler:(id)handler callOptions:(GRPCCallOptions *)callOptions responseClass:(Class)responseClass NS_DESIGNATED_INITIALIZER; diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 957d6365341..7a57affbf15 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -33,7 +33,7 @@ - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions message:(GPBMessage *)message - responseHandler:(id)handler + responseHandler:(id)handler callOptions:(GRPCCallOptions *)callOptions responseClass:(Class)responseClass { if ((self = [super init])) { @@ -60,7 +60,7 @@ @implementation GRPCStreamingProtoCall { GRPCRequestOptions *_requestOptions; - id _handler; + id _handler; GRPCCallOptions *_callOptions; Class _responseClass; @@ -69,7 +69,7 @@ } - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions - responseHandler:(id)handler + responseHandler:(id)handler callOptions:(GRPCCallOptions *)callOptions responseClass:(Class)responseClass { if ((self = [super init])) { @@ -98,16 +98,18 @@ _call = nil; } if (_handler) { - id handler = _handler; - dispatch_async(handler.dispatchQueue, ^{ - [handler closedWithTrailingMetadata:nil - error:[NSError errorWithDomain:kGRPCErrorDomain - code:GRPCErrorCodeCancelled - userInfo:@{ - NSLocalizedDescriptionKey : - @"Canceled by app" - }]]; - }); + id handler = _handler; + if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + dispatch_async(handler.dispatchQueue, ^{ + [handler closedWithTrailingMetadata:nil + error:[NSError errorWithDomain:kGRPCErrorDomain + code:GRPCErrorCodeCancelled + userInfo:@{ + NSLocalizedDescriptionKey : + @"Canceled by app" + }]]; + }); + } _handler = nil; } }); @@ -136,27 +138,33 @@ - (void)receivedInitialMetadata:(NSDictionary *)initialMetadata { if (_handler) { - id handler = _handler; - dispatch_async(handler.dispatchQueue, ^{ - [handler receivedInitialMetadata:initialMetadata]; - }); + id handler = _handler; + if ([handler respondsToSelector:@selector(initialMetadata:)]) { + dispatch_async(handler.dispatchQueue, ^{ + [handler receivedInitialMetadata:initialMetadata]; + }); + } } } -- (void)receivedMessage:(NSData *)message { +- (void)receivedRawMessage:(NSData *)message { if (_handler) { - id handler = _handler; + id handler = _handler; NSError *error = nil; id parsed = [_responseClass parseFromData:message error:&error]; if (parsed) { - dispatch_async(handler.dispatchQueue, ^{ - [handler receivedMessage:parsed]; - }); + if ([handler respondsToSelector:@selector(receivedProtoMessage:)]) { + dispatch_async(handler.dispatchQueue, ^{ + [handler receivedProtoMessage:parsed]; + }); + } } else { - dispatch_async(handler.dispatchQueue, ^{ - [handler closedWithTrailingMetadata:nil error:error]; - }); - handler = nil; + if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + dispatch_async(handler.dispatchQueue, ^{ + [handler closedWithTrailingMetadata:nil error:error]; + }); + } + _handler = nil; [_call cancel]; _call = nil; } @@ -165,16 +173,16 @@ - (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { if (_handler) { - id handler = _handler; - dispatch_async(handler.dispatchQueue, ^{ - [handler closedWithTrailingMetadata:trailingMetadata error:error]; - }); + id handler = _handler; + if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + dispatch_async(handler.dispatchQueue, ^{ + [handler closedWithTrailingMetadata:trailingMetadata error:error]; + }); + } _handler = nil; } - if (_call) { - [_call cancel]; - _call = nil; - } + [_call cancel]; + _call = nil; } - (dispatch_queue_t)dispatchQueue { diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index 8a4eddb1b70..f961b6a86fd 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -120,7 +120,7 @@ static GRPCProtoMethod *kFullDuplexCallMethod; } } -- (void)receivedMessage:(id)message { +- (void)receivedProtoMessage:(id)message { if (_messageCallback) { _messageCallback(message); } diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index 0835ff909f5..11d4b95663a 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -75,7 +75,7 @@ BOOL isRemoteInteropTest(NSString *host) { } // Convenience class to use blocks as callbacks -@interface InteropTestsBlockCallbacks : NSObject +@interface InteropTestsBlockCallbacks : NSObject - (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback messageCallback:(void (^)(id))messageCallback @@ -108,7 +108,7 @@ BOOL isRemoteInteropTest(NSString *host) { } } -- (void)receivedMessage:(id)message { +- (void)receivedProtoMessage:(id)message { if (_messageCallback) { _messageCallback(message); }