Merge pull request #1 from jcanizales/import-ios-library

Imports Objective-C library
pull/571/head
Jorge Canizales 10 years ago
commit 2aee4b26a8
  1. 18
      src/objective-c/.gitignore
  2. 57
      src/objective-c/GRPCClient/GRPCCall.h
  3. 373
      src/objective-c/GRPCClient/GRPCCall.m
  4. 15
      src/objective-c/GRPCClient/GRPCMethodName.h
  5. 14
      src/objective-c/GRPCClient/GRPCMethodName.m
  6. 4
      src/objective-c/GRPCClient/README.md
  7. 17
      src/objective-c/GRPCClient/private/GRPCChannel.h
  8. 32
      src/objective-c/GRPCClient/private/GRPCChannel.m
  9. 21
      src/objective-c/GRPCClient/private/GRPCCompletionQueue.h
  10. 73
      src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
  11. 48
      src/objective-c/GRPCClient/private/GRPCDelegateWrapper.h
  12. 87
      src/objective-c/GRPCClient/private/GRPCDelegateWrapper.m
  13. 7
      src/objective-c/GRPCClient/private/GRPCMethodName+HTTP2Encoding.h
  14. 11
      src/objective-c/GRPCClient/private/GRPCMethodName+HTTP2Encoding.m
  15. 8
      src/objective-c/GRPCClient/private/NSData+GRPC.h
  16. 53
      src/objective-c/GRPCClient/private/NSData+GRPC.m
  17. 7
      src/objective-c/GRPCClient/private/NSDictionary+GRPC.h
  18. 23
      src/objective-c/GRPCClient/private/NSDictionary+GRPC.m
  19. 41
      src/objective-c/GRPCClient/private/NSError+GRPC.h
  20. 18
      src/objective-c/GRPCClient/private/NSError+GRPC.m
  21. 3
      src/objective-c/README.md
  22. 40
      src/objective-c/RxLibrary/GRXImmediateWriter.h
  23. 132
      src/objective-c/RxLibrary/GRXImmediateWriter.m
  24. 27
      src/objective-c/RxLibrary/GRXWriteable.h
  25. 33
      src/objective-c/RxLibrary/GRXWriteable.m
  26. 33
      src/objective-c/RxLibrary/GRXWriter+Immediate.h
  27. 31
      src/objective-c/RxLibrary/GRXWriter+Immediate.m
  28. 9
      src/objective-c/RxLibrary/GRXWriter+Transformations.h
  29. 14
      src/objective-c/RxLibrary/GRXWriter+Transformations.m
  30. 94
      src/objective-c/RxLibrary/GRXWriter.h
  31. 79
      src/objective-c/RxLibrary/GRXWriter.m
  32. 18
      src/objective-c/RxLibrary/NSEnumerator+GRXUtil.h
  33. 21
      src/objective-c/RxLibrary/NSEnumerator+GRXUtil.m
  34. 8
      src/objective-c/RxLibrary/README.md
  35. 12
      src/objective-c/RxLibrary/RxLibrary.podspec
  36. 9
      src/objective-c/RxLibrary/private/GRXNSBlockEnumerator.h
  37. 28
      src/objective-c/RxLibrary/private/GRXNSBlockEnumerator.m
  38. 10
      src/objective-c/RxLibrary/private/GRXNSFastEnumerator.h
  39. 55
      src/objective-c/RxLibrary/private/GRXNSFastEnumerator.m
  40. 8
      src/objective-c/RxLibrary/private/GRXNSScalarEnumerator.h
  41. 24
      src/objective-c/RxLibrary/private/GRXNSScalarEnumerator.m
  42. 7
      src/objective-c/RxLibrary/transformations/GRXMappingWriter.h
  43. 30
      src/objective-c/RxLibrary/transformations/GRXMappingWriter.m
  44. 12
      src/objective-c/examples/Sample/Podfile
  45. 14
      src/objective-c/examples/Sample/Podfile.lock
  46. 1
      src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXImmediateWriter.h
  47. 1
      src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXWriteable.h
  48. 1
      src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXWriter+Immediate.h
  49. 1
      src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXWriter+Transformations.h
  50. 1
      src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXWriter.h
  51. 1
      src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/NSEnumerator+GRXUtil.h
  52. 12
      src/objective-c/examples/Sample/Pods/Local Podspecs/RxLibrary.podspec
  53. 14
      src/objective-c/examples/Sample/Pods/Manifest.lock
  54. 2568
      src/objective-c/examples/Sample/Pods/Pods.xcodeproj/project.pbxproj
  55. 5
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-RxLibrary/Pods-RxLibrary-Private.xcconfig
  56. 5
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-RxLibrary/Pods-RxLibrary-dummy.m
  57. 5
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-RxLibrary/Pods-RxLibrary-prefix.pch
  58. 0
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-RxLibrary/Pods-RxLibrary.xcconfig
  59. 5
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-RxLibrary/Pods-Sample-RxLibrary-Private.xcconfig
  60. 5
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-RxLibrary/Pods-Sample-RxLibrary-dummy.m
  61. 5
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-RxLibrary/Pods-Sample-RxLibrary-prefix.pch
  62. 0
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-RxLibrary/Pods-Sample-RxLibrary.xcconfig
  63. 3
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-acknowledgements.markdown
  64. 29
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-acknowledgements.plist
  65. 5
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-dummy.m
  66. 14
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-environment.h
  67. 74
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-resources.sh
  68. 6
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample.debug.xcconfig
  69. 6
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample.release.xcconfig
  70. 5
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary-Private.xcconfig
  71. 5
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary-dummy.m
  72. 5
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary-prefix.pch
  73. 0
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary.xcconfig
  74. 3
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-acknowledgements.markdown
  75. 29
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-acknowledgements.plist
  76. 5
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-dummy.m
  77. 14
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-environment.h
  78. 74
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-resources.sh
  79. 6
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests.debug.xcconfig
  80. 6
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests.release.xcconfig
  81. 3
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown
  82. 29
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-acknowledgements.plist
  83. 5
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-dummy.m
  84. 14
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-environment.h
  85. 74
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-resources.sh
  86. 6
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods.debug.xcconfig
  87. 6
      src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods.release.xcconfig
  88. 2
      src/objective-c/examples/Sample/README.md
  89. 955
      src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj
  90. 7
      src/objective-c/examples/Sample/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  91. 10
      src/objective-c/examples/Sample/Sample.xcworkspace/contents.xcworkspacedata
  92. 17
      src/objective-c/examples/Sample/Sample/AppDelegate.h
  93. 45
      src/objective-c/examples/Sample/Sample/AppDelegate.m
  94. 41
      src/objective-c/examples/Sample/Sample/Base.lproj/LaunchScreen.xib
  95. 25
      src/objective-c/examples/Sample/Sample/Base.lproj/Main.storyboard
  96. 68
      src/objective-c/examples/Sample/Sample/Images.xcassets/AppIcon.appiconset/Contents.json
  97. 47
      src/objective-c/examples/Sample/Sample/Info.plist
  98. 15
      src/objective-c/examples/Sample/Sample/ViewController.h
  99. 27
      src/objective-c/examples/Sample/Sample/ViewController.m
  100. 16
      src/objective-c/examples/Sample/Sample/main.m
  101. Some files were not shown because too many files have changed in this diff Show More

@ -0,0 +1,18 @@
# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate

@ -0,0 +1,57 @@
#import <Foundation/Foundation.h>
#import <RxLibrary/GRXWriter.h>
@class GRPCMethodName;
@class GRPCCall;
// The gRPC protocol is an RPC protocol on top of HTTP2.
//
// While the most common type of RPC receives only one request message and
// returns only one response message, the protocol also supports RPCs that
// return multiple individual messages in a streaming fashion, RPCs that
// accept a stream of request messages, or RPCs with both streaming requests
// and responses.
//
// Conceptually, each gRPC call consists of a bidirectional stream of binary
// messages, with RPCs of the "non-streaming type" sending only one message in
// the corresponding direction (the protocol doesn't make any distinction).
//
// Each RPC uses a different HTTP2 stream, and thus multiple simultaneous RPCs
// can be multiplexed transparently on the same TCP connection.
@interface GRPCCall : NSObject<GRXWriter>
// These HTTP2 headers will be passed to the server as part of this call. Each
// HTTP2 header is a name-value pair with string names and either string or binary values.
// The passed dictionary has to use NSString keys, corresponding to the header names. The
// value associated to each can be a NSString object or a NSData object. E.g.:
//
// call.requestMetadata = @{
// @"Authorization": @"Bearer ...",
// @"SomeBinaryHeader": someData
// };
//
// After the call is started, modifying this won't have any effect.
@property(nonatomic, readwrite) NSMutableDictionary *requestMetadata;
// This isn't populated until the first event is delivered to the handler.
@property(atomic, readonly) NSDictionary *responseMetadata;
// The request writer has to write NSData objects into the provided Writeable. The server will
// receive each of those separately and in order.
// A gRPC call might not complete until the request writer finishes. On the other hand, the
// request finishing doesn't necessarily make the call to finish, as the server might continue
// sending messages to the response side of the call indefinitely (depending on the semantics of
// the specific remote method called).
// To finish a call right away, invoke cancel.
- (instancetype)initWithHost:(NSString *)host
method:(GRPCMethodName *)method
requestsWriter:(id<GRXWriter>)requestsWriter NS_DESIGNATED_INITIALIZER;
// Finishes the request side of this call, notifies the server that the RPC
// should be cancelled, and finishes the response side of the call with an error
// of code CANCELED.
- (void)cancel;
// TODO(jcanizales): Let specify a deadline. As a category of GRXWriter?
@end

@ -0,0 +1,373 @@
#import "GRPCCall.h"
#include <grpc.h>
#include <support/time.h>
#import "GRPCMethodName.h"
#import "private/GRPCChannel.h"
#import "private/GRPCCompletionQueue.h"
#import "private/GRPCDelegateWrapper.h"
#import "private/GRPCMethodName+HTTP2Encoding.h"
#import "private/NSData+GRPC.h"
#import "private/NSDictionary+GRPC.h"
#import "private/NSError+GRPC.h"
// A grpc_call_error represents a precondition failure when invoking the
// grpc_call_* functions. If one ever happens, it's a bug in this library.
//
// TODO(jcanizales): Can an application shut down gracefully when a thread other
// than the main one throws an exception?
static void AssertNoErrorInCall(grpc_call_error error) {
if (error != GRPC_CALL_OK) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:@"Precondition of grpc_call_* not met."
userInfo:nil];
}
}
@interface GRPCCall () <GRXWriteable>
// Makes it readwrite.
@property(atomic, strong) NSDictionary *responseMetadata;
@end
// The following methods of a C gRPC call object aren't reentrant, and thus
// calls to them must be serialized:
// - add_metadata
// - invoke
// - start_write
// - writes_done
// - start_read
// - destroy
// The first four are called as part of responding to client commands, but
// start_read we want to call as soon as we're notified that the RPC was
// successfully established (which happens concurrently in the network queue).
// Serialization is achieved by using a private serial queue to operate the
// call object.
// Because add_metadata and invoke are called and return successfully before
// any of the other methods is called, they don't need to use the queue.
//
// Furthermore, start_write and writes_done can only be called after the
// WRITE_ACCEPTED event for any previous write is received. This is achieved by
// pausing the requests writer immediately every time it writes a value, and
// resuming it again when WRITE_ACCEPTED is received.
//
// Similarly, start_read can only be called after the READ event for any
// previous read is received. This is easier to enforce, as we're writing the
// received messages into the writeable: start_read is enqueued once upon receiving
// the CLIENT_METADATA_READ event, and then once after receiving each READ
// event.
@implementation GRPCCall {
dispatch_queue_t _callQueue;
grpc_call *_gRPCCall;
dispatch_once_t _callAlreadyInvoked;
GRPCChannel *_channel;
GRPCCompletionQueue *_completionQueue;
// The C gRPC library has less guarantees on the ordering of events than we
// do. Particularly, in the face of errors, there's no ordering guarantee at
// all. This wrapper over our actual writeable ensures thread-safety and
// correct ordering.
GRPCDelegateWrapper *_responseWriteable;
id<GRXWriter> _requestWriter;
}
@synthesize state = _state;
- (instancetype)init {
return [self initWithHost:nil method:nil requestsWriter:nil];
}
// Designated initializer
- (instancetype)initWithHost:(NSString *)host
method:(GRPCMethodName *)method
requestsWriter:(id<GRXWriter>)requestWriter {
if (!host || !method) {
[NSException raise:NSInvalidArgumentException format:@"Neither host nor method can be nil."];
}
// TODO(jcanizales): Throw if the requestWriter was already started.
if ((self = [super init])) {
static dispatch_once_t initialization;
dispatch_once(&initialization, ^{
grpc_init();
});
_completionQueue = [GRPCCompletionQueue completionQueue];
_channel = [GRPCChannel channelToHost:host];
_gRPCCall = grpc_channel_create_call_old(_channel.unmanagedChannel,
method.HTTP2Path.UTF8String,
host.UTF8String,
gpr_inf_future);
// Serial queue to invoke the non-reentrant methods of the grpc_call object.
_callQueue = dispatch_queue_create("org.grpc.call", NULL);
_requestWriter = requestWriter;
}
return self;
}
#pragma mark Finish
- (void)finishWithError:(NSError *)errorOrNil {
_requestWriter.state = GRXWriterStateFinished;
_requestWriter = nil;
if (errorOrNil) {
[_responseWriteable cancelWithError:errorOrNil];
} else {
[_responseWriteable enqueueSuccessfulCompletion];
}
}
- (void)cancelCall {
// Can be called from any thread, any number of times.
AssertNoErrorInCall(grpc_call_cancel(_gRPCCall));
}
- (void)cancel {
[self finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeCancelled
userInfo:nil]];
[self cancelCall];
}
- (void)dealloc {
grpc_call *gRPCCall = _gRPCCall;
dispatch_async(_callQueue, ^{
grpc_call_destroy(gRPCCall);
});
}
#pragma mark Read messages
// Only called from the call queue.
// The handler will be called from the network queue.
- (void)startReadWithHandler:(GRPCEventHandler)handler {
AssertNoErrorInCall(grpc_call_start_read_old(_gRPCCall, (__bridge_retained void *)handler));
}
// Called initially from the network queue once response headers are received,
// then "recursively" from the responseWriteable queue after each response from the
// server has been written.
// If the call is currently paused, this is a noop. Restarting the call will invoke this
// method.
// TODO(jcanizales): Rename to readResponseIfNotPaused.
- (void)startNextRead {
if (self.state == GRXWriterStatePaused) {
return;
}
__weak GRPCCall *weakSelf = self;
__weak GRPCDelegateWrapper *weakWriteable = _responseWriteable;
dispatch_async(_callQueue, ^{
[weakSelf startReadWithHandler:^(grpc_event *event) {
if (!event->data.read) {
// No more responses from the server.
return;
}
NSData *data = [NSData grpc_dataWithByteBuffer:event->data.read];
if (!data) {
// The app doesn't have enough memory to hold the server response. We
// don't want to throw, because the app shouldn't crash for a behavior
// that's on the hands of any server to have. Instead we finish and ask
// the server to cancel.
//
// TODO(jcanizales): No canonical code is appropriate for this situation
// (because it's just a client problem). Use another domain and an
// appropriately-documented code.
[weakSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeInternal
userInfo:nil]];
[weakSelf cancelCall];
return;
}
[weakWriteable enqueueMessage:data completionHandler:^{
[weakSelf startNextRead];
}];
}];
});
}
#pragma mark Send headers
- (void)addHeaderWithName:(NSString *)name binaryValue:(NSData *)value {
grpc_metadata metadata;
// Safe to discard const qualifiers; we're not going to modify the contents.
metadata.key = (char *)name.UTF8String;
metadata.value = (char *)value.bytes;
metadata.value_length = value.length;
grpc_call_add_metadata_old(_gRPCCall, &metadata, 0);
}
- (void)addHeaderWithName:(NSString *)name ASCIIValue:(NSString *)value {
grpc_metadata metadata;
// Safe to discard const qualifiers; we're not going to modify the contents.
metadata.key = (char *)name.UTF8String;
metadata.value = (char *)value.UTF8String;
// The trailing \0 isn't encoded in HTTP2.
metadata.value_length = value.length;
grpc_call_add_metadata_old(_gRPCCall, &metadata, 0);
}
// TODO(jcanizales): Rename to commitHeaders.
- (void)sendHeaders:(NSDictionary *)metadata {
for (NSString *name in metadata) {
id value = metadata[name];
if ([value isKindOfClass:[NSData class]]) {
[self addHeaderWithName:name binaryValue:value];
} else if ([value isKindOfClass:[NSString class]]) {
[self addHeaderWithName:name ASCIIValue:value];
}
}
}
#pragma mark GRXWriteable implementation
// Only called from the call queue. The error handler will be called from the
// network queue if the write didn't succeed.
- (void)writeMessage:(NSData *)message withErrorHandler:(void (^)())errorHandler {
__weak GRPCCall *weakSelf = self;
GRPCEventHandler resumingHandler = ^(grpc_event *event) {
if (event->data.write_accepted != GRPC_OP_OK) {
errorHandler();
}
// Resume the request writer (even in the case of error).
// TODO(jcanizales): No need to do it in the case of errors anymore?
GRPCCall *strongSelf = weakSelf;
if (strongSelf) {
strongSelf->_requestWriter.state = GRXWriterStateStarted;
}
};
grpc_byte_buffer *buffer = message.grpc_byteBuffer;
AssertNoErrorInCall(grpc_call_start_write_old(_gRPCCall,
buffer,
(__bridge_retained void *)resumingHandler,
0));
grpc_byte_buffer_destroy(buffer);
}
- (void)didReceiveValue:(id)value {
// TODO(jcanizales): Throw/assert if value isn't NSData.
// Pause the input and only resume it when the C layer notifies us that writes
// can proceed.
_requestWriter.state = GRXWriterStatePaused;
__weak GRPCCall *weakSelf = self;
dispatch_async(_callQueue, ^{
[weakSelf writeMessage:value withErrorHandler:^{
[weakSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeInternal
userInfo:nil]];
}];
});
}
// Only called from the call queue. The error handler will be called from the
// network queue if the requests stream couldn't be closed successfully.
- (void)finishRequestWithErrorHandler:(void (^)())errorHandler {
GRPCEventHandler handler = ^(grpc_event *event) {
if (event->data.finish_accepted != GRPC_OP_OK) {
errorHandler();
}
};
AssertNoErrorInCall(grpc_call_writes_done_old(_gRPCCall, (__bridge_retained void *)handler));
}
- (void)didFinishWithError:(NSError *)errorOrNil {
if (errorOrNil) {
[self cancel];
} else {
__weak GRPCCall *weakSelf = self;
dispatch_async(_callQueue, ^{
[weakSelf finishRequestWithErrorHandler:^{
[weakSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeInternal
userInfo:nil]];
}];
});
}
}
#pragma mark Invoke
// Both handlers will eventually be called, from the network queue. Writes can start immediately
// after this.
// The first one (metadataHandler), when the response headers are received.
// The second one (completionHandler), whenever the RPC finishes for any reason.
- (void)invokeCallWithMetadataHandler:(GRPCEventHandler)metadataHandler
completionHandler:(GRPCEventHandler)completionHandler {
AssertNoErrorInCall(grpc_call_invoke_old(_gRPCCall,
_completionQueue.unmanagedQueue,
(__bridge_retained void *)metadataHandler,
(__bridge_retained void *)completionHandler,
0));
}
- (void)invokeCall {
__weak GRPCCall *weakSelf = self;
[self invokeCallWithMetadataHandler:^(grpc_event *event) {
// Response metadata received.
// TODO(jcanizales): Name the type of event->data.client_metadata_read
// in the C library so one can actually pass the object to a method.
grpc_metadata *entries = event->data.client_metadata_read.elements;
size_t count = event->data.client_metadata_read.count;
GRPCCall *strongSelf = weakSelf;
if (strongSelf) {
strongSelf.responseMetadata = [NSDictionary grpc_dictionaryFromMetadata:entries
count:count];
[strongSelf startNextRead];
}
} completionHandler:^(grpc_event *event) {
// TODO(jcanizales): Merge HTTP2 trailers into response metadata.
[weakSelf finishWithError:[NSError grpc_errorFromStatus:&event->data.finished]];
}];
// Now that the RPC has been initiated, request writes can start.
[_requestWriter startWithWriteable:self];
}
#pragma mark GRXWriter implementation
- (void)startWithWriteable:(id<GRXWriteable>)writeable {
// The following produces a retain cycle self:_responseWriteable:self, which is only
// broken when didFinishWithError: is sent to the wrapped writeable.
// Care is taken not to retain self strongly in any of the blocks used in
// the implementation of GRPCCall, so that the life of the instance is
// determined by this retain cycle.
_responseWriteable = [[GRPCDelegateWrapper alloc] initWithWriteable:writeable writer:self];
[self sendHeaders:_requestMetadata];
[self invokeCall];
}
- (void)setState:(GRXWriterState)newState {
// Manual transitions are only allowed from the started or paused states.
if (_state == GRXWriterStateNotStarted || _state == GRXWriterStateFinished) {
return;
}
switch (newState) {
case GRXWriterStateFinished:
_state = newState;
// Per GRXWriter's contract, setting the state to Finished manually
// means one doesn't wish the writeable to be messaged anymore.
[_responseWriteable cancelSilently];
_responseWriteable = nil;
return;
case GRXWriterStatePaused:
_state = newState;
return;
case GRXWriterStateStarted:
if (_state == GRXWriterStatePaused) {
_state = newState;
[self startNextRead];
}
return;
case GRXWriterStateNotStarted:
return;
}
}
@end

@ -0,0 +1,15 @@
#import <Foundation/Foundation.h>
// See the README file for an introduction to this library.
// A fully-qualified gRPC method name. Full qualification is needed because a gRPC endpoint can
// implement multiple interfaces.
// TODO(jcanizales): Is this proto-specific, or actual part of gRPC? If the former, move one layer up.
@interface GRPCMethodName : NSObject
@property(nonatomic, readonly) NSString *package;
@property(nonatomic, readonly) NSString *interface;
@property(nonatomic, readonly) NSString *method;
- (instancetype)initWithPackage:(NSString *)package
interface:(NSString *)interface
method:(NSString *)method;
@end

@ -0,0 +1,14 @@
#import "GRPCMethodName.h"
@implementation GRPCMethodName
- (instancetype)initWithPackage:(NSString *)package
interface:(NSString *)interface
method:(NSString *)method {
if ((self = [super init])) {
_package = [package copy];
_interface = [interface copy];
_method = [method copy];
}
return self;
}
@end

@ -0,0 +1,4 @@
This is a generic gRPC client for Objective-C on iOS.
If you're trying to get started with the library or with gRPC, you should first
read GRPCCall.h.

@ -0,0 +1,17 @@
#import <Foundation/Foundation.h>
struct grpc_channel;
// Each separate instance of this class represents at least one TCP
// connection to the provided host. To create a grpc_call, pass the
// value of the unmanagedChannel property to grpc_channel_create_call.
// Release this object when the call is finished.
@interface GRPCChannel : NSObject
@property(nonatomic, readonly) struct grpc_channel *unmanagedChannel;
// Convenience constructor to allow for reuse of connections.
+ (instancetype)channelToHost:(NSString *)host;
// Designated initializer
- (instancetype)initWithHost:(NSString *)host;
@end

@ -0,0 +1,32 @@
#import "GRPCChannel.h"
#import <grpc.h>
@implementation GRPCChannel
+ (instancetype)channelToHost:(NSString *)host {
// TODO(jcanizales): Reuse channels.
return [[self alloc] initWithHost:host];
}
- (instancetype)init {
return [self initWithHost:nil];
}
// Designated initializer
- (instancetype)initWithHost:(NSString *)host {
if (!host) {
[NSException raise:NSInvalidArgumentException format:@"Host can't be nil."];
}
if ((self = [super init])) {
_unmanagedChannel = grpc_channel_create(host.UTF8String, NULL);
}
return self;
}
- (void)dealloc {
// TODO(jcanizales): Be sure to add a test with a server that closes the connection prematurely,
// as in the past that made this call to crash.
grpc_channel_destroy(_unmanagedChannel);
}
@end

@ -0,0 +1,21 @@
#import <Foundation/Foundation.h>
struct grpc_completion_queue;
struct grpc_event;
typedef void(^GRPCEventHandler)(struct grpc_event *event);
// This class lets one more easily use grpc_completion_queue. To use it, pass
// the value of the unmanagedQueue property of an instance of this class to
// grpc_call_start_invoke. Then for every grpc_call_* method that accepts a tag,
// you can pass a block of type GRPCEventHandler (remembering to cast it using
// __bridge_retained). The block is guaranteed to eventually be called, by a
// concurrent queue, and then released. Each such block is passed a pointer to
// the grpc_event that carried it (in event->tag).
// Release the GRPCCompletionQueue object only after you are not going to pass
// any more blocks to the grpc_call that's using it.
@interface GRPCCompletionQueue : NSObject
@property(nonatomic, readonly) struct grpc_completion_queue *unmanagedQueue;
+ (instancetype)completionQueue;
@end

@ -0,0 +1,73 @@
#import "GRPCCompletionQueue.h"
#import <grpc.h>
@implementation GRPCCompletionQueue
+ (instancetype)completionQueue {
// TODO(jcanizales): Reuse completion queues to consume only one thread,
// instead of one per call.
return [[self alloc] init];
}
- (instancetype)init {
if ((self = [super init])) {
_unmanagedQueue = grpc_completion_queue_create();
// This is for the following block to capture the pointer by value (instead
// of retaining self and doing self->_unmanagedQueue). This is essential
// because the block doesn't end until after grpc_completion_queue_shutdown
// is called, and we only want that to happen after nobody's using the queue
// anymore (i.e. on self dealloc). So the block would never end if it
// retained self.
grpc_completion_queue *unmanagedQueue = _unmanagedQueue;
// Start a loop on a concurrent queue to read events from the completion
// queue and dispatch each.
static dispatch_once_t initialization;
static dispatch_queue_t gDefaultConcurrentQueue;
dispatch_once(&initialization, ^{
gDefaultConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
});
dispatch_async(gDefaultConcurrentQueue, ^{
while (YES) {
// The following call blocks until an event is available.
grpc_event *event = grpc_completion_queue_next(unmanagedQueue, gpr_inf_future);
switch (event->type) {
case GRPC_WRITE_ACCEPTED:
case GRPC_FINISH_ACCEPTED:
case GRPC_CLIENT_METADATA_READ:
case GRPC_READ:
case GRPC_FINISHED:
if (event->tag) {
GRPCEventHandler handler = (__bridge_transfer GRPCEventHandler) event->tag;
handler(event);
}
grpc_event_finish(event);
continue;
case GRPC_QUEUE_SHUTDOWN:
grpc_completion_queue_destroy(unmanagedQueue);
grpc_event_finish(event);
return;
case GRPC_SERVER_RPC_NEW:
NSAssert(NO, @"C gRPC library produced a server-only event.");
continue;
}
// This means the C gRPC library produced an event that wasn't known
// when this library was written. To preserve evolvability, ignore the
// unknown event on release builds.
NSAssert(NO, @"C gRPC library produced an unknown event.");
};
});
}
return self;
}
- (void)dealloc {
// This makes the completion queue produce a GRPC_QUEUE_SHUTDOWN event *after*
// all other pending events are flushed. What this means is all the blocks
// passed to the gRPC C library as void* are eventually called, even if some
// are called after self is dealloc'd.
grpc_completion_queue_shutdown(_unmanagedQueue);
}
@end

@ -0,0 +1,48 @@
#import <Foundation/Foundation.h>
@protocol GRXWriteable;
@protocol GRXWriter;
// This is a thread-safe wrapper over a GRXWriteable instance. It lets one
// enqueue calls to a GRXWriteable instance for the main thread, guaranteeing
// that didFinishWithError: is the last message sent to it (no matter what
// messages are sent to the wrapper, in what order, nor from which thread). It
// also guarantees that, if cancelWithError: is called from the main thread
// (e.g. by the app cancelling the writes), no further messages are sent to the
// writeable except didFinishWithError:.
//
// TODO(jcanizales): Let the user specify another queue for the writeable
// callbacks.
// TODO(jcanizales): Rename to GRXWriteableWrapper and move to the Rx library.
@interface GRPCDelegateWrapper : NSObject
// The GRXWriteable passed is the wrapped writeable.
// Both the GRXWriter instance and the GRXWriteable instance are retained until
// didFinishWithError: is sent to the writeable, and released after that.
// This is used to create a retain cycle that keeps both objects alive until the
// writing is explicitly finished.
- (instancetype)initWithWriteable:(id<GRXWriteable>)writeable writer:(id<GRXWriter>)writer
NS_DESIGNATED_INITIALIZER;
// Enqueues didReceiveValue: to be sent to the writeable in the main thread.
// The passed handler is invoked from the main thread after didReceiveValue:
// returns.
- (void)enqueueMessage:(NSData *)message completionHandler:(void (^)())handler;
// Enqueues didFinishWithError:nil to be sent to the writeable in the main
// thread. After that message is sent to the writeable, all other methods of
// this object are effectively noops.
- (void)enqueueSuccessfulCompletion;
// If the writeable has not yet received a didFinishWithError: message, this
// will enqueue one to be sent to it in the main thread, and cancel all other
// pending messages to the writeable enqueued by this object (both past and
// future).
// The error argument cannot be nil.
- (void)cancelWithError:(NSError *)error;
// Cancels all pending messages to the writeable enqueued by this object (both
// past and future). Because the writeable won't receive didFinishWithError:,
// this also releases the writeable and the writer.
- (void)cancelSilently;
@end

@ -0,0 +1,87 @@
#import "GRPCDelegateWrapper.h"
#import <net/grpc/objc/RxLibrary/GRXWriteable.h>
@interface GRPCDelegateWrapper ()
// These are atomic so that cancellation can nillify them from any thread.
@property(atomic, strong) id<GRXWriteable> writeable;
@property(atomic, strong) id<GRXWriter> writer;
@end
@implementation GRPCDelegateWrapper {
dispatch_queue_t _writeableQueue;
// This ensures that didFinishWithError: is only sent once to the writeable.
dispatch_once_t _alreadyFinished;
}
- (instancetype)init {
return [self initWithWriteable:nil writer:nil];
}
// Designated initializer
- (instancetype)initWithWriteable:(id<GRXWriteable>)writeable writer:(id<GRXWriter>)writer {
if (self = [super init]) {
_writeableQueue = dispatch_get_main_queue();
_writeable = writeable;
_writer = writer;
}
return self;
}
- (void)enqueueMessage:(NSData *)message completionHandler:(void (^)())handler {
dispatch_async(_writeableQueue, ^{
// We're racing a possible cancellation performed by another thread. To turn
// all already-enqueued messages into noops, cancellation nillifies the
// writeable property. If we get it before it's nil, we won
// the race.
id<GRXWriteable> writeable = self.writeable;
if (writeable) {
[writeable didReceiveValue:message];
handler();
}
});
}
- (void)enqueueSuccessfulCompletion {
dispatch_async(_writeableQueue, ^{
dispatch_once(&_alreadyFinished, ^{
// Cancellation is now impossible. None of the other three blocks can run
// concurrently with this one.
[self.writeable didFinishWithError:nil];
// Break the retain cycle with writer, and skip any possible message to the
// wrapped writeable enqueued after this one.
self.writeable = nil;
self.writer = nil;
});
});
}
- (void)cancelWithError:(NSError *)error {
NSAssert(error, @"For a successful completion, use enqueueSuccessfulCompletion.");
dispatch_once(&_alreadyFinished, ^{
// Skip any of the still-enqueued messages to the wrapped writeable. We use
// the atomic setter to nillify writer and writeable because we might be
// running concurrently with the blocks in _writeableQueue, and assignment
// with ARC isn't atomic.
id<GRXWriteable> writeable = self.writeable;
self.writeable = nil;
dispatch_async(_writeableQueue, ^{
[writeable didFinishWithError:error];
// Break the retain cycle with writer.
self.writer = nil;
});
});
}
- (void)cancelSilently {
dispatch_once(&_alreadyFinished, ^{
// Skip any of the still-enqueued messages to the wrapped writeable. We use
// the atomic setter to nillify writer and writeable because we might be
// running concurrently with the blocks in _writeableQueue, and assignment
// with ARC isn't atomic.
self.writeable = nil;
self.writer = nil;
});
}
@end

@ -0,0 +1,7 @@
#import <Foundation/Foundation.h>
#import "GRPCMethodName.h"
@interface GRPCMethodName (HTTP2Encoding)
- (NSString *)HTTP2Path;
@end

@ -0,0 +1,11 @@
#import "GRPCMethodName+HTTP2Encoding.h"
@implementation GRPCMethodName (HTTP2Encoding)
- (NSString *)HTTP2Path {
if (self.package) {
return [NSString stringWithFormat:@"/%@.%@/%@", self.package, self.interface, self.method];
} else {
return [NSString stringWithFormat:@"/%@/%@", self.interface, self.method];
}
}
@end

@ -0,0 +1,8 @@
#import <Foundation/Foundation.h>
struct grpc_byte_buffer;
@interface NSData (GRPC)
+ (instancetype)grpc_dataWithByteBuffer:(struct grpc_byte_buffer *)buffer;
- (struct grpc_byte_buffer *)grpc_byteBuffer;
@end

@ -0,0 +1,53 @@
#import "NSData+GRPC.h"
#include <byte_buffer.h>
#include <string.h>
// TODO(jcanizales): Move these two incantations to the C library.
static void CopyByteBufferToCharArray(grpc_byte_buffer *buffer, char *array) {
size_t offset = 0;
grpc_byte_buffer_reader *reader = grpc_byte_buffer_reader_create(buffer);
gpr_slice next;
while (grpc_byte_buffer_reader_next(reader, &next) != 0){
memcpy(array + offset, GPR_SLICE_START_PTR(next), (size_t) GPR_SLICE_LENGTH(next));
offset += GPR_SLICE_LENGTH(next);
gpr_slice_unref(next);
}
grpc_byte_buffer_reader_destroy(reader);
}
static grpc_byte_buffer *CopyCharArrayToNewByteBuffer(const char *array, size_t length) {
gpr_slice slice = gpr_slice_from_copied_buffer(array, length);
grpc_byte_buffer *buffer = grpc_byte_buffer_create(&slice, 1);
gpr_slice_unref(slice);
return buffer;
}
@implementation NSData (GRPC)
+ (instancetype)grpc_dataWithByteBuffer:(grpc_byte_buffer *)buffer {
NSUInteger length = grpc_byte_buffer_length(buffer);
char *array = malloc(length * sizeof(*array));
if (!array) {
// TODO(jcanizales): grpc_byte_buffer is reference-counted, so we can
// prevent this memory problem by implementing a subclass of NSData
// that wraps the grpc_byte_buffer. Then enumerateByteRangesUsingBlock:
// can be implemented using a grpc_byte_buffer_reader.
return nil;
}
CopyByteBufferToCharArray(buffer, array);
return [self dataWithBytesNoCopy:array length:length freeWhenDone:YES];
}
- (grpc_byte_buffer *)grpc_byteBuffer {
// Some implementations of NSData, as well as grpc_byte_buffer, support O(1)
// appending of byte arrays by not using internally a single contiguous memory
// block for representation.
// The following implementation is thus not optimal, sometimes requiring two
// copies (one by self.bytes and another by gpr_slice_from_copied_buffer).
// If it turns out to be an issue, we can use enumerateByteRangesUsingblock:
// to create an array of gpr_slice objects to pass to grpc_byte_buffer_create.
// That would make it do exactly one copy, always.
return CopyCharArrayToNewByteBuffer((const char *)self.bytes, (size_t)self.length);
}
@end

@ -0,0 +1,7 @@
#import <Foundation/Foundation.h>
struct grpc_metadata;
@interface NSDictionary (GRPC)
+ (instancetype)grpc_dictionaryFromMetadata:(struct grpc_metadata *)entries count:(size_t)count;
@end

@ -0,0 +1,23 @@
#import "NSDictionary+GRPC.h"
#include <grpc.h>
@implementation NSDictionary (GRPC)
+ (instancetype)grpc_dictionaryFromMetadata:(grpc_metadata *)entries count:(size_t)count {
NSMutableDictionary *metadata = [NSMutableDictionary dictionaryWithCapacity:count];
for (grpc_metadata *entry = entries; entry < entries + count; entry++) {
// TODO(jcanizales): Verify in a C library test that it's converting header names to lower case automatically.
NSString *name = [NSString stringWithUTF8String:entry->key];
if (!name) {
continue;
}
if (!metadata[name]) {
metadata[name] = [NSMutableArray array];
}
// TODO(jcanizales): Should we use a non-copy constructor?
[metadata[name] addObject:[NSData dataWithBytes:entry->value
length:entry->value_length]];
}
return metadata;
}
@end

@ -0,0 +1,41 @@
#import <Foundation/Foundation.h>
// TODO(jcanizales): Make the domain string public.
extern NSString *const kGRPCErrorDomain;
// TODO(jcanizales): Make this public and document each code.
typedef NS_ENUM(NSInteger, GRPCErrorCode) {
GRPCErrorCodeCancelled = 1,
GRPCErrorCodeUnknown = 2,
GRPCErrorCodeInvalidArgument = 3,
GRPCErrorCodeDeadlineExceeded = 4,
GRPCErrorCodeNotFound = 5,
GRPCErrorCodeAlreadyExists = 6,
GRPCErrorCodePermissionDenied = 7,
GRPCErrorCodeUnauthenticated = 16,
GRPCErrorCodeResourceExhausted = 8,
GRPCErrorCodeFailedPrecondition = 9,
GRPCErrorCodeAborted = 10,
GRPCErrorCodeOutOfRange = 11,
GRPCErrorCodeUnimplemented = 12,
GRPCErrorCodeInternal = 13,
GRPCErrorCodeUnavailable = 14,
GRPCErrorCodeDataLoss = 15
};
// TODO(jcanizales): This is conflating trailing metadata with Status details. Fix it once there's
// a decision on how to codify Status.
#include <grpc/status.h>
struct grpc_metadata;
struct grpc_status {
grpc_status_code status;
const char *details;
size_t metadata_count;
struct grpc_metadata *metadata_elements;
};
@interface NSError (GRPC)
// Returns nil if the status is OK. Otherwise, a NSError whose code is one of
// GRPCErrorCode and whose domain is kGRPCErrorDomain.
+ (instancetype)grpc_errorFromStatus:(struct grpc_status *)status;
@end

@ -0,0 +1,18 @@
#import "NSError+GRPC.h"
#include <grpc.h>
NSString *const kGRPCErrorDomain = @"org.grpc";
@implementation NSError (GRPC)
+ (instancetype)grpc_errorFromStatus:(struct grpc_status *)status {
if (status->status == GRPC_STATUS_OK) {
return nil;
}
NSString *message =
[NSString stringWithFormat:@"Code=%i Message='%s'", status->status, status->details];
return [NSError errorWithDomain:kGRPCErrorDomain
code:status->status
userInfo:@{NSLocalizedDescriptionKey: message}];
}
@end

@ -0,0 +1,3 @@
gRPC implementation for Objective-C on iOS
This is a work in progress.

@ -0,0 +1,40 @@
#import <Foundation/Foundation.h>
#import "GRXWriter.h"
// Utility to construct GRXWriter instances from values that are immediately available when
// required. The returned writers all support pausing and early termination.
//
// Unless the writeable callback pauses them or stops them early, these writers will do all their
// interactions with the writeable before the start method returns.
@interface GRXImmediateWriter : NSObject<GRXWriter>
// Returns a writer that pulls values from the passed NSEnumerator instance and pushes them to
// its writeable. The NSEnumerator is released when it finishes.
+ (id<GRXWriter>)writerWithEnumerator:(NSEnumerator *)enumerator;
// Returns a writer that pushes to its writeable the successive values returned by the passed
// block. When the block first returns nil, it is released.
+ (id<GRXWriter>)writerWithValueSupplier:(id (^)())block;
// Returns a writer that iterates over the values of the passed container and pushes them to
// its writeable. The container is released when the iteration is over.
//
// Note that the usual speed gain of NSFastEnumeration over NSEnumerator results from not having to
// call one method per element. Because GRXWriteable instances accept values one by one, that speed
// gain doesn't happen here.
+ (id<GRXWriter>)writerWithContainer:(id<NSFastEnumeration>)container;
// Returns a writer that sends the passed value to its writeable and then finishes (releasing the
// value).
+ (id<GRXWriter>)writerWithValue:(id)value;
// Returns a writer that, as part of its start method, sends the passed error to the writeable
// (then releasing the error).
+ (id<GRXWriter>)writerWithError:(NSError *)error;
// Returns a writer that, as part of its start method, finishes immediately without sending any
// values to its writeable.
+ (id<GRXWriter>)emptyWriter;
@end

@ -0,0 +1,132 @@
#import "GRXImmediateWriter.h"
#import "NSEnumerator+GRXUtil.h"
@implementation GRXImmediateWriter {
NSEnumerator *_enumerator;
NSError *_errorOrNil;
id<GRXWriteable> _writeable;
}
@synthesize state = _state;
- (instancetype) init {
return [self initWithEnumerator:nil error:nil]; // results in an empty writer.
}
// Designated initializer
- (instancetype)initWithEnumerator:(NSEnumerator *)enumerator error:(NSError *)errorOrNil {
if (((self = [super init]))) {
_enumerator = enumerator;
_errorOrNil = errorOrNil;
_state = GRXWriterStateNotStarted;
}
return self;
}
#pragma mark Convenience constructors
+ (instancetype)writerWithEnumerator:(NSEnumerator *)enumerator error:(NSError *)errorOrNil {
return [[self alloc] initWithEnumerator:enumerator error:errorOrNil];
}
+ (id<GRXWriter>)writerWithEnumerator:(NSEnumerator *)enumerator {
return [self writerWithEnumerator:enumerator error:nil];
}
+ (id<GRXWriter>)writerWithValueSupplier:(id (^)())block {
return [self writerWithEnumerator:[NSEnumerator grx_enumeratorWithValueSupplier:block]];
}
+ (id<GRXWriter>)writerWithContainer:(id<NSFastEnumeration>)container {
return [self writerWithEnumerator:[NSEnumerator grx_enumeratorWithContainer:container]];;
}
+ (id<GRXWriter>)writerWithValue:(id)value {
if (value) {
return [self writerWithEnumerator:[NSEnumerator grx_enumeratorWithSingleValue:value]];
} else {
return [self emptyWriter];
}
}
+ (id<GRXWriter>)writerWithError:(NSError *)error {
if (error) {
return [self writerWithEnumerator:nil error:error];
} else {
return [self emptyWriter];
}
}
+ (id<GRXWriter>)emptyWriter {
static GRXImmediateWriter *emptyWriter;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
emptyWriter = [self writerWithEnumerator:nil error:nil];
});
return emptyWriter;
}
#pragma mark Conformance with GRXWriter
// Most of the complexity in this implementation is the result of supporting pause and resumption of
// the GRXWriter. It's an important feature for instances of GRXWriter that are backed by a
// container (which may be huge), or by a NSEnumerator (which may even be infinite).
- (void)writeUntilPausedOrStopped {
id value;
while (value = [_enumerator nextObject]) {
[_writeable didReceiveValue:value];
// If the writeable has a reference to us, it might change our state to paused or finished.
if (_state == GRXWriterStatePaused || _state == GRXWriterStateFinished) {
return;
}
}
[self finishWithError:_errorOrNil];
}
- (void)startWithWriteable:(id<GRXWriteable>)writeable {
_state = GRXWriterStateStarted;
_writeable = writeable;
[self writeUntilPausedOrStopped];
}
- (void)finishWithError:(NSError *)errorOrNil {
_state = GRXWriterStateFinished;
_enumerator = nil;
_errorOrNil = nil;
id<GRXWriteable> writeable = _writeable;
_writeable = nil;
[writeable didFinishWithError:errorOrNil];
}
- (void)setState:(GRXWriterState)newState {
// Manual transitions are only allowed from the started or paused states.
if (_state == GRXWriterStateNotStarted || _state == GRXWriterStateFinished) {
return;
}
switch (newState) {
case GRXWriterStateFinished:
_state = newState;
_enumerator = nil;
_errorOrNil = nil;
// Per GRXWriter's contract, setting the state to Finished manually
// means one doesn't wish the writeable to be messaged anymore.
_writeable = nil;
return;
case GRXWriterStatePaused:
_state = newState;
return;
case GRXWriterStateStarted:
if (_state == GRXWriterStatePaused) {
_state = newState;
[self writeUntilPausedOrStopped];
}
return;
case GRXWriterStateNotStarted:
return;
}
}
@end

@ -0,0 +1,27 @@
#import <Foundation/Foundation.h>
// A GRXWriteable is an object to which a sequence of values can be sent. The
// sequence finishes with an optional error.
@protocol GRXWriteable <NSObject>
// Push the next value of the sequence to the receiving object.
// TODO(jcanizales): Name it enumerator:(id<GRXEnumerator>) didProduceValue:(id)?
- (void)didReceiveValue:(id)value;
// Signal that the sequence is completed, or that an error ocurred. After this
// message is sent to the instance, neither it nor didReceiveValue: may be
// called again.
// TODO(jcanizales): enumerator:(id<GRXEnumerator>) didFinishWithError:(NSError*)?
- (void)didFinishWithError:(NSError *)errorOrNil;
@end
typedef void (^GRXValueHandler)(id value);
typedef void (^GRXCompletionHandler)(NSError *errorOrNil);
// Utility to create objects that conform to the GRXWriteable protocol, from
// blocks that handle each of the two methods of the protocol.
@interface GRXWriteable : NSObject<GRXWriteable>
- (instancetype)initWithValueHandler:(GRXValueHandler)valueHandler
completionHandler:(GRXCompletionHandler)completionHandler
NS_DESIGNATED_INITIALIZER;
@end

@ -0,0 +1,33 @@
#import "GRXWriteable.h"
@implementation GRXWriteable {
GRXValueHandler _valueHandler;
GRXCompletionHandler _completionHandler;
}
- (instancetype)init {
return [self initWithValueHandler:nil completionHandler:nil];
}
// Designated initializer
- (instancetype)initWithValueHandler:(GRXValueHandler)valueHandler
completionHandler:(GRXCompletionHandler)completionHandler {
if ((self = [super init])) {
_valueHandler = valueHandler;
_completionHandler = completionHandler;
}
return self;
}
- (void)didReceiveValue:(id)value {
if (_valueHandler) {
_valueHandler(value);
}
}
- (void)didFinishWithError:(NSError *)errorOrNil {
if (_completionHandler) {
_completionHandler(errorOrNil);
}
}
@end

@ -0,0 +1,33 @@
#import "GRXWriter.h"
@interface GRXWriter (Immediate)
// Returns a writer that pulls values from the passed NSEnumerator instance and pushes them to
// its writeable. The NSEnumerator is released when it finishes.
+ (instancetype)writerWithEnumerator:(NSEnumerator *)enumerator;
// Returns a writer that pushes to its writeable the successive values returned by the passed
// block. When the block first returns nil, it is released.
+ (instancetype)writerWithValueSupplier:(id (^)())block;
// Returns a writer that iterates over the values of the passed container and pushes them to
// its writeable. The container is released when the iteration is over.
//
// Note that the usual speed gain of NSFastEnumeration over NSEnumerator results from not having to
// call one method per element. Because GRXWriteable instances accept values one by one, that speed
// gain doesn't happen here.
+ (instancetype)writerWithContainer:(id<NSFastEnumeration>)container;
// Returns a writer that sends the passed value to its writeable and then finishes (releasing the
// value).
+ (instancetype)writerWithValue:(id)value;
// Returns a writer that, as part of its start method, sends the passed error to the writeable
// (then releasing the error).
+ (instancetype)writerWithError:(NSError *)error;
// Returns a writer that, as part of its start method, finishes immediately without sending any
// values to its writeable.
+ (instancetype)emptyWriter;
@end

@ -0,0 +1,31 @@
#import "GRXWriter+Immediate.h"
#import "GRXImmediateWriter.h"
@implementation GRXWriter (Immediate)
+ (instancetype)writerWithEnumerator:(NSEnumerator *)enumerator {
return [[self alloc] initWithWriter:[GRXImmediateWriter writerWithEnumerator:enumerator]];
}
+ (instancetype)writerWithValueSupplier:(id (^)())block {
return [[self alloc] initWithWriter:[GRXImmediateWriter writerWithValueSupplier:block]];
}
+ (instancetype)writerWithContainer:(id<NSFastEnumeration>)container {
return [[self alloc] initWithWriter:[GRXImmediateWriter writerWithContainer:container]];
}
+ (instancetype)writerWithValue:(id)value {
return [[self alloc] initWithWriter:[GRXImmediateWriter writerWithValue:value]];
}
+ (instancetype)writerWithError:(NSError *)error {
return [[self alloc] initWithWriter:[GRXImmediateWriter writerWithError:error]];
}
+ (instancetype)emptyWriter {
return [[self alloc] initWithWriter:[GRXImmediateWriter emptyWriter]];
}
@end

@ -0,0 +1,9 @@
#import "GRXWriter.h"
@interface GRXWriter (Transformations)
// Returns a writer that wraps the receiver, and has all the values the receiver would write
// transformed by the provided mapping function.
- (GRXWriter *)map:(id (^)(id value))map;
@end

@ -0,0 +1,14 @@
#import "GRXWriter+Transformations.h"
#import "transformations/GRXMappingWriter.h"
@implementation GRXWriter (Transformations)
- (GRXWriter *)map:(id (^)(id))map {
if (!map) {
return self;
}
return [[GRXMappingWriter alloc] initWithWriter:self map:map];
}
@end

@ -0,0 +1,94 @@
#import <Foundation/Foundation.h>
#import "GRXWriteable.h"
typedef NS_ENUM(NSInteger, GRXWriterState) {
// The writer has not yet been given a writeable to which it can push its
// values. To have an writer transition to the Started state, send it a
// startWithWriteable: message.
//
// An writer's state cannot be manually set to this value.
GRXWriterStateNotStarted,
// The writer might push values to the writeable at any moment.
GRXWriterStateStarted,
// The writer is temporarily paused, and won't send any more values to the
// writeable unless its state is set back to Started. The writer might still
// transition to the Finished state at any moment, and is allowed to send
// didFinishWithError: to its writeable.
//
// Not all implementations of writer have to support pausing, and thus
// trying to set an writer's state to this value might have no effect.
GRXWriterStatePaused,
// The writer has released its writeable and won't interact with it anymore.
//
// One seldomly wants to set an writer's state to this value, as its
// writeable isn't notified with a didFinishWithError: message. Instead, sending
// finishWithError: to the writer will make it notify the writeable and then
// transition to this state.
GRXWriterStateFinished
};
// An object that conforms to this protocol can produce, on demand, a sequence
// of values. The sequence may be produced asynchronously, and it may consist of
// any number of elements, including none or an infinite number.
//
// GRXWriter is the active dual of NSEnumerator. The difference between them
// is thus whether the object plays an active or passive role during usage: A
// user of NSEnumerator pulls values off it, and passes the values to a writeable.
// A user of GRXWriter, though, just gives it a writeable, and the
// GRXWriter instance pushes values to the writeable. This makes this protocol
// suitable to represent a sequence of future values, as well as collections
// with internal iteration.
//
// An instance of GRXWriter can start producing values after a writeable is
// passed to it. It can also be commanded to finish the sequence immediately
// (with an optional error). Finally, it can be asked to pause, but the
// conforming instance is not required to oblige.
//
// Unless otherwise indicated by a conforming class, no messages should be sent
// concurrently to a GRXWriter. I.e., conforming classes aren't required to
// be thread-safe.
@protocol GRXWriter <NSObject>
// This property can be used to query the current state of the writer, which
// determines how it might currently use its writeable. Some state transitions can
// be triggered by setting this property to the corresponding value, and that's
// useful for advanced use cases like pausing an writer. For more details,
// see the documentation of the enum.
@property(nonatomic) GRXWriterState state;
// Start sending messages to the writeable. Messages may be sent before the method
// returns, or they may be sent later in the future. See GRXWriteable.h for the
// different messages a writeable can receive.
//
// If this writer draws its values from an external source (e.g. from the
// filesystem or from a server), calling this method will commonly trigger side
// effects (like network connections).
//
// This method might only be called on writers in the NotStarted state.
- (void)startWithWriteable:(id<GRXWriteable>)writeable;
// Send didFinishWithError:errorOrNil immediately to the writeable, and don't send
// any more messages to it.
//
// This method might only be called on writers in the Started or Paused
// state.
//
// TODO(jcanizales): Consider adding some guarantee about the immediacy of that
// stopping. I know I've relied on it in part of the code that uses this, but
// can't remember the details in the presence of concurrency.
- (void)finishWithError:(NSError *)errorOrNil;
@end
// A "proxy" class that simply forwards values, completion, and errors from its
// input writer to its writeable.
// It is useful as a superclass for pipes that act as a transformation of their
// input writer, and for classes that represent objects with input and
// output sequences of values, like an RPC.
@interface GRXWriter : NSObject<GRXWriter>
- (instancetype)initWithWriter:(id<GRXWriter>)writer NS_DESIGNATED_INITIALIZER;
@end

@ -0,0 +1,79 @@
#import "GRXWriter.h"
@interface GRXWriter () <GRXWriteable>
@end
@implementation GRXWriter {
id<GRXWriter> _writer;
id<GRXWriteable> _writeable;
}
- (instancetype)init {
return [self initWithWriter:nil];
}
// Designated initializer
- (instancetype)initWithWriter:(id<GRXWriter>)writer {
if (!writer) {
[NSException raise:NSInvalidArgumentException format:@"writer can't be nil."];
}
if ((self = [super init])) {
_writer = writer;
}
return self;
}
// This is used to send a completion or an error to the writeable. It nillifies
// our reference to it in order to guarantee no more messages are sent to it,
// and to release it.
- (void)finishOutputWithError:(NSError *)errorOrNil {
id<GRXWriteable> writeable = _writeable;
_writeable = nil;
[writeable didFinishWithError:errorOrNil];
}
// This is used to stop the input writer. It nillifies our reference to it
// to release it.
- (void)finishInput {
id<GRXWriter> writer = _writer;
_writer = nil;
writer.state = GRXWriterStateFinished;
}
#pragma mark GRXWriteable implementation
- (void)didReceiveValue:(id)value {
[_writeable didReceiveValue:value];
}
- (void)didFinishWithError:(NSError *)errorOrNil {
_writer = nil;
[self finishOutputWithError:errorOrNil];
}
#pragma mark GRXWriter implementation
- (GRXWriterState)state {
return _writer ? _writer.state : GRXWriterStateFinished;
}
- (void)setState:(GRXWriterState)state {
if (state == GRXWriterStateFinished) {
_writeable = nil;
[self finishInput];
} else {
_writer.state = state;
}
}
- (void)startWithWriteable:(id<GRXWriteable>)writeable {
_writeable = writeable;
[_writer startWithWriteable:self];
}
- (void)finishWithError:(NSError *)errorOrNil {
[self finishOutputWithError:errorOrNil];
[self finishInput];
}
@end

@ -0,0 +1,18 @@
#import <Foundation/Foundation.h>
@interface NSEnumerator (GRXUtil)
// Returns a NSEnumerator instance that iterates through the elements of the passed container that
// supports fast enumeration. Note that this negates the speed benefits of fast enumeration over
// NSEnumerator. It's only intended for the rare cases when one needs the latter and only has the
// former, e.g. for iteration that needs to be paused and resumed later.
+ (NSEnumerator *)grx_enumeratorWithContainer:(id<NSFastEnumeration>)container;
// Returns a NSEnumerator instance that provides a single object before finishing. The value is then
// released.
+ (NSEnumerator *)grx_enumeratorWithSingleValue:(id)value;
// Returns a NSEnumerator instance that delegates the invocations of nextObject to the passed block.
// When the block first returns nil, it is released.
+ (NSEnumerator *)grx_enumeratorWithValueSupplier:(id (^)())block;
@end

@ -0,0 +1,21 @@
#import "NSEnumerator+GRXUtil.h"
#import "private/GRXNSBlockEnumerator.h"
#import "private/GRXNSFastEnumerator.h"
#import "private/GRXNSScalarEnumerator.h"
@implementation NSEnumerator (GRXUtil)
+ (NSEnumerator *)grx_enumeratorWithContainer:(id<NSFastEnumeration>)container {
// TODO(jcanizales): Consider checking if container responds to objectEnumerator and return that?
return [[GRXNSFastEnumerator alloc] initWithContainer:container];
}
+ (NSEnumerator *)grx_enumeratorWithSingleValue:(id)value {
return [[GRXNSScalarEnumerator alloc] initWithValue:value];
}
+ (NSEnumerator *)grx_enumeratorWithValueSupplier:(id (^)())block {
return [[GRXNSBlockEnumerator alloc] initWithValueSupplier:block];
}
@end

@ -0,0 +1,8 @@
This is a generic Reactive Extensions library for Objective-C, created to ease
the implementation of the gRPC Objective-C runtime.
It has no dependencies on gRPC nor other libraries, and should eventually be
moved under its own GitHub project.
If you're trying to get started on the library, you might want to first read
GRXWriter.h and then GRXWriteable.h.

@ -0,0 +1,12 @@
Pod::Spec.new do |s|
s.name = 'RxLibrary'
s.version = '0.0.1'
s.summary = 'Reactive Extensions library for iOS'
s.author = {
'Jorge Canizales' => 'jcanizales@google.com'
}
s.source_files = '*.{h,m}'
s.platform = :ios
s.ios.deployment_target = '6.0'
s.requires_arc = true
end

@ -0,0 +1,9 @@
#import <Foundation/Foundation.h>
// Concrete subclass of NSEnumerator that delegates the invocations of nextObject to a block passed
// on initialization.
@interface GRXNSBlockEnumerator : NSEnumerator
// The first time the passed block returns nil, the enumeration will end and the block will be
// released.
- (instancetype)initWithValueSupplier:(id (^)())block;
@end

@ -0,0 +1,28 @@
#import "GRXNSBlockEnumerator.h"
@implementation GRXNSBlockEnumerator {
id (^_block)();
}
- (instancetype)init {
return [self initWithValueSupplier:nil];
}
- (instancetype)initWithValueSupplier:(id (^)())block {
if ((self = [super init])) {
_block = block;
}
return self;
}
- (id)nextObject {
if (!_block) {
return nil;
}
id value = _block();
if (!value) {
_block = nil;
}
return value;
}
@end

@ -0,0 +1,10 @@
#import <Foundation/Foundation.h>
// This is a bridge to interact through NSEnumerator's interface with objects that only conform to
// NSFastEnumeration. (There's nothing specifically fast about it - you certainly don't win any
// speed by using this instead of a NSEnumerator provided by your container).
@interface GRXNSFastEnumerator : NSEnumerator
// After the iteration of the container (via the NSFastEnumeration protocol) is over, the container
// is released. If the container is modified during enumeration, an exception is thrown.
- (instancetype)initWithContainer:(id<NSFastEnumeration>)container;
@end

@ -0,0 +1,55 @@
#import "GRXNSFastEnumerator.h"
@implementation GRXNSFastEnumerator {
id<NSFastEnumeration> _container;
NSFastEnumerationState _state;
// Number of elements of the container currently in the _state.itemsPtr array.
NSUInteger _count;
// The index of the next object to return from the _state.itemsPtr array.
NSUInteger _index;
// A "buffer of one element," for the containers that enumerate their elements one by one. Those
// will set _state.itemsPtr to point to this.
// The NSFastEnumeration protocol requires it to be __unsafe_unretained, but that's alright
// because the only use we'd make of its value is to return it immediately as the result of
// nextObject.
__unsafe_unretained id _bufferValue;
// Neither NSEnumerator nor NSFastEnumeration instances are required to work correctly when the
// underlying container is mutated during iteration. The expectation is that an exception is
// thrown when that happens. So we check for mutations.
unsigned long _mutationFlag;
BOOL _mutationFlagIsSet;
}
- (instancetype)init {
return [self initWithContainer:nil];
}
// Designated initializer.
- (instancetype)initWithContainer:(id<NSFastEnumeration>)container {
NSAssert(container, @"container can't be nil");
if ((self = [super init])) {
_container = container;
}
return self;
}
- (id)nextObject {
if (_index == _count) {
_index = 0;
_count = [_container countByEnumeratingWithState:&_state objects:&_bufferValue count:1];
if (_count == 0) {
// Enumeration is over.
_container = nil;
return nil;
}
if (_mutationFlagIsSet) {
NSAssert(_mutationFlag == *(_state.mutationsPtr),
@"container was mutated while being enumerated");
} else {
_mutationFlag = *(_state.mutationsPtr);
_mutationFlagIsSet = YES;
}
}
return _state.itemsPtr[_index++];
}
@end

@ -0,0 +1,8 @@
#import <Foundation/Foundation.h>
// Concrete subclass of NSEnumerator whose instances return a single object before finishing.
@interface GRXNSScalarEnumerator : NSEnumerator
// Param value: the single object this instance will produce. After the first invocation of
// nextObject, the value is released.
- (instancetype)initWithValue:(id)value;
@end

@ -0,0 +1,24 @@
#import "GRXNSScalarEnumerator.h"
@implementation GRXNSScalarEnumerator {
id _value;
}
- (instancetype)init {
return [self initWithValue:nil];
}
// Designated initializer.
- (instancetype)initWithValue:(id)value {
if ((self = [super init])) {
_value = value;
}
return self;
}
- (id)nextObject {
id value = _value;
_value = nil;
return value;
}
@end

@ -0,0 +1,7 @@
#import "GRXWriter.h"
// A "proxy" writer that transforms all the values of its input writer by using a mapping function.
@interface GRXMappingWriter : GRXWriter
- (instancetype)initWithWriter:(id<GRXWriter>)writer map:(id (^)(id value))map
NS_DESIGNATED_INITIALIZER;
@end

@ -0,0 +1,30 @@
#import "GRXMappingWriter.h"
static id (^kIdentity)(id value) = ^id(id value) {
return value;
};
@interface GRXWriter () <GRXWriteable>
@end
@implementation GRXMappingWriter {
id (^_map)(id value);
}
- (instancetype)initWithWriter:(id<GRXWriter>)writer {
return [self initWithWriter:writer map:nil];
}
// Designated initializer
- (instancetype)initWithWriter:(id<GRXWriter>)writer map:(id (^)(id value))map {
if ((self = [super initWithWriter:writer])) {
_map = map ?: kIdentity;
}
return self;
}
// Override
- (void)didReceiveValue:(id)value {
[super didReceiveValue:_map(value)];
}
@end

@ -0,0 +1,12 @@
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
pod 'RxLibrary', :path => "../../RxLibrary"
target 'Sample' do
end
target 'SampleTests' do
end

@ -0,0 +1,14 @@
PODS:
- RxLibrary (0.0.1)
DEPENDENCIES:
- RxLibrary (from `../../RxLibrary`)
EXTERNAL SOURCES:
RxLibrary:
:path: ../../RxLibrary
SPEC CHECKSUMS:
RxLibrary: fc24868ee72616e8c4e58128b439811fdade0da4
COCOAPODS: 0.35.0

@ -0,0 +1 @@
../../../../../../RxLibrary/GRXImmediateWriter.h

@ -0,0 +1 @@
../../../../../../RxLibrary/GRXWriteable.h

@ -0,0 +1 @@
../../../../../../RxLibrary/GRXWriter+Immediate.h

@ -0,0 +1 @@
../../../../../../RxLibrary/GRXWriter+Transformations.h

@ -0,0 +1 @@
../../../../../../RxLibrary/GRXWriter.h

@ -0,0 +1 @@
../../../../../../RxLibrary/NSEnumerator+GRXUtil.h

@ -0,0 +1,12 @@
Pod::Spec.new do |s|
s.name = 'RxLibrary'
s.version = '0.0.1'
s.summary = 'Reactive Extensions library for iOS'
s.author = {
'Jorge Canizales' => 'jcanizales@google.com'
}
s.source_files = '*.{h,m}'
s.platform = :ios
s.ios.deployment_target = '6.0'
s.requires_arc = true
end

@ -0,0 +1,14 @@
PODS:
- RxLibrary (0.0.1)
DEPENDENCIES:
- RxLibrary (from `../../RxLibrary`)
EXTERNAL SOURCES:
RxLibrary:
:path: ../../RxLibrary
SPEC CHECKSUMS:
RxLibrary: fc24868ee72616e8c4e58128b439811fdade0da4
COCOAPODS: 0.35.0

File diff suppressed because it is too large Load Diff

@ -0,0 +1,5 @@
#include "Pods-RxLibrary.xcconfig"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Build" "${PODS_ROOT}/Headers/Build/RxLibrary" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RxLibrary"
OTHER_LDFLAGS = -ObjC
PODS_ROOT = ${SRCROOT}

@ -0,0 +1,5 @@
#import <Foundation/Foundation.h>
@interface PodsDummy_Pods_RxLibrary : NSObject
@end
@implementation PodsDummy_Pods_RxLibrary
@end

@ -0,0 +1,5 @@
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#endif
#import "Pods-environment.h"

@ -0,0 +1,5 @@
#include "Pods-Sample-RxLibrary.xcconfig"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Build" "${PODS_ROOT}/Headers/Build/RxLibrary" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RxLibrary"
OTHER_LDFLAGS = -ObjC
PODS_ROOT = ${SRCROOT}

@ -0,0 +1,5 @@
#import <Foundation/Foundation.h>
@interface PodsDummy_Pods_Sample_RxLibrary : NSObject
@end
@implementation PodsDummy_Pods_Sample_RxLibrary
@end

@ -0,0 +1,5 @@
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#endif
#import "Pods-Sample-environment.h"

@ -0,0 +1,3 @@
# Acknowledgements
This application makes use of the following third party libraries:
Generated by CocoaPods - http://cocoapods.org

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>FooterText</key>
<string>This application makes use of the following third party libraries:</string>
<key>Title</key>
<string>Acknowledgements</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Generated by CocoaPods - http://cocoapods.org</string>
<key>Title</key>
<string></string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
</array>
<key>StringsTable</key>
<string>Acknowledgements</string>
<key>Title</key>
<string>Acknowledgements</string>
</dict>
</plist>

@ -0,0 +1,5 @@
#import <Foundation/Foundation.h>
@interface PodsDummy_Pods_Sample : NSObject
@end
@implementation PodsDummy_Pods_Sample
@end

@ -0,0 +1,14 @@
// To check if a library is compiled with CocoaPods you
// can use the `COCOAPODS` macro definition which is
// defined in the xcconfigs so it is available in
// headers also when they are imported in the client
// project.
// RxLibrary
#define COCOAPODS_POD_AVAILABLE_RxLibrary
#define COCOAPODS_VERSION_MAJOR_RxLibrary 0
#define COCOAPODS_VERSION_MINOR_RxLibrary 0
#define COCOAPODS_VERSION_PATCH_RxLibrary 1

@ -0,0 +1,74 @@
#!/bin/sh
set -e
mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
> "$RESOURCES_TO_COPY"
install_resource()
{
case $1 in
*.storyboard)
echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc ${PODS_ROOT}/$1 --sdk ${SDKROOT}"
ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc" "${PODS_ROOT}/$1" --sdk "${SDKROOT}"
;;
*.xib)
echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}"
ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}"
;;
*.framework)
echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
echo "rsync -av ${PODS_ROOT}/$1 ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
rsync -av "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
;;
*.xcdatamodel)
echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1"`.mom\""
xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodel`.mom"
;;
*.xcdatamodeld)
echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd\""
xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd"
;;
*.xcmappingmodel)
echo "xcrun mapc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm\""
xcrun mapc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm"
;;
*.xcassets)
;;
/*)
echo "$1"
echo "$1" >> "$RESOURCES_TO_COPY"
;;
*)
echo "${PODS_ROOT}/$1"
echo "${PODS_ROOT}/$1" >> "$RESOURCES_TO_COPY"
;;
esac
}
rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
if [[ "${ACTION}" == "install" ]]; then
rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
fi
rm -f "$RESOURCES_TO_COPY"
if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ `find . -name '*.xcassets' | wc -l` -ne 0 ]
then
case "${TARGETED_DEVICE_FAMILY}" in
1,2)
TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
;;
1)
TARGET_DEVICE_ARGS="--target-device iphone"
;;
2)
TARGET_DEVICE_ARGS="--target-device ipad"
;;
*)
TARGET_DEVICE_ARGS="--target-device mac"
;;
esac
find "${PWD}" -name "*.xcassets" -print0 | xargs -0 actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
fi

@ -0,0 +1,6 @@
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RxLibrary"
OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/RxLibrary"
OTHER_LDFLAGS = -ObjC -l"Pods-Sample-RxLibrary"
OTHER_LIBTOOLFLAGS = $(OTHER_LDFLAGS)
PODS_ROOT = ${SRCROOT}/Pods

@ -0,0 +1,6 @@
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RxLibrary"
OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/RxLibrary"
OTHER_LDFLAGS = -ObjC -l"Pods-Sample-RxLibrary"
OTHER_LIBTOOLFLAGS = $(OTHER_LDFLAGS)
PODS_ROOT = ${SRCROOT}/Pods

@ -0,0 +1,5 @@
#include "Pods-SampleTests-RxLibrary.xcconfig"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Build" "${PODS_ROOT}/Headers/Build/RxLibrary" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RxLibrary"
OTHER_LDFLAGS = -ObjC
PODS_ROOT = ${SRCROOT}

@ -0,0 +1,5 @@
#import <Foundation/Foundation.h>
@interface PodsDummy_Pods_SampleTests_RxLibrary : NSObject
@end
@implementation PodsDummy_Pods_SampleTests_RxLibrary
@end

@ -0,0 +1,5 @@
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#endif
#import "Pods-SampleTests-environment.h"

@ -0,0 +1,3 @@
# Acknowledgements
This application makes use of the following third party libraries:
Generated by CocoaPods - http://cocoapods.org

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>FooterText</key>
<string>This application makes use of the following third party libraries:</string>
<key>Title</key>
<string>Acknowledgements</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Generated by CocoaPods - http://cocoapods.org</string>
<key>Title</key>
<string></string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
</array>
<key>StringsTable</key>
<string>Acknowledgements</string>
<key>Title</key>
<string>Acknowledgements</string>
</dict>
</plist>

@ -0,0 +1,5 @@
#import <Foundation/Foundation.h>
@interface PodsDummy_Pods_SampleTests : NSObject
@end
@implementation PodsDummy_Pods_SampleTests
@end

@ -0,0 +1,14 @@
// To check if a library is compiled with CocoaPods you
// can use the `COCOAPODS` macro definition which is
// defined in the xcconfigs so it is available in
// headers also when they are imported in the client
// project.
// RxLibrary
#define COCOAPODS_POD_AVAILABLE_RxLibrary
#define COCOAPODS_VERSION_MAJOR_RxLibrary 0
#define COCOAPODS_VERSION_MINOR_RxLibrary 0
#define COCOAPODS_VERSION_PATCH_RxLibrary 1

@ -0,0 +1,74 @@
#!/bin/sh
set -e
mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
> "$RESOURCES_TO_COPY"
install_resource()
{
case $1 in
*.storyboard)
echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc ${PODS_ROOT}/$1 --sdk ${SDKROOT}"
ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc" "${PODS_ROOT}/$1" --sdk "${SDKROOT}"
;;
*.xib)
echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}"
ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}"
;;
*.framework)
echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
echo "rsync -av ${PODS_ROOT}/$1 ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
rsync -av "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
;;
*.xcdatamodel)
echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1"`.mom\""
xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodel`.mom"
;;
*.xcdatamodeld)
echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd\""
xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd"
;;
*.xcmappingmodel)
echo "xcrun mapc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm\""
xcrun mapc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm"
;;
*.xcassets)
;;
/*)
echo "$1"
echo "$1" >> "$RESOURCES_TO_COPY"
;;
*)
echo "${PODS_ROOT}/$1"
echo "${PODS_ROOT}/$1" >> "$RESOURCES_TO_COPY"
;;
esac
}
rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
if [[ "${ACTION}" == "install" ]]; then
rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
fi
rm -f "$RESOURCES_TO_COPY"
if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ `find . -name '*.xcassets' | wc -l` -ne 0 ]
then
case "${TARGETED_DEVICE_FAMILY}" in
1,2)
TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
;;
1)
TARGET_DEVICE_ARGS="--target-device iphone"
;;
2)
TARGET_DEVICE_ARGS="--target-device ipad"
;;
*)
TARGET_DEVICE_ARGS="--target-device mac"
;;
esac
find "${PWD}" -name "*.xcassets" -print0 | xargs -0 actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
fi

@ -0,0 +1,6 @@
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RxLibrary"
OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/RxLibrary"
OTHER_LDFLAGS = -ObjC -l"Pods-SampleTests-RxLibrary"
OTHER_LIBTOOLFLAGS = $(OTHER_LDFLAGS)
PODS_ROOT = ${SRCROOT}/Pods

@ -0,0 +1,6 @@
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RxLibrary"
OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/RxLibrary"
OTHER_LDFLAGS = -ObjC -l"Pods-SampleTests-RxLibrary"
OTHER_LIBTOOLFLAGS = $(OTHER_LDFLAGS)
PODS_ROOT = ${SRCROOT}/Pods

@ -0,0 +1,3 @@
# Acknowledgements
This application makes use of the following third party libraries:
Generated by CocoaPods - http://cocoapods.org

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>FooterText</key>
<string>This application makes use of the following third party libraries:</string>
<key>Title</key>
<string>Acknowledgements</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Generated by CocoaPods - http://cocoapods.org</string>
<key>Title</key>
<string></string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
</array>
<key>StringsTable</key>
<string>Acknowledgements</string>
<key>Title</key>
<string>Acknowledgements</string>
</dict>
</plist>

@ -0,0 +1,5 @@
#import <Foundation/Foundation.h>
@interface PodsDummy_Pods : NSObject
@end
@implementation PodsDummy_Pods
@end

@ -0,0 +1,14 @@
// To check if a library is compiled with CocoaPods you
// can use the `COCOAPODS` macro definition which is
// defined in the xcconfigs so it is available in
// headers also when they are imported in the client
// project.
// RxLibrary
#define COCOAPODS_POD_AVAILABLE_RxLibrary
#define COCOAPODS_VERSION_MAJOR_RxLibrary 0
#define COCOAPODS_VERSION_MINOR_RxLibrary 0
#define COCOAPODS_VERSION_PATCH_RxLibrary 1

@ -0,0 +1,74 @@
#!/bin/sh
set -e
mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
> "$RESOURCES_TO_COPY"
install_resource()
{
case $1 in
*.storyboard)
echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc ${PODS_ROOT}/$1 --sdk ${SDKROOT}"
ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc" "${PODS_ROOT}/$1" --sdk "${SDKROOT}"
;;
*.xib)
echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}"
ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}"
;;
*.framework)
echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
echo "rsync -av ${PODS_ROOT}/$1 ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
rsync -av "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
;;
*.xcdatamodel)
echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1"`.mom\""
xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodel`.mom"
;;
*.xcdatamodeld)
echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd\""
xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd"
;;
*.xcmappingmodel)
echo "xcrun mapc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm\""
xcrun mapc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm"
;;
*.xcassets)
;;
/*)
echo "$1"
echo "$1" >> "$RESOURCES_TO_COPY"
;;
*)
echo "${PODS_ROOT}/$1"
echo "${PODS_ROOT}/$1" >> "$RESOURCES_TO_COPY"
;;
esac
}
rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
if [[ "${ACTION}" == "install" ]]; then
rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
fi
rm -f "$RESOURCES_TO_COPY"
if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ `find . -name '*.xcassets' | wc -l` -ne 0 ]
then
case "${TARGETED_DEVICE_FAMILY}" in
1,2)
TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
;;
1)
TARGET_DEVICE_ARGS="--target-device iphone"
;;
2)
TARGET_DEVICE_ARGS="--target-device ipad"
;;
*)
TARGET_DEVICE_ARGS="--target-device mac"
;;
esac
find "${PWD}" -name "*.xcassets" -print0 | xargs -0 actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
fi

@ -0,0 +1,6 @@
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RxLibrary"
OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/RxLibrary"
OTHER_LDFLAGS = -ObjC -l"Pods-RxLibrary"
OTHER_LIBTOOLFLAGS = $(OTHER_LDFLAGS)
PODS_ROOT = ${SRCROOT}/Pods

@ -0,0 +1,6 @@
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RxLibrary"
OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/RxLibrary"
OTHER_LDFLAGS = -ObjC -l"Pods-RxLibrary"
OTHER_LIBTOOLFLAGS = $(OTHER_LDFLAGS)
PODS_ROOT = ${SRCROOT}/Pods

@ -0,0 +1,2 @@
When contributing changes to this sample, use Cocoapods to manage the workspace
file and everything under the Pods directory.

@ -0,0 +1,955 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>archiveVersion</key>
<string>1</string>
<key>classes</key>
<dict/>
<key>objectVersion</key>
<string>46</string>
<key>objects</key>
<dict>
<key>04554623324BE4A838846086</key>
<dict>
<key>buildActionMask</key>
<string>2147483647</string>
<key>files</key>
<array/>
<key>inputPaths</key>
<array/>
<key>isa</key>
<string>PBXShellScriptBuildPhase</string>
<key>name</key>
<string>Copy Pods Resources</string>
<key>outputPaths</key>
<array/>
<key>runOnlyForDeploymentPostprocessing</key>
<string>0</string>
<key>shellPath</key>
<string>/bin/sh</string>
<key>shellScript</key>
<string>"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh"
</string>
<key>showEnvVarsInLog</key>
<string>0</string>
</dict>
<key>2DC7B7C4C0410F43B9621631</key>
<dict>
<key>explicitFileType</key>
<string>archive.ar</string>
<key>includeInIndex</key>
<string>0</string>
<key>isa</key>
<string>PBXFileReference</string>
<key>path</key>
<string>libPods.a</string>
<key>sourceTree</key>
<string>BUILT_PRODUCTS_DIR</string>
</dict>
<key>41F7486D8F66994B0BFB84AF</key>
<dict>
<key>buildActionMask</key>
<string>2147483647</string>
<key>files</key>
<array/>
<key>inputPaths</key>
<array/>
<key>isa</key>
<string>PBXShellScriptBuildPhase</string>
<key>name</key>
<string>Check Pods Manifest.lock</string>
<key>outputPaths</key>
<array/>
<key>runOnlyForDeploymentPostprocessing</key>
<string>0</string>
<key>shellPath</key>
<string>/bin/sh</string>
<key>shellScript</key>
<string>diff "${PODS_ROOT}/../Podfile.lock" "${PODS_ROOT}/Manifest.lock" &gt; /dev/null
if [[ $? != 0 ]] ; then
cat &lt;&lt; EOM
error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.
EOM
exit 1
fi
</string>
<key>showEnvVarsInLog</key>
<string>0</string>
</dict>
<key>6369A2611A9322E20015FC5C</key>
<dict>
<key>children</key>
<array>
<string>6369A26C1A9322E20015FC5C</string>
<string>6369A2861A9322E20015FC5C</string>
<string>6369A26B1A9322E20015FC5C</string>
<string>AB3331C9AE6488E61B2B094E</string>
<string>C4C2C5219053E079C9EFB930</string>
</array>
<key>isa</key>
<string>PBXGroup</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>6369A2621A9322E20015FC5C</key>
<dict>
<key>attributes</key>
<dict>
<key>LastUpgradeCheck</key>
<string>0610</string>
<key>ORGANIZATIONNAME</key>
<string>gRPC</string>
<key>TargetAttributes</key>
<dict>
<key>6369A2691A9322E20015FC5C</key>
<dict>
<key>CreatedOnToolsVersion</key>
<string>6.1.1</string>
</dict>
<key>6369A2821A9322E20015FC5C</key>
<dict>
<key>CreatedOnToolsVersion</key>
<string>6.1.1</string>
<key>TestTargetID</key>
<string>6369A2691A9322E20015FC5C</string>
</dict>
</dict>
</dict>
<key>buildConfigurationList</key>
<string>6369A2651A9322E20015FC5C</string>
<key>compatibilityVersion</key>
<string>Xcode 3.2</string>
<key>developmentRegion</key>
<string>English</string>
<key>hasScannedForEncodings</key>
<string>0</string>
<key>isa</key>
<string>PBXProject</string>
<key>knownRegions</key>
<array>
<string>en</string>
<string>Base</string>
</array>
<key>mainGroup</key>
<string>6369A2611A9322E20015FC5C</string>
<key>productRefGroup</key>
<string>6369A26B1A9322E20015FC5C</string>
<key>projectDirPath</key>
<string></string>
<key>projectReferences</key>
<array/>
<key>projectRoot</key>
<string></string>
<key>targets</key>
<array>
<string>6369A2691A9322E20015FC5C</string>
<string>6369A2821A9322E20015FC5C</string>
</array>
</dict>
<key>6369A2651A9322E20015FC5C</key>
<dict>
<key>buildConfigurations</key>
<array>
<string>6369A28B1A9322E20015FC5C</string>
<string>6369A28C1A9322E20015FC5C</string>
</array>
<key>defaultConfigurationIsVisible</key>
<string>0</string>
<key>defaultConfigurationName</key>
<string>Release</string>
<key>isa</key>
<string>XCConfigurationList</string>
</dict>
<key>6369A2661A9322E20015FC5C</key>
<dict>
<key>buildActionMask</key>
<string>2147483647</string>
<key>files</key>
<array>
<string>6369A2761A9322E20015FC5C</string>
<string>6369A2731A9322E20015FC5C</string>
<string>6369A2701A9322E20015FC5C</string>
</array>
<key>isa</key>
<string>PBXSourcesBuildPhase</string>
<key>runOnlyForDeploymentPostprocessing</key>
<string>0</string>
</dict>
<key>6369A2671A9322E20015FC5C</key>
<dict>
<key>buildActionMask</key>
<string>2147483647</string>
<key>files</key>
<array>
<string>FC81FE63CA655031F3524EC0</string>
</array>
<key>isa</key>
<string>PBXFrameworksBuildPhase</string>
<key>runOnlyForDeploymentPostprocessing</key>
<string>0</string>
</dict>
<key>6369A2681A9322E20015FC5C</key>
<dict>
<key>buildActionMask</key>
<string>2147483647</string>
<key>files</key>
<array>
<string>6369A2791A9322E20015FC5C</string>
<string>6369A27E1A9322E20015FC5C</string>
<string>6369A27B1A9322E20015FC5C</string>
</array>
<key>isa</key>
<string>PBXResourcesBuildPhase</string>
<key>runOnlyForDeploymentPostprocessing</key>
<string>0</string>
</dict>
<key>6369A2691A9322E20015FC5C</key>
<dict>
<key>buildConfigurationList</key>
<string>6369A28D1A9322E20015FC5C</string>
<key>buildPhases</key>
<array>
<string>41F7486D8F66994B0BFB84AF</string>
<string>6369A2661A9322E20015FC5C</string>
<string>6369A2671A9322E20015FC5C</string>
<string>6369A2681A9322E20015FC5C</string>
<string>04554623324BE4A838846086</string>
</array>
<key>buildRules</key>
<array/>
<key>dependencies</key>
<array/>
<key>isa</key>
<string>PBXNativeTarget</string>
<key>name</key>
<string>Sample</string>
<key>productName</key>
<string>Sample</string>
<key>productReference</key>
<string>6369A26A1A9322E20015FC5C</string>
<key>productType</key>
<string>com.apple.product-type.application</string>
</dict>
<key>6369A26A1A9322E20015FC5C</key>
<dict>
<key>explicitFileType</key>
<string>wrapper.application</string>
<key>includeInIndex</key>
<string>0</string>
<key>isa</key>
<string>PBXFileReference</string>
<key>path</key>
<string>Sample.app</string>
<key>sourceTree</key>
<string>BUILT_PRODUCTS_DIR</string>
</dict>
<key>6369A26B1A9322E20015FC5C</key>
<dict>
<key>children</key>
<array>
<string>6369A26A1A9322E20015FC5C</string>
<string>6369A2831A9322E20015FC5C</string>
</array>
<key>isa</key>
<string>PBXGroup</string>
<key>name</key>
<string>Products</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>6369A26C1A9322E20015FC5C</key>
<dict>
<key>children</key>
<array>
<string>6369A2711A9322E20015FC5C</string>
<string>6369A2721A9322E20015FC5C</string>
<string>6369A2741A9322E20015FC5C</string>
<string>6369A2751A9322E20015FC5C</string>
<string>6369A2771A9322E20015FC5C</string>
<string>6369A27A1A9322E20015FC5C</string>
<string>6369A27C1A9322E20015FC5C</string>
<string>6369A26D1A9322E20015FC5C</string>
</array>
<key>isa</key>
<string>PBXGroup</string>
<key>path</key>
<string>Sample</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>6369A26D1A9322E20015FC5C</key>
<dict>
<key>children</key>
<array>
<string>6369A26E1A9322E20015FC5C</string>
<string>6369A26F1A9322E20015FC5C</string>
</array>
<key>isa</key>
<string>PBXGroup</string>
<key>name</key>
<string>Supporting Files</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>6369A26E1A9322E20015FC5C</key>
<dict>
<key>isa</key>
<string>PBXFileReference</string>
<key>lastKnownFileType</key>
<string>text.plist.xml</string>
<key>path</key>
<string>Info.plist</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>6369A26F1A9322E20015FC5C</key>
<dict>
<key>isa</key>
<string>PBXFileReference</string>
<key>lastKnownFileType</key>
<string>sourcecode.c.objc</string>
<key>path</key>
<string>main.m</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>6369A2701A9322E20015FC5C</key>
<dict>
<key>fileRef</key>
<string>6369A26F1A9322E20015FC5C</string>
<key>isa</key>
<string>PBXBuildFile</string>
</dict>
<key>6369A2711A9322E20015FC5C</key>
<dict>
<key>isa</key>
<string>PBXFileReference</string>
<key>lastKnownFileType</key>
<string>sourcecode.c.h</string>
<key>path</key>
<string>AppDelegate.h</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>6369A2721A9322E20015FC5C</key>
<dict>
<key>isa</key>
<string>PBXFileReference</string>
<key>lastKnownFileType</key>
<string>sourcecode.c.objc</string>
<key>path</key>
<string>AppDelegate.m</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>6369A2731A9322E20015FC5C</key>
<dict>
<key>fileRef</key>
<string>6369A2721A9322E20015FC5C</string>
<key>isa</key>
<string>PBXBuildFile</string>
</dict>
<key>6369A2741A9322E20015FC5C</key>
<dict>
<key>isa</key>
<string>PBXFileReference</string>
<key>lastKnownFileType</key>
<string>sourcecode.c.h</string>
<key>path</key>
<string>ViewController.h</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>6369A2751A9322E20015FC5C</key>
<dict>
<key>isa</key>
<string>PBXFileReference</string>
<key>lastKnownFileType</key>
<string>sourcecode.c.objc</string>
<key>path</key>
<string>ViewController.m</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>6369A2761A9322E20015FC5C</key>
<dict>
<key>fileRef</key>
<string>6369A2751A9322E20015FC5C</string>
<key>isa</key>
<string>PBXBuildFile</string>
</dict>
<key>6369A2771A9322E20015FC5C</key>
<dict>
<key>children</key>
<array>
<string>6369A2781A9322E20015FC5C</string>
</array>
<key>isa</key>
<string>PBXVariantGroup</string>
<key>name</key>
<string>Main.storyboard</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>6369A2781A9322E20015FC5C</key>
<dict>
<key>isa</key>
<string>PBXFileReference</string>
<key>lastKnownFileType</key>
<string>file.storyboard</string>
<key>name</key>
<string>Base</string>
<key>path</key>
<string>Base.lproj/Main.storyboard</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>6369A2791A9322E20015FC5C</key>
<dict>
<key>fileRef</key>
<string>6369A2771A9322E20015FC5C</string>
<key>isa</key>
<string>PBXBuildFile</string>
</dict>
<key>6369A27A1A9322E20015FC5C</key>
<dict>
<key>isa</key>
<string>PBXFileReference</string>
<key>lastKnownFileType</key>
<string>folder.assetcatalog</string>
<key>path</key>
<string>Images.xcassets</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>6369A27B1A9322E20015FC5C</key>
<dict>
<key>fileRef</key>
<string>6369A27A1A9322E20015FC5C</string>
<key>isa</key>
<string>PBXBuildFile</string>
</dict>
<key>6369A27C1A9322E20015FC5C</key>
<dict>
<key>children</key>
<array>
<string>6369A27D1A9322E20015FC5C</string>
</array>
<key>isa</key>
<string>PBXVariantGroup</string>
<key>name</key>
<string>LaunchScreen.xib</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>6369A27D1A9322E20015FC5C</key>
<dict>
<key>isa</key>
<string>PBXFileReference</string>
<key>lastKnownFileType</key>
<string>file.xib</string>
<key>name</key>
<string>Base</string>
<key>path</key>
<string>Base.lproj/LaunchScreen.xib</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>6369A27E1A9322E20015FC5C</key>
<dict>
<key>fileRef</key>
<string>6369A27C1A9322E20015FC5C</string>
<key>isa</key>
<string>PBXBuildFile</string>
</dict>
<key>6369A27F1A9322E20015FC5C</key>
<dict>
<key>buildActionMask</key>
<string>2147483647</string>
<key>files</key>
<array>
<string>6369A28A1A9322E20015FC5C</string>
</array>
<key>isa</key>
<string>PBXSourcesBuildPhase</string>
<key>runOnlyForDeploymentPostprocessing</key>
<string>0</string>
</dict>
<key>6369A2801A9322E20015FC5C</key>
<dict>
<key>buildActionMask</key>
<string>2147483647</string>
<key>files</key>
<array/>
<key>isa</key>
<string>PBXFrameworksBuildPhase</string>
<key>runOnlyForDeploymentPostprocessing</key>
<string>0</string>
</dict>
<key>6369A2811A9322E20015FC5C</key>
<dict>
<key>buildActionMask</key>
<string>2147483647</string>
<key>files</key>
<array/>
<key>isa</key>
<string>PBXResourcesBuildPhase</string>
<key>runOnlyForDeploymentPostprocessing</key>
<string>0</string>
</dict>
<key>6369A2821A9322E20015FC5C</key>
<dict>
<key>buildConfigurationList</key>
<string>6369A2901A9322E20015FC5C</string>
<key>buildPhases</key>
<array>
<string>6369A27F1A9322E20015FC5C</string>
<string>6369A2801A9322E20015FC5C</string>
<string>6369A2811A9322E20015FC5C</string>
</array>
<key>buildRules</key>
<array/>
<key>dependencies</key>
<array>
<string>6369A2851A9322E20015FC5C</string>
</array>
<key>isa</key>
<string>PBXNativeTarget</string>
<key>name</key>
<string>SampleTests</string>
<key>productName</key>
<string>SampleTests</string>
<key>productReference</key>
<string>6369A2831A9322E20015FC5C</string>
<key>productType</key>
<string>com.apple.product-type.bundle.unit-test</string>
</dict>
<key>6369A2831A9322E20015FC5C</key>
<dict>
<key>explicitFileType</key>
<string>wrapper.cfbundle</string>
<key>includeInIndex</key>
<string>0</string>
<key>isa</key>
<string>PBXFileReference</string>
<key>path</key>
<string>SampleTests.xctest</string>
<key>sourceTree</key>
<string>BUILT_PRODUCTS_DIR</string>
</dict>
<key>6369A2841A9322E20015FC5C</key>
<dict>
<key>containerPortal</key>
<string>6369A2621A9322E20015FC5C</string>
<key>isa</key>
<string>PBXContainerItemProxy</string>
<key>proxyType</key>
<string>1</string>
<key>remoteGlobalIDString</key>
<string>6369A2691A9322E20015FC5C</string>
<key>remoteInfo</key>
<string>Sample</string>
</dict>
<key>6369A2851A9322E20015FC5C</key>
<dict>
<key>isa</key>
<string>PBXTargetDependency</string>
<key>target</key>
<string>6369A2691A9322E20015FC5C</string>
<key>targetProxy</key>
<string>6369A2841A9322E20015FC5C</string>
</dict>
<key>6369A2861A9322E20015FC5C</key>
<dict>
<key>children</key>
<array>
<string>6369A2891A9322E20015FC5C</string>
<string>6369A2871A9322E20015FC5C</string>
</array>
<key>isa</key>
<string>PBXGroup</string>
<key>path</key>
<string>SampleTests</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>6369A2871A9322E20015FC5C</key>
<dict>
<key>children</key>
<array>
<string>6369A2881A9322E20015FC5C</string>
</array>
<key>isa</key>
<string>PBXGroup</string>
<key>name</key>
<string>Supporting Files</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>6369A2881A9322E20015FC5C</key>
<dict>
<key>isa</key>
<string>PBXFileReference</string>
<key>lastKnownFileType</key>
<string>text.plist.xml</string>
<key>path</key>
<string>Info.plist</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>6369A2891A9322E20015FC5C</key>
<dict>
<key>isa</key>
<string>PBXFileReference</string>
<key>lastKnownFileType</key>
<string>sourcecode.c.objc</string>
<key>path</key>
<string>SampleTests.m</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>6369A28A1A9322E20015FC5C</key>
<dict>
<key>fileRef</key>
<string>6369A2891A9322E20015FC5C</string>
<key>isa</key>
<string>PBXBuildFile</string>
</dict>
<key>6369A28B1A9322E20015FC5C</key>
<dict>
<key>buildSettings</key>
<dict>
<key>ALWAYS_SEARCH_USER_PATHS</key>
<string>NO</string>
<key>CLANG_CXX_LANGUAGE_STANDARD</key>
<string>gnu++0x</string>
<key>CLANG_CXX_LIBRARY</key>
<string>libc++</string>
<key>CLANG_ENABLE_MODULES</key>
<string>YES</string>
<key>CLANG_ENABLE_OBJC_ARC</key>
<string>YES</string>
<key>CLANG_WARN_BOOL_CONVERSION</key>
<string>YES</string>
<key>CLANG_WARN_CONSTANT_CONVERSION</key>
<string>YES</string>
<key>CLANG_WARN_DIRECT_OBJC_ISA_USAGE</key>
<string>YES_ERROR</string>
<key>CLANG_WARN_EMPTY_BODY</key>
<string>YES</string>
<key>CLANG_WARN_ENUM_CONVERSION</key>
<string>YES</string>
<key>CLANG_WARN_INT_CONVERSION</key>
<string>YES</string>
<key>CLANG_WARN_OBJC_ROOT_CLASS</key>
<string>YES_ERROR</string>
<key>CLANG_WARN_UNREACHABLE_CODE</key>
<string>YES</string>
<key>CLANG_WARN__DUPLICATE_METHOD_MATCH</key>
<string>YES</string>
<key>CODE_SIGN_IDENTITY[sdk=iphoneos*]</key>
<string>iPhone Developer</string>
<key>COPY_PHASE_STRIP</key>
<string>NO</string>
<key>ENABLE_STRICT_OBJC_MSGSEND</key>
<string>YES</string>
<key>GCC_C_LANGUAGE_STANDARD</key>
<string>gnu99</string>
<key>GCC_DYNAMIC_NO_PIC</key>
<string>NO</string>
<key>GCC_OPTIMIZATION_LEVEL</key>
<string>0</string>
<key>GCC_PREPROCESSOR_DEFINITIONS</key>
<array>
<string>DEBUG=1</string>
<string>$(inherited)</string>
</array>
<key>GCC_SYMBOLS_PRIVATE_EXTERN</key>
<string>NO</string>
<key>GCC_WARN_64_TO_32_BIT_CONVERSION</key>
<string>YES</string>
<key>GCC_WARN_ABOUT_RETURN_TYPE</key>
<string>YES_ERROR</string>
<key>GCC_WARN_UNDECLARED_SELECTOR</key>
<string>YES</string>
<key>GCC_WARN_UNINITIALIZED_AUTOS</key>
<string>YES_AGGRESSIVE</string>
<key>GCC_WARN_UNUSED_FUNCTION</key>
<string>YES</string>
<key>GCC_WARN_UNUSED_VARIABLE</key>
<string>YES</string>
<key>IPHONEOS_DEPLOYMENT_TARGET</key>
<string>8.1</string>
<key>MTL_ENABLE_DEBUG_INFO</key>
<string>YES</string>
<key>ONLY_ACTIVE_ARCH</key>
<string>YES</string>
<key>SDKROOT</key>
<string>iphoneos</string>
<key>TARGETED_DEVICE_FAMILY</key>
<string>1,2</string>
</dict>
<key>isa</key>
<string>XCBuildConfiguration</string>
<key>name</key>
<string>Debug</string>
</dict>
<key>6369A28C1A9322E20015FC5C</key>
<dict>
<key>buildSettings</key>
<dict>
<key>ALWAYS_SEARCH_USER_PATHS</key>
<string>NO</string>
<key>CLANG_CXX_LANGUAGE_STANDARD</key>
<string>gnu++0x</string>
<key>CLANG_CXX_LIBRARY</key>
<string>libc++</string>
<key>CLANG_ENABLE_MODULES</key>
<string>YES</string>
<key>CLANG_ENABLE_OBJC_ARC</key>
<string>YES</string>
<key>CLANG_WARN_BOOL_CONVERSION</key>
<string>YES</string>
<key>CLANG_WARN_CONSTANT_CONVERSION</key>
<string>YES</string>
<key>CLANG_WARN_DIRECT_OBJC_ISA_USAGE</key>
<string>YES_ERROR</string>
<key>CLANG_WARN_EMPTY_BODY</key>
<string>YES</string>
<key>CLANG_WARN_ENUM_CONVERSION</key>
<string>YES</string>
<key>CLANG_WARN_INT_CONVERSION</key>
<string>YES</string>
<key>CLANG_WARN_OBJC_ROOT_CLASS</key>
<string>YES_ERROR</string>
<key>CLANG_WARN_UNREACHABLE_CODE</key>
<string>YES</string>
<key>CLANG_WARN__DUPLICATE_METHOD_MATCH</key>
<string>YES</string>
<key>CODE_SIGN_IDENTITY[sdk=iphoneos*]</key>
<string>iPhone Developer</string>
<key>COPY_PHASE_STRIP</key>
<string>YES</string>
<key>ENABLE_NS_ASSERTIONS</key>
<string>NO</string>
<key>ENABLE_STRICT_OBJC_MSGSEND</key>
<string>YES</string>
<key>GCC_C_LANGUAGE_STANDARD</key>
<string>gnu99</string>
<key>GCC_WARN_64_TO_32_BIT_CONVERSION</key>
<string>YES</string>
<key>GCC_WARN_ABOUT_RETURN_TYPE</key>
<string>YES_ERROR</string>
<key>GCC_WARN_UNDECLARED_SELECTOR</key>
<string>YES</string>
<key>GCC_WARN_UNINITIALIZED_AUTOS</key>
<string>YES_AGGRESSIVE</string>
<key>GCC_WARN_UNUSED_FUNCTION</key>
<string>YES</string>
<key>GCC_WARN_UNUSED_VARIABLE</key>
<string>YES</string>
<key>IPHONEOS_DEPLOYMENT_TARGET</key>
<string>8.1</string>
<key>MTL_ENABLE_DEBUG_INFO</key>
<string>NO</string>
<key>SDKROOT</key>
<string>iphoneos</string>
<key>TARGETED_DEVICE_FAMILY</key>
<string>1,2</string>
<key>VALIDATE_PRODUCT</key>
<string>YES</string>
</dict>
<key>isa</key>
<string>XCBuildConfiguration</string>
<key>name</key>
<string>Release</string>
</dict>
<key>6369A28D1A9322E20015FC5C</key>
<dict>
<key>buildConfigurations</key>
<array>
<string>6369A28E1A9322E20015FC5C</string>
<string>6369A28F1A9322E20015FC5C</string>
</array>
<key>defaultConfigurationIsVisible</key>
<string>0</string>
<key>isa</key>
<string>XCConfigurationList</string>
</dict>
<key>6369A28E1A9322E20015FC5C</key>
<dict>
<key>baseConfigurationReference</key>
<string>AC29DD6FCDF962F519FEBB0D</string>
<key>buildSettings</key>
<dict>
<key>ASSETCATALOG_COMPILER_APPICON_NAME</key>
<string>AppIcon</string>
<key>INFOPLIST_FILE</key>
<string>Sample/Info.plist</string>
<key>LD_RUNPATH_SEARCH_PATHS</key>
<string>$(inherited) @executable_path/Frameworks</string>
<key>PRODUCT_NAME</key>
<string>$(TARGET_NAME)</string>
</dict>
<key>isa</key>
<string>XCBuildConfiguration</string>
<key>name</key>
<string>Debug</string>
</dict>
<key>6369A28F1A9322E20015FC5C</key>
<dict>
<key>baseConfigurationReference</key>
<string>C68330F8D451CC6ACEABA09F</string>
<key>buildSettings</key>
<dict>
<key>ASSETCATALOG_COMPILER_APPICON_NAME</key>
<string>AppIcon</string>
<key>INFOPLIST_FILE</key>
<string>Sample/Info.plist</string>
<key>LD_RUNPATH_SEARCH_PATHS</key>
<string>$(inherited) @executable_path/Frameworks</string>
<key>PRODUCT_NAME</key>
<string>$(TARGET_NAME)</string>
</dict>
<key>isa</key>
<string>XCBuildConfiguration</string>
<key>name</key>
<string>Release</string>
</dict>
<key>6369A2901A9322E20015FC5C</key>
<dict>
<key>buildConfigurations</key>
<array>
<string>6369A2911A9322E20015FC5C</string>
<string>6369A2921A9322E20015FC5C</string>
</array>
<key>defaultConfigurationIsVisible</key>
<string>0</string>
<key>isa</key>
<string>XCConfigurationList</string>
</dict>
<key>6369A2911A9322E20015FC5C</key>
<dict>
<key>buildSettings</key>
<dict>
<key>BUNDLE_LOADER</key>
<string>$(TEST_HOST)</string>
<key>FRAMEWORK_SEARCH_PATHS</key>
<array>
<string>$(SDKROOT)/Developer/Library/Frameworks</string>
<string>$(inherited)</string>
</array>
<key>GCC_PREPROCESSOR_DEFINITIONS</key>
<array>
<string>DEBUG=1</string>
<string>$(inherited)</string>
</array>
<key>INFOPLIST_FILE</key>
<string>SampleTests/Info.plist</string>
<key>LD_RUNPATH_SEARCH_PATHS</key>
<string>$(inherited) @executable_path/Frameworks @loader_path/Frameworks</string>
<key>PRODUCT_NAME</key>
<string>$(TARGET_NAME)</string>
<key>TEST_HOST</key>
<string>$(BUILT_PRODUCTS_DIR)/Sample.app/Sample</string>
</dict>
<key>isa</key>
<string>XCBuildConfiguration</string>
<key>name</key>
<string>Debug</string>
</dict>
<key>6369A2921A9322E20015FC5C</key>
<dict>
<key>buildSettings</key>
<dict>
<key>BUNDLE_LOADER</key>
<string>$(TEST_HOST)</string>
<key>FRAMEWORK_SEARCH_PATHS</key>
<array>
<string>$(SDKROOT)/Developer/Library/Frameworks</string>
<string>$(inherited)</string>
</array>
<key>INFOPLIST_FILE</key>
<string>SampleTests/Info.plist</string>
<key>LD_RUNPATH_SEARCH_PATHS</key>
<string>$(inherited) @executable_path/Frameworks @loader_path/Frameworks</string>
<key>PRODUCT_NAME</key>
<string>$(TARGET_NAME)</string>
<key>TEST_HOST</key>
<string>$(BUILT_PRODUCTS_DIR)/Sample.app/Sample</string>
</dict>
<key>isa</key>
<string>XCBuildConfiguration</string>
<key>name</key>
<string>Release</string>
</dict>
<key>AB3331C9AE6488E61B2B094E</key>
<dict>
<key>children</key>
<array>
<string>AC29DD6FCDF962F519FEBB0D</string>
<string>C68330F8D451CC6ACEABA09F</string>
</array>
<key>isa</key>
<string>PBXGroup</string>
<key>name</key>
<string>Pods</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>AC29DD6FCDF962F519FEBB0D</key>
<dict>
<key>includeInIndex</key>
<string>1</string>
<key>isa</key>
<string>PBXFileReference</string>
<key>lastKnownFileType</key>
<string>text.xcconfig</string>
<key>name</key>
<string>Pods.debug.xcconfig</string>
<key>path</key>
<string>Pods/Target Support Files/Pods/Pods.debug.xcconfig</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>C4C2C5219053E079C9EFB930</key>
<dict>
<key>children</key>
<array>
<string>2DC7B7C4C0410F43B9621631</string>
</array>
<key>isa</key>
<string>PBXGroup</string>
<key>name</key>
<string>Frameworks</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>C68330F8D451CC6ACEABA09F</key>
<dict>
<key>includeInIndex</key>
<string>1</string>
<key>isa</key>
<string>PBXFileReference</string>
<key>lastKnownFileType</key>
<string>text.xcconfig</string>
<key>name</key>
<string>Pods.release.xcconfig</string>
<key>path</key>
<string>Pods/Target Support Files/Pods/Pods.release.xcconfig</string>
<key>sourceTree</key>
<string>&lt;group&gt;</string>
</dict>
<key>FC81FE63CA655031F3524EC0</key>
<dict>
<key>fileRef</key>
<string>2DC7B7C4C0410F43B9621631</string>
<key>isa</key>
<string>PBXBuildFile</string>
</dict>
</dict>
<key>rootObject</key>
<string>6369A2621A9322E20015FC5C</string>
</dict>
</plist>

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:Sample.xcodeproj">
</FileRef>
</Workspace>

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Sample.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

@ -0,0 +1,17 @@
//
// AppDelegate.h
// Sample
//
// Created by Jorge Canizalez Diaz on 2/16/15.
// Copyright (c) 2015 gRPC. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end

@ -0,0 +1,45 @@
//
// AppDelegate.m
// Sample
//
// Created by Jorge Canizalez Diaz on 2/16/15.
// Copyright (c) 2015 gRPC. All rights reserved.
//
#import "AppDelegate.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
@end

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6214" systemVersion="14A314h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6207"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 gRPC. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439" width="441" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Sample" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="140" width="441" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="548" y="455"/>
</view>
</objects>
</document>

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6211" systemVersion="14A298i" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6204"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

@ -0,0 +1,68 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>org.grpc.$(PRODUCT_NAME:rfc1034identifier)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

@ -0,0 +1,15 @@
//
// ViewController.h
// Sample
//
// Created by Jorge Canizalez Diaz on 2/16/15.
// Copyright (c) 2015 gRPC. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end

@ -0,0 +1,27 @@
//
// ViewController.m
// Sample
//
// Created by Jorge Canizalez Diaz on 2/16/15.
// Copyright (c) 2015 gRPC. All rights reserved.
//
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end

@ -0,0 +1,16 @@
//
// main.m
// Sample
//
// Created by Jorge Canizalez Diaz on 2/16/15.
// Copyright (c) 2015 gRPC. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save