aboutsummaryrefslogtreecommitdiffhomepage
path: root/examples/objective-c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/objective-c')
-rw-r--r--examples/objective-c/auth_sample/AuthSample.xcodeproj/project.pbxproj366
-rw-r--r--examples/objective-c/auth_sample/AuthSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata7
-rw-r--r--examples/objective-c/auth_sample/AuthTestService.podspec35
-rw-r--r--examples/objective-c/auth_sample/MakeRPCViewController.h40
-rw-r--r--examples/objective-c/auth_sample/MakeRPCViewController.m100
-rw-r--r--examples/objective-c/auth_sample/Misc/AppDelegate.h38
-rw-r--r--examples/objective-c/auth_sample/Misc/AppDelegate.m61
-rw-r--r--examples/objective-c/auth_sample/Misc/Base.lproj/Main.storyboard154
-rw-r--r--examples/objective-c/auth_sample/Misc/GoogleService-Info.plist10
-rw-r--r--examples/objective-c/auth_sample/Misc/Images.xcassets/AppIcon.appiconset/Contents.json68
-rw-r--r--examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/Contents.json12
-rw-r--r--examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/first.pdfbin0 -> 2465 bytes
-rw-r--r--examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/Contents.json12
-rw-r--r--examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/second.pdfbin0 -> 2423 bytes
-rw-r--r--examples/objective-c/auth_sample/Misc/Info.plist80
-rw-r--r--examples/objective-c/auth_sample/Misc/main.m41
-rw-r--r--examples/objective-c/auth_sample/Podfile10
-rw-r--r--examples/objective-c/auth_sample/README.md189
-rw-r--r--examples/objective-c/auth_sample/SelectUserViewController.h42
-rw-r--r--examples/objective-c/auth_sample/SelectUserViewController.m86
-rw-r--r--examples/objective-c/helloworld/HelloWorld.podspec35
-rw-r--r--examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj349
-rw-r--r--examples/objective-c/helloworld/HelloWorld.xcodeproj/project.xcworkspace/contents.xcworkspacedata7
-rw-r--r--examples/objective-c/helloworld/HelloWorld/AppDelegate.h38
-rw-r--r--examples/objective-c/helloworld/HelloWorld/AppDelegate.m37
-rw-r--r--examples/objective-c/helloworld/HelloWorld/Base.lproj/Main.storyboard25
-rw-r--r--examples/objective-c/helloworld/HelloWorld/Images.xcassets/AppIcon.appiconset/Contents.json68
-rw-r--r--examples/objective-c/helloworld/HelloWorld/Info.plist47
-rw-r--r--examples/objective-c/helloworld/HelloWorld/ViewController.m40
-rw-r--r--examples/objective-c/helloworld/Podfile7
-rw-r--r--examples/objective-c/helloworld/README.md56
-rw-r--r--examples/objective-c/helloworld/main.m51
-rw-r--r--examples/objective-c/route_guide/Misc/AppDelegate.h38
-rw-r--r--examples/objective-c/route_guide/Misc/AppDelegate.m37
-rw-r--r--examples/objective-c/route_guide/Misc/Base.lproj/Main.storyboard193
-rw-r--r--examples/objective-c/route_guide/Misc/Images.xcassets/AppIcon.appiconset/Contents.json68
-rw-r--r--examples/objective-c/route_guide/Misc/Images.xcassets/first.imageset/Contents.json12
-rw-r--r--examples/objective-c/route_guide/Misc/Images.xcassets/first.imageset/first.pdfbin0 -> 2465 bytes
-rw-r--r--examples/objective-c/route_guide/Misc/Images.xcassets/second.imageset/Contents.json12
-rw-r--r--examples/objective-c/route_guide/Misc/Images.xcassets/second.imageset/second.pdfbin0 -> 2423 bytes
-rw-r--r--examples/objective-c/route_guide/Misc/Info.plist57
-rw-r--r--examples/objective-c/route_guide/Misc/main.m41
-rw-r--r--examples/objective-c/route_guide/Podfile7
-rw-r--r--examples/objective-c/route_guide/README.md360
-rw-r--r--examples/objective-c/route_guide/RouteGuide.podspec35
-rw-r--r--examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.pbxproj366
-rw-r--r--examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.xcworkspace/contents.xcworkspacedata7
-rw-r--r--examples/objective-c/route_guide/ViewControllers.m228
-rw-r--r--examples/objective-c/route_guide/route_guide_db.json121
49 files changed, 3693 insertions, 0 deletions
diff --git a/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.pbxproj b/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.pbxproj
new file mode 100644
index 0000000000..51a39c578c
--- /dev/null
+++ b/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.pbxproj
@@ -0,0 +1,366 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 63E1E9821B28CB2100EF0978 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E1E9811B28CB2100EF0978 /* main.m */; };
+ 63E1E9851B28CB2100EF0978 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E1E9841B28CB2100EF0978 /* AppDelegate.m */; };
+ 63E1E9881B28CB2100EF0978 /* SelectUserViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E1E9871B28CB2100EF0978 /* SelectUserViewController.m */; };
+ 63E1E98B1B28CB2100EF0978 /* MakeRPCViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E1E98A1B28CB2100EF0978 /* MakeRPCViewController.m */; };
+ 63E1E98E1B28CB2100EF0978 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 63E1E98C1B28CB2100EF0978 /* Main.storyboard */; };
+ 63E1E9901B28CB2100EF0978 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 63E1E98F1B28CB2100EF0978 /* Images.xcassets */; };
+ 63F5DE481B28F5C100CDD07E /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 63F5DE471B28F5C100CDD07E /* GoogleService-Info.plist */; };
+ 832213142AB24DB816D02635 /* libPods-AuthSample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F217A6ECA7F5BD1D5FB5071B /* libPods-AuthSample.a */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 63E1E97C1B28CB2100EF0978 /* AuthSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AuthSample.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 63E1E9801B28CB2100EF0978 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 63E1E9811B28CB2100EF0978 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ 63E1E9831B28CB2100EF0978 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+ 63E1E9841B28CB2100EF0978 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+ 63E1E9861B28CB2100EF0978 /* SelectUserViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SelectUserViewController.h; sourceTree = "<group>"; };
+ 63E1E9871B28CB2100EF0978 /* SelectUserViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SelectUserViewController.m; sourceTree = "<group>"; };
+ 63E1E9891B28CB2100EF0978 /* MakeRPCViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MakeRPCViewController.h; sourceTree = "<group>"; };
+ 63E1E98A1B28CB2100EF0978 /* MakeRPCViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MakeRPCViewController.m; sourceTree = "<group>"; };
+ 63E1E98D1B28CB2100EF0978 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+ 63E1E98F1B28CB2100EF0978 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
+ 63F5DE471B28F5C100CDD07E /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
+ A387D6CECBCF2EAF2983033A /* Pods-AuthSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AuthSample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-AuthSample/Pods-AuthSample.debug.xcconfig"; sourceTree = "<group>"; };
+ B444176735DA81FBE4B8B80C /* Pods-AuthSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AuthSample.release.xcconfig"; path = "Pods/Target Support Files/Pods-AuthSample/Pods-AuthSample.release.xcconfig"; sourceTree = "<group>"; };
+ F217A6ECA7F5BD1D5FB5071B /* libPods-AuthSample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AuthSample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 63E1E9791B28CB2000EF0978 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 832213142AB24DB816D02635 /* libPods-AuthSample.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 021FA0E0B3F5D3D477DDAC10 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ A387D6CECBCF2EAF2983033A /* Pods-AuthSample.debug.xcconfig */,
+ B444176735DA81FBE4B8B80C /* Pods-AuthSample.release.xcconfig */,
+ );
+ name = Pods;
+ sourceTree = "<group>";
+ };
+ 4F443572636F3D60F26E870D /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ F217A6ECA7F5BD1D5FB5071B /* libPods-AuthSample.a */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 63E1E9731B28CB2000EF0978 = {
+ isa = PBXGroup;
+ children = (
+ 63E1E97E1B28CB2100EF0978 /* AuthSample */,
+ 63E1E97D1B28CB2100EF0978 /* Products */,
+ 021FA0E0B3F5D3D477DDAC10 /* Pods */,
+ 4F443572636F3D60F26E870D /* Frameworks */,
+ );
+ sourceTree = "<group>";
+ };
+ 63E1E97D1B28CB2100EF0978 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 63E1E97C1B28CB2100EF0978 /* AuthSample.app */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 63E1E97E1B28CB2100EF0978 /* AuthSample */ = {
+ isa = PBXGroup;
+ children = (
+ 63E1E9861B28CB2100EF0978 /* SelectUserViewController.h */,
+ 63E1E9871B28CB2100EF0978 /* SelectUserViewController.m */,
+ 63E1E9891B28CB2100EF0978 /* MakeRPCViewController.h */,
+ 63E1E98A1B28CB2100EF0978 /* MakeRPCViewController.m */,
+ 63E1E97F1B28CB2100EF0978 /* Supporting Files */,
+ );
+ name = AuthSample;
+ sourceTree = SOURCE_ROOT;
+ };
+ 63E1E97F1B28CB2100EF0978 /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ 63E1E98C1B28CB2100EF0978 /* Main.storyboard */,
+ 63F5DE471B28F5C100CDD07E /* GoogleService-Info.plist */,
+ 63E1E98F1B28CB2100EF0978 /* Images.xcassets */,
+ 63E1E9801B28CB2100EF0978 /* Info.plist */,
+ 63E1E9831B28CB2100EF0978 /* AppDelegate.h */,
+ 63E1E9841B28CB2100EF0978 /* AppDelegate.m */,
+ 63E1E9811B28CB2100EF0978 /* main.m */,
+ );
+ name = "Supporting Files";
+ path = Misc;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 63E1E97B1B28CB2000EF0978 /* AuthSample */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 63E1E9A21B28CB2100EF0978 /* Build configuration list for PBXNativeTarget "AuthSample" */;
+ buildPhases = (
+ DAABBA7B5788A39108D7CA83 /* Check Pods Manifest.lock */,
+ 63E1E9781B28CB2000EF0978 /* Sources */,
+ 63E1E9791B28CB2000EF0978 /* Frameworks */,
+ 63E1E97A1B28CB2000EF0978 /* Resources */,
+ AEFCCC69DD59CE8F6EB769D7 /* Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = AuthSample;
+ productName = AuthSample;
+ productReference = 63E1E97C1B28CB2100EF0978 /* AuthSample.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 63E1E9741B28CB2000EF0978 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0630;
+ ORGANIZATIONNAME = gRPC;
+ TargetAttributes = {
+ 63E1E97B1B28CB2000EF0978 = {
+ CreatedOnToolsVersion = 6.3.1;
+ };
+ };
+ };
+ buildConfigurationList = 63E1E9771B28CB2000EF0978 /* Build configuration list for PBXProject "AuthSample" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 63E1E9731B28CB2000EF0978;
+ productRefGroup = 63E1E97D1B28CB2100EF0978 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 63E1E97B1B28CB2000EF0978 /* AuthSample */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 63E1E97A1B28CB2000EF0978 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 63E1E98E1B28CB2100EF0978 /* Main.storyboard in Resources */,
+ 63E1E9901B28CB2100EF0978 /* Images.xcassets in Resources */,
+ 63F5DE481B28F5C100CDD07E /* GoogleService-Info.plist in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ AEFCCC69DD59CE8F6EB769D7 /* Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AuthSample/Pods-AuthSample-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ DAABBA7B5788A39108D7CA83 /* Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Check Pods Manifest.lock";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 63E1E9781B28CB2000EF0978 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 63E1E98B1B28CB2100EF0978 /* MakeRPCViewController.m in Sources */,
+ 63E1E9851B28CB2100EF0978 /* AppDelegate.m in Sources */,
+ 63E1E9881B28CB2100EF0978 /* SelectUserViewController.m in Sources */,
+ 63E1E9821B28CB2100EF0978 /* main.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ 63E1E98C1B28CB2100EF0978 /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 63E1E98D1B28CB2100EF0978 /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 63E1E9A01B28CB2100EF0978 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.3;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 63E1E9A11B28CB2100EF0978 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.3;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 63E1E9A31B28CB2100EF0978 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = A387D6CECBCF2EAF2983033A /* Pods-AuthSample.debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = Misc/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 63E1E9A41B28CB2100EF0978 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = B444176735DA81FBE4B8B80C /* Pods-AuthSample.release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = Misc/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 63E1E9771B28CB2000EF0978 /* Build configuration list for PBXProject "AuthSample" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 63E1E9A01B28CB2100EF0978 /* Debug */,
+ 63E1E9A11B28CB2100EF0978 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 63E1E9A21B28CB2100EF0978 /* Build configuration list for PBXNativeTarget "AuthSample" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 63E1E9A31B28CB2100EF0978 /* Debug */,
+ 63E1E9A41B28CB2100EF0978 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 63E1E9741B28CB2000EF0978 /* Project object */;
+}
diff --git a/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000000..39b57a4b33
--- /dev/null
+++ b/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:AuthSample.xcodeproj">
+ </FileRef>
+</Workspace>
diff --git a/examples/objective-c/auth_sample/AuthTestService.podspec b/examples/objective-c/auth_sample/AuthTestService.podspec
new file mode 100644
index 0000000000..9f2a2cc361
--- /dev/null
+++ b/examples/objective-c/auth_sample/AuthTestService.podspec
@@ -0,0 +1,35 @@
+Pod::Spec.new do |s|
+ s.name = "AuthTestService"
+ s.version = "0.0.1"
+ s.license = "New BSD"
+
+ s.ios.deployment_target = "6.0"
+ s.osx.deployment_target = "10.8"
+
+ # Base directory where the .proto files are.
+ src = "../../protos"
+
+ # Directory where the generated files will be place.
+ dir = "Pods/" + s.name
+
+ # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
+ s.prepare_command = <<-CMD
+ mkdir -p #{dir}
+ protoc -I #{src} --objc_out=#{dir} --objcgrpc_out=#{dir} #{src}/auth_sample.proto
+ CMD
+
+ s.subspec "Messages" do |ms|
+ ms.source_files = "#{dir}/*.pbobjc.{h,m}", "#{dir}/**/*.pbobjc.{h,m}"
+ ms.header_mappings_dir = dir
+ ms.requires_arc = false
+ ms.dependency "Protobuf", "~> 3.0.0-alpha-3"
+ end
+
+ s.subspec "Services" do |ss|
+ ss.source_files = "#{dir}/*.pbrpc.{h,m}", "#{dir}/**/*.pbrpc.{h,m}"
+ ss.header_mappings_dir = dir
+ ss.requires_arc = true
+ ss.dependency "gRPC", "~> 0.6"
+ ss.dependency "#{s.name}/Messages"
+ end
+end
diff --git a/examples/objective-c/auth_sample/MakeRPCViewController.h b/examples/objective-c/auth_sample/MakeRPCViewController.h
new file mode 100644
index 0000000000..c75a8b3180
--- /dev/null
+++ b/examples/objective-c/auth_sample/MakeRPCViewController.h
@@ -0,0 +1,40 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+
+extern NSString * const kTestScope;
+
+@interface MakeRPCViewController : UIViewController
+@property(weak, nonatomic) IBOutlet UILabel *mainLabel;
+@end
diff --git a/examples/objective-c/auth_sample/MakeRPCViewController.m b/examples/objective-c/auth_sample/MakeRPCViewController.m
new file mode 100644
index 0000000000..366bc9deea
--- /dev/null
+++ b/examples/objective-c/auth_sample/MakeRPCViewController.m
@@ -0,0 +1,100 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import "MakeRPCViewController.h"
+
+#import <AuthTestService/AuthSample.pbrpc.h>
+#import <Google/SignIn.h>
+#include <grpc/status.h>
+#import <ProtoRPC/ProtoRPC.h>
+
+NSString * const kTestScope = @"https://www.googleapis.com/auth/xapi.zoo";
+
+static NSString * const kTestHostAddress = @"grpc-test.sandbox.google.com";
+
+// Category for RPC errors to create the descriptions as we want them to appear on our view.
+@interface NSError (AuthSample)
+- (NSString *)UIDescription;
+@end
+
+@implementation NSError (AuthSample)
+- (NSString *)UIDescription {
+ if (self.code == GRPC_STATUS_UNAUTHENTICATED) {
+ // Authentication error. OAuth2 specifies we'll receive a challenge header.
+ // |userInfo[kGRPCStatusMetadataKey]| is the dictionary of response metadata.
+ NSString *challengeHeader = self.userInfo[kGRPCStatusMetadataKey][@"www-authenticate"] ?: @"";
+ return [@"Invalid credentials. Server challenge:\n" stringByAppendingString:challengeHeader];
+ } else {
+ // Any other error.
+ return [NSString stringWithFormat:@"Unexpected RPC error %li: %@",
+ (long)self.code, self.localizedDescription];
+ }
+}
+@end
+
+@implementation MakeRPCViewController
+
+- (void)viewWillAppear:(BOOL)animated {
+
+ // Create a service client and a proto request as usual.
+ AUTHTestService *client = [[AUTHTestService alloc] initWithHost:kTestHostAddress];
+
+ AUTHRequest *request = [AUTHRequest message];
+ request.fillUsername = YES;
+ request.fillOauthScope = YES;
+
+ // Create a not-yet-started RPC. We want to set the request headers on this object before starting
+ // it.
+ ProtoRPC *call =
+ [client RPCToUnaryCallWithRequest:request handler:^(AUTHResponse *response, NSError *error) {
+ if (response) {
+ // This test server responds with the email and scope of the access token it receives.
+ self.mainLabel.text = [NSString stringWithFormat:@"Used scope: %@ on behalf of user %@",
+ response.oauthScope, response.username];
+
+ } else {
+ self.mainLabel.text = error.UIDescription;
+ }
+ }];
+
+ // Set the access token to be used.
+ NSString *accessToken = GIDSignIn.sharedInstance.currentUser.authentication.accessToken;
+ call.requestMetadata[@"Authorization"] = [@"Bearer " stringByAppendingString:accessToken];
+
+ // Start the RPC.
+ [call start];
+
+ self.mainLabel.text = @"Waiting for RPC to complete...";
+}
+
+@end
diff --git a/examples/objective-c/auth_sample/Misc/AppDelegate.h b/examples/objective-c/auth_sample/Misc/AppDelegate.h
new file mode 100644
index 0000000000..102e7f3ade
--- /dev/null
+++ b/examples/objective-c/auth_sample/Misc/AppDelegate.h
@@ -0,0 +1,38 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+@property (strong, nonatomic) UIWindow *window;
+@end
diff --git a/examples/objective-c/auth_sample/Misc/AppDelegate.m b/examples/objective-c/auth_sample/Misc/AppDelegate.m
new file mode 100644
index 0000000000..798d342938
--- /dev/null
+++ b/examples/objective-c/auth_sample/Misc/AppDelegate.m
@@ -0,0 +1,61 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import "AppDelegate.h"
+
+#import <Google/SignIn.h>
+
+@implementation AppDelegate
+
+// As instructed in https://developers.google.com/identity/sign-in/ios/sign-in
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+ NSError* configureError;
+ [GGLContext.sharedInstance configureWithError: &configureError];
+ NSAssert(!configureError, @"Error configuring Google services: %@", configureError);
+
+ return YES;
+}
+
+// As instructed in https://developers.google.com/identity/sign-in/ios/sign-in
+- (BOOL)application:(UIApplication *)application
+ openURL:(NSURL *)url
+ sourceApplication:(NSString *)sourceApplication
+ annotation:(id)annotation {
+ // This will properly handle the URL that the application receives at the end of the
+ // authentication process.
+ return [GIDSignIn.sharedInstance handleURL:url
+ sourceApplication:sourceApplication
+ annotation:annotation];
+}
+
+@end
diff --git a/examples/objective-c/auth_sample/Misc/Base.lproj/Main.storyboard b/examples/objective-c/auth_sample/Misc/Base.lproj/Main.storyboard
new file mode 100644
index 0000000000..fb29c124e2
--- /dev/null
+++ b/examples/objective-c/auth_sample/Misc/Base.lproj/Main.storyboard
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7702" systemVersion="14D131" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="49e-Tb-3d3">
+ <dependencies>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/>
+ <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
+ </dependencies>
+ <scenes>
+ <!--Select User-->
+ <scene sceneID="hNz-n2-bh7">
+ <objects>
+ <viewController id="9pv-A4-QxB" userLabel="Select User" customClass="SelectUserViewController" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="Ia1-K6-d13"/>
+ <viewControllerLayoutGuide type="bottom" id="4ug-Mw-9AY"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="tsR-hK-woN">
+ <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" text="Please sign in." textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="KQZ-1w-vlD" userLabel="Main Label">
+ <rect key="frame" x="222" y="190" width="157" height="28"/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ <fontDescription key="fontDescription" name="Helvetica" family="Helvetica" pointSize="24"/>
+ <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="A5M-7J-77L" userLabel="Sub Label">
+ <rect key="frame" x="301" y="226" width="0.0" height="0.0"/>
+ <fontDescription key="fontDescription" type="system" pointSize="14"/>
+ <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="W20-aa-6Xr">
+ <rect key="frame" x="150" y="370" width="300" height="50"/>
+ <subviews>
+ <view contentMode="center" translatesAutoresizingMaskIntoConstraints="NO" id="25e-pE-eb8" customClass="GIDSignInButton">
+ <rect key="frame" x="42" y="0.0" width="216" height="77"/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <constraints>
+ <constraint firstAttribute="width" constant="216" placeholder="YES" id="Gfn-Hn-HXd"/>
+ <constraint firstAttribute="height" constant="77" placeholder="YES" id="cy1-xY-er0"/>
+ </constraints>
+ </view>
+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="RKb-EE-mCZ">
+ <rect key="frame" x="0.0" y="0.0" width="300" height="42"/>
+ <color key="backgroundColor" red="0.0" green="0.50196081399917603" blue="1" alpha="1" colorSpace="calibratedRGB"/>
+ <constraints>
+ <constraint firstAttribute="width" constant="300" id="ILy-QC-YPq"/>
+ <constraint firstAttribute="height" constant="42" id="MFs-aL-fQF"/>
+ </constraints>
+ <fontDescription key="fontDescription" type="boldSystem" pointSize="14"/>
+ <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <state key="normal" title="Sign out">
+ <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
+ </state>
+ <connections>
+ <action selector="didTapSignOut" destination="9pv-A4-QxB" eventType="touchUpInside" id="lcC-7k-Rki"/>
+ </connections>
+ </button>
+ </subviews>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <constraints>
+ <constraint firstAttribute="centerX" secondItem="25e-pE-eb8" secondAttribute="centerX" id="47f-A8-C2R"/>
+ <constraint firstAttribute="height" constant="50" id="EDJ-oo-Ix4"/>
+ <constraint firstItem="25e-pE-eb8" firstAttribute="top" secondItem="W20-aa-6Xr" secondAttribute="top" id="KSP-qb-mCJ"/>
+ <constraint firstItem="RKb-EE-mCZ" firstAttribute="top" secondItem="W20-aa-6Xr" secondAttribute="top" id="QDr-HV-DXb"/>
+ <constraint firstAttribute="width" constant="300" id="zWU-pZ-oQ7"/>
+ <constraint firstAttribute="centerX" secondItem="RKb-EE-mCZ" secondAttribute="centerX" id="zwy-cD-xao"/>
+ </constraints>
+ </view>
+ </subviews>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ <constraints>
+ <constraint firstAttribute="centerX" secondItem="KQZ-1w-vlD" secondAttribute="centerX" id="6BV-lF-sBN"/>
+ <constraint firstItem="KQZ-1w-vlD" firstAttribute="top" secondItem="Ia1-K6-d13" secondAttribute="bottom" constant="170" id="82x-jY-eWa"/>
+ <constraint firstAttribute="centerX" secondItem="W20-aa-6Xr" secondAttribute="centerX" id="aHL-Ts-LoW"/>
+ <constraint firstItem="A5M-7J-77L" firstAttribute="top" secondItem="KQZ-1w-vlD" secondAttribute="bottom" constant="8" symbolic="YES" id="cfb-er-3JN"/>
+ <constraint firstItem="A5M-7J-77L" firstAttribute="centerX" secondItem="KQZ-1w-vlD" secondAttribute="centerX" id="e1l-AV-tCB"/>
+ <constraint firstItem="W20-aa-6Xr" firstAttribute="top" secondItem="Ia1-K6-d13" secondAttribute="bottom" constant="350" id="pab-Li-xZ5"/>
+ </constraints>
+ </view>
+ <tabBarItem key="tabBarItem" title="Select User" image="first" id="acW-dT-cKf"/>
+ <connections>
+ <outlet property="mainLabel" destination="KQZ-1w-vlD" id="fWK-H9-WXN"/>
+ <outlet property="signInButton" destination="25e-pE-eb8" id="ovt-t5-7BV"/>
+ <outlet property="signOutButton" destination="RKb-EE-mCZ" id="afy-Q6-rK8"/>
+ <outlet property="subLabel" destination="A5M-7J-77L" id="DIj-ZX-1NK"/>
+ </connections>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="W5J-7L-Pyd" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="750" y="-320"/>
+ </scene>
+ <!--Make RPC-->
+ <scene sceneID="wg7-f3-ORb">
+ <objects>
+ <viewController id="8rJ-Kc-sve" userLabel="Make RPC" customClass="MakeRPCViewController" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="L7p-HK-0SC"/>
+ <viewControllerLayoutGuide type="bottom" id="Djb-ko-YwX"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="QS5-Rx-YEW">
+ <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" misplaced="YES" text="Waiting for RPC to complete..." lineBreakMode="wordWrap" numberOfLines="0" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="zEq-FU-wV5">
+ <rect key="frame" x="16" y="286" width="568" height="28"/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <fontDescription key="fontDescription" name="Helvetica" family="Helvetica" pointSize="18"/>
+ <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
+ <nil key="highlightedColor"/>
+ </label>
+ </subviews>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ <constraints>
+ <constraint firstItem="zEq-FU-wV5" firstAttribute="leading" secondItem="QS5-Rx-YEW" secondAttribute="leadingMargin" id="173-PJ-A9Y"/>
+ <constraint firstAttribute="trailingMargin" secondItem="zEq-FU-wV5" secondAttribute="trailing" id="Tct-jU-lL7"/>
+ <constraint firstAttribute="centerY" secondItem="zEq-FU-wV5" secondAttribute="centerY" id="qzY-Ky-pLD"/>
+ </constraints>
+ </view>
+ <tabBarItem key="tabBarItem" title="Make RPC" image="second" id="cPa-gy-q4n" userLabel="Make RPC"/>
+ <connections>
+ <outlet property="mainLabel" destination="zEq-FU-wV5" id="l1H-U6-oAa"/>
+ </connections>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="4Nw-L8-lE0" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="750" y="360"/>
+ </scene>
+ <!--Tab Bar Controller-->
+ <scene sceneID="yl2-sM-qoP">
+ <objects>
+ <tabBarController id="49e-Tb-3d3" sceneMemberID="viewController">
+ <nil key="simulatedBottomBarMetrics"/>
+ <tabBar key="tabBar" contentMode="scaleToFill" id="W28-zg-YXA">
+ <rect key="frame" x="0.0" y="975" width="768" height="49"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+ </tabBar>
+ <connections>
+ <segue destination="9pv-A4-QxB" kind="relationship" relationship="viewControllers" id="u7Y-xg-7CH"/>
+ <segue destination="8rJ-Kc-sve" kind="relationship" relationship="viewControllers" id="lzU-1b-eKA"/>
+ </connections>
+ </tabBarController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="HuB-VB-40B" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="0.0" y="0.0"/>
+ </scene>
+ </scenes>
+ <resources>
+ <image name="first" width="30" height="30"/>
+ <image name="second" width="30" height="30"/>
+ </resources>
+</document>
diff --git a/examples/objective-c/auth_sample/Misc/GoogleService-Info.plist b/examples/objective-c/auth_sample/Misc/GoogleService-Info.plist
new file mode 100644
index 0000000000..86909d84a3
--- /dev/null
+++ b/examples/objective-c/auth_sample/Misc/GoogleService-Info.plist
@@ -0,0 +1,10 @@
+<?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>CLIENT_ID</key>
+ <string>15087385131-lh9bpkiai9nls53uadju0if6k7un3uih.apps.googleusercontent.com</string>
+ <key>REVERSED_CLIENT_ID</key>
+ <string>com.googleusercontent.apps.15087385131-lh9bpkiai9nls53uadju0if6k7un3uih</string>
+</dict>
+</plist> \ No newline at end of file
diff --git a/examples/objective-c/auth_sample/Misc/Images.xcassets/AppIcon.appiconset/Contents.json b/examples/objective-c/auth_sample/Misc/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000000..36d2c80d88
--- /dev/null
+++ b/examples/objective-c/auth_sample/Misc/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -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"
+ }
+} \ No newline at end of file
diff --git a/examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/Contents.json b/examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/Contents.json
new file mode 100644
index 0000000000..33a745102c
--- /dev/null
+++ b/examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "first.pdf"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/first.pdf b/examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/first.pdf
new file mode 100644
index 0000000000..47d911dea6
--- /dev/null
+++ b/examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/first.pdf
Binary files differ
diff --git a/examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/Contents.json b/examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/Contents.json
new file mode 100644
index 0000000000..03bd9c927f
--- /dev/null
+++ b/examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "second.pdf"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/second.pdf b/examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/second.pdf
new file mode 100644
index 0000000000..401614e288
--- /dev/null
+++ b/examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/second.pdf
Binary files differ
diff --git a/examples/objective-c/auth_sample/Misc/Info.plist b/examples/objective-c/auth_sample/Misc/Info.plist
new file mode 100644
index 0000000000..fc292507c7
--- /dev/null
+++ b/examples/objective-c/auth_sample/Misc/Info.plist
@@ -0,0 +1,80 @@
+<?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>io.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>CFBundleURLTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ <key>CFBundleURLName</key>
+ <string>REVERSED_CLIENT_ID</string>
+ <key>CFBundleURLSchemes</key>
+ <array>
+ <string>com.googleusercontent.apps.15087385131-lh9bpkiai9nls53uadju0if6k7un3uih</string>
+ </array>
+ </dict>
+ <dict>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ <key>CFBundleURLName</key>
+ <string>BUNDLE_ID</string>
+ <key>CFBundleURLSchemes</key>
+ <array>
+ <string>io.grpc.AuthSample</string>
+ </array>
+ </dict>
+ </array>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UILaunchStoryboardName</key>
+ <string>Main</string>
+ <key>UIMainStoryboardFile</key>
+ <string>Main</string>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>armv7</string>
+ </array>
+ <key>UIStatusBarTintParameters</key>
+ <dict>
+ <key>UINavigationBar</key>
+ <dict>
+ <key>Style</key>
+ <string>UIBarStyleDefault</string>
+ <key>Translucent</key>
+ <false/>
+ </dict>
+ </dict>
+ <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>
diff --git a/examples/objective-c/auth_sample/Misc/main.m b/examples/objective-c/auth_sample/Misc/main.m
new file mode 100644
index 0000000000..81e9d44e54
--- /dev/null
+++ b/examples/objective-c/auth_sample/Misc/main.m
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import "AppDelegate.h"
+
+int main(int argc, char * argv[]) {
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+ }
+}
diff --git a/examples/objective-c/auth_sample/Podfile b/examples/objective-c/auth_sample/Podfile
new file mode 100644
index 0000000000..dd4fd558c0
--- /dev/null
+++ b/examples/objective-c/auth_sample/Podfile
@@ -0,0 +1,10 @@
+source 'https://github.com/CocoaPods/Specs.git'
+platform :ios, '8.0'
+
+target 'AuthSample' do
+ # Depend on the generated AuthTestService library.
+ pod 'AuthTestService', :path => '.'
+
+ # Depend on Google's OAuth2 library
+ pod 'Google/SignIn'
+end
diff --git a/examples/objective-c/auth_sample/README.md b/examples/objective-c/auth_sample/README.md
new file mode 100644
index 0000000000..3dbe7e334c
--- /dev/null
+++ b/examples/objective-c/auth_sample/README.md
@@ -0,0 +1,189 @@
+#OAuth2 on gRPC: Objective-C
+
+This example application demostrates how to use OAuth2 on gRPC to make authenticated API calls on
+behalf of a user. By walking through it you'll learn how to use the Objective-C gRPC API to:
+
+- Initialize and configure a remote call object before the RPC is started.
+- Set request metadata elements on a call, which are semantically equivalent to HTTP request
+headers.
+- Read response metadata from a call, which is equivalent to HTTP response headers and trailers.
+
+It assumes you know the basics on how to make gRPC API calls using the Objective-C client library,
+as shown in the [Hello World](examples/objective-c/helloworld)
+or [Route Guide](examples/objective-c/route_guide) tutorials,
+and are familiar with OAuth2 concepts like _access token_.
+
+- [Example code and setup](#setup)
+- [Try it out!](#try)
+- [Create an RPC object and start it later](#rpc-object)
+- [Set request metadata of a call: Authorization header with an access token](#request-metadata)
+- [Get response metadata of a call: Auth challenge header](#response-metadata)
+
+<a name="setup"></a>
+## Example code and setup
+
+The example code for our tutorial is in [examples/objective-c/auth_sample](examples/objective-c/auth_sample).
+To download the example, clone this repository by running the following command:
+```shell
+$ git clone https://github.com/grpc/grpc.git
+```
+
+Then change your current directory to `examples/objective-c/auth_sample`:
+```shell
+$ cd examples/objective-c/auth_sample
+```
+
+Our example is a simple application with two views. The first one lets a user sign in and out using
+the OAuth2 flow of Google's [iOS SignIn library](https://developers.google.com/identity/sign-in/ios/).
+(Google's library is used in this example because the test gRPC service we are going to call expects
+Google account credentials, but neither gRPC nor the Objective-C client library is tied to any
+specific OAuth2 provider). The second view makes a gRPC request to the test server, using the
+access token obtained by the first view.
+
+Note: OAuth2 libraries need the application to register and obtain an ID from the identity provider
+(in the case of this example app, Google). The app's XCode project is configured using that ID, so
+you shouldn't copy this project "as is" for your own app: it would result in your app being
+identified in the consent screen as "gRPC-AuthSample", and not having access to real Google
+services. Instead, configure your own XCode project following the [instructions here](https://developers.google.com/identity/sign-in/ios/).
+
+As with the other examples, you also should have [Cocoapods](https://cocoapods.org/#install)
+installed, as well as the relevant tools to generate the client library code. You can obtain the
+latter by following [these setup instructions](https://github.com/grpc/homebrew-grpc).
+
+
+<a name="try"></a>
+## Try it out!
+
+To try the sample app, first have Cocoapods generate and install the client library for our .proto
+files:
+
+```shell
+$ pod install
+```
+
+(This might have to compile OpenSSL, which takes around 15 minutes if Cocoapods doesn't have it yet
+on your computer's cache).
+
+Finally, open the XCode workspace created by Cocoapods, and run the app.
+
+The first view, `SelectUserViewController.h/m`, asks you to sign in with your Google account, and to
+give the "gRPC-AuthSample" app the following permissions:
+
+- View your email address.
+- View your basic profile info.
+- "Test scope for access to the Zoo service".
+
+This last permission, corresponding to the scope `https://www.googleapis.com/auth/xapi.zoo` doesn't
+grant any real capability: it's only used for testing. You can log out at any time.
+
+The second view, `MakeRPCViewController.h/m`, makes a gRPC request to a test server at
+https://grpc-test.sandbox.google.com, sending the access token along with the request. The test
+service simply validates the token and writes in its response which user it belongs to, and which
+scopes it gives access to. (The client application already knows those two values; it's a way to
+verify that everything went as expected).
+
+The next sections guide you step-by-step through how the gRPC call in `MakeRPCViewController` is
+performed.
+
+<a name="rpc-object"></a>
+## Create an RPC object and start it later
+
+The other basic tutorials show how to invoke an RPC by calling an asynchronous method in a generated
+client object. This shows how to initialize an object that represents the RPC, and configure it
+before starting the network request.
+
+Assume you have a proto service definition like this:
+
+```protobuf
+option objc_class_prefix = "AUTH";
+
+service TestService {
+ rpc UnaryCall(Request) returns (Response);
+}
+```
+
+A `unaryCallWithRequest:handler:` method, with which you're already familiar, is generated for the
+`AUTHTestService` class:
+
+```objective-c
+[client unaryCallWithRequest:request handler:^(AUTHResponse *response, NSError *error) {
+ ...
+}];
+```
+
+In addition, an `RPCToUnaryCallWithRequest:handler:` method is generated, which returns a
+not-yet-started RPC object:
+
+```objective-c
+#import <ProtoRPC/ProtoRPC.h>
+
+ProtoRPC *call =
+ [client RPCToUnaryCallWithRequest:request handler:^(AUTHResponse *response, NSError *error) {
+ ...
+ }];
+```
+
+The RPC represented by this object can be started at any later time like this:
+
+```objective-c
+[call start];
+```
+
+<a name="request-metadata"></a>
+## Set request metadata of a call: Authorization header with an access token
+
+The `ProtoRPC` class has a `requestMetadata` property (inherited from `GRPCCall`) defined like this:
+
+```objective-c
+- (NSMutableDictionary *)requestMetadata; // nonatomic
+- (void)setRequestMetadata:(NSDictionary *)requestMetadata; // nonatomic, copy
+```
+
+Setting it to a dictionary of metadata keys and values will have them sent on the wire when the call
+is started. gRPC metadata are pieces of information about the call sent by the client to the server
+(and vice versa). They take the form of key-value pairs and are essentially opaque to gRPC itself.
+
+```objective-c
+call.requestMetadata = @{@"My-Header": @"Value for this header",
+ @"Another-Header": @"Its value"};
+```
+
+For convenience, the property is initialized with an empty `NSMutableDictionary`, so that request
+metadata elements can be set like this:
+
+```objective-c
+call.requestMetadata[@"My-Header"] = @"Value for this header";
+```
+
+If you have an access token, OAuth2 specifies it is to be sent in this format:
+
+```objective-c
+call.requestMetadata[@"Authorization"] = [@"Bearer " stringByAppendingString:accessToken];
+```
+
+<a name="response-metadata"></a>
+## Get response metadata of a call: Auth challenge header
+
+The `ProtoRPC` class also inherits a `responseMetadata` property, analogous to the request metadata
+we just looked at. It's defined like this:
+
+```objective-c
+@property(atomic, readonly) NSDictionary *responseMetadata;
+```
+
+To access OAuth2's authentication challenge header you write:
+
+```objective-c
+call.responseMetadata[@"www-authenticate"]
+```
+
+Note that, as gRPC metadata elements are mapped to HTTP/2 headers (or trailers), the keys of the
+response metadata are always ASCII strings in lowercase.
+
+Many uses cases of response metadata are getting more details about an RPC error. For convenience,
+when a `NSError` instance is passed to an RPC handler block, the response metadata dictionary can
+also be accessed this way:
+
+```objective-c
+error.userInfo[kGRPCStatusMetadataKey]
+```
diff --git a/examples/objective-c/auth_sample/SelectUserViewController.h b/examples/objective-c/auth_sample/SelectUserViewController.h
new file mode 100644
index 0000000000..eb3c2cf5f0
--- /dev/null
+++ b/examples/objective-c/auth_sample/SelectUserViewController.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import <Google/SignIn.h>
+#import <UIKit/UIKit.h>
+
+@interface SelectUserViewController : UIViewController <GIDSignInDelegate, GIDSignInUIDelegate>
+@property(weak, nonatomic) IBOutlet GIDSignInButton *signInButton;
+@property(weak, nonatomic) IBOutlet UIButton *signOutButton;
+@property(weak, nonatomic) IBOutlet UILabel *mainLabel;
+@property(weak, nonatomic) IBOutlet UILabel *subLabel;
+@end
diff --git a/examples/objective-c/auth_sample/SelectUserViewController.m b/examples/objective-c/auth_sample/SelectUserViewController.m
new file mode 100644
index 0000000000..954c531f3f
--- /dev/null
+++ b/examples/objective-c/auth_sample/SelectUserViewController.m
@@ -0,0 +1,86 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import "SelectUserViewController.h"
+
+#import "MakeRPCViewController.h"
+
+@implementation SelectUserViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+
+ self.signOutButton.layer.cornerRadius = 5;
+ self.signOutButton.hidden = YES;
+
+ // As instructed in https://developers.google.com/identity/sign-in/ios/sign-in
+ GIDSignIn *signIn = GIDSignIn.sharedInstance;
+ signIn.delegate = self;
+ signIn.uiDelegate = self;
+
+ // As instructed in https://developers.google.com/identity/sign-in/ios/additional-scopes
+ if (![signIn.scopes containsObject:kTestScope]) {
+ signIn.scopes = [signIn.scopes arrayByAddingObject:kTestScope];
+ }
+
+ [signIn signInSilently];
+}
+
+- (void)signIn:(GIDSignIn *)signIn
+didSignInForUser:(GIDGoogleUser *)user
+ withError:(NSError *)error {
+ if (error) {
+ // The user probably cancelled the sign-in flow.
+ return;
+ }
+
+ self.mainLabel.text = [NSString stringWithFormat:@"User: %@", user.profile.email];
+ NSString *scopes = [user.accessibleScopes componentsJoinedByString:@", "];
+ scopes = scopes.length ? scopes : @"(none)";
+ self.subLabel.text = [NSString stringWithFormat:@"Scopes: %@", scopes];
+
+ self.signInButton.hidden = YES;
+ self.signOutButton.hidden = NO;
+}
+
+- (IBAction)didTapSignOut {
+ [GIDSignIn.sharedInstance signOut];
+
+ self.mainLabel.text = @"Please sign in.";
+ self.subLabel.text = @"";
+
+ self.signInButton.hidden = NO;
+ self.signOutButton.hidden = YES;
+}
+
+@end
diff --git a/examples/objective-c/helloworld/HelloWorld.podspec b/examples/objective-c/helloworld/HelloWorld.podspec
new file mode 100644
index 0000000000..ae009a688c
--- /dev/null
+++ b/examples/objective-c/helloworld/HelloWorld.podspec
@@ -0,0 +1,35 @@
+Pod::Spec.new do |s|
+ s.name = "HelloWorld"
+ s.version = "0.0.1"
+ s.license = "New BSD"
+
+ s.ios.deployment_target = "6.0"
+ s.osx.deployment_target = "10.8"
+
+ # Base directory where the .proto files are.
+ src = "../../protos"
+
+ # Directory where the generated files will be place.
+ dir = "Pods/" + s.name
+
+ # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
+ s.prepare_command = <<-CMD
+ mkdir -p #{dir}
+ protoc -I #{src} --objc_out=#{dir} --objcgrpc_out=#{dir} #{src}/helloworld.proto
+ CMD
+
+ s.subspec "Messages" do |ms|
+ ms.source_files = "#{dir}/*.pbobjc.{h,m}", "#{dir}/**/*.pbobjc.{h,m}"
+ ms.header_mappings_dir = dir
+ ms.requires_arc = false
+ ms.dependency "Protobuf", "~> 3.0.0-alpha-3"
+ end
+
+ s.subspec "Services" do |ss|
+ ss.source_files = "#{dir}/*.pbrpc.{h,m}", "#{dir}/**/*.pbrpc.{h,m}"
+ ss.header_mappings_dir = dir
+ ss.requires_arc = true
+ ss.dependency "gRPC", "~> 0.6"
+ ss.dependency "#{s.name}/Messages"
+ end
+end
diff --git a/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj b/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj
new file mode 100644
index 0000000000..702ad3ff8b
--- /dev/null
+++ b/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj
@@ -0,0 +1,349 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 5E3690661B2A23800040F884 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E3690651B2A23800040F884 /* main.m */; };
+ 5E3690691B2A23800040F884 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E3690681B2A23800040F884 /* AppDelegate.m */; };
+ 5E36906C1B2A23800040F884 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E36906B1B2A23800040F884 /* ViewController.m */; };
+ 5E36906F1B2A23800040F884 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5E36906D1B2A23800040F884 /* Main.storyboard */; };
+ 5E3690711B2A23800040F884 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5E3690701B2A23800040F884 /* Images.xcassets */; };
+ EF61CF6AE2536A31D47F0E63 /* libPods-HelloWorld.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6B4E1F55F8A2EC95A0E7EE88 /* libPods-HelloWorld.a */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 0C432EF610DB15C0F47A66BB /* Pods-HelloWorld.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld.release.xcconfig"; path = "Pods/Target Support Files/Pods-HelloWorld/Pods-HelloWorld.release.xcconfig"; sourceTree = "<group>"; };
+ 5E3690601B2A23800040F884 /* HelloWorld.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloWorld.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 5E3690641B2A23800040F884 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 5E3690651B2A23800040F884 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ 5E3690671B2A23800040F884 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+ 5E3690681B2A23800040F884 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+ 5E36906B1B2A23800040F884 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
+ 5E36906E1B2A23800040F884 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+ 5E3690701B2A23800040F884 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
+ 6B4E1F55F8A2EC95A0E7EE88 /* libPods-HelloWorld.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HelloWorld.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ DBDE3E48389499064CD664B8 /* Pods-HelloWorld.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld.debug.xcconfig"; path = "Pods/Target Support Files/Pods-HelloWorld/Pods-HelloWorld.debug.xcconfig"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 5E36905D1B2A23800040F884 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ EF61CF6AE2536A31D47F0E63 /* libPods-HelloWorld.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 5E3690571B2A23800040F884 = {
+ isa = PBXGroup;
+ children = (
+ 5E3690651B2A23800040F884 /* main.m */,
+ 5E3690621B2A23800040F884 /* HelloWorld */,
+ 5E3690611B2A23800040F884 /* Products */,
+ BD9CE6458E7C4FF49A1DF69F /* Pods */,
+ 66CEC7120220DDD2221DD075 /* Frameworks */,
+ );
+ sourceTree = "<group>";
+ };
+ 5E3690611B2A23800040F884 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 5E3690601B2A23800040F884 /* HelloWorld.app */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 5E3690621B2A23800040F884 /* HelloWorld */ = {
+ isa = PBXGroup;
+ children = (
+ 5E3690631B2A23800040F884 /* Supporting Files */,
+ );
+ path = HelloWorld;
+ sourceTree = "<group>";
+ };
+ 5E3690631B2A23800040F884 /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ 5E3690701B2A23800040F884 /* Images.xcassets */,
+ 5E36906D1B2A23800040F884 /* Main.storyboard */,
+ 5E36906B1B2A23800040F884 /* ViewController.m */,
+ 5E3690681B2A23800040F884 /* AppDelegate.m */,
+ 5E3690671B2A23800040F884 /* AppDelegate.h */,
+ 5E3690641B2A23800040F884 /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "<group>";
+ };
+ 66CEC7120220DDD2221DD075 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 6B4E1F55F8A2EC95A0E7EE88 /* libPods-HelloWorld.a */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ BD9CE6458E7C4FF49A1DF69F /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ DBDE3E48389499064CD664B8 /* Pods-HelloWorld.debug.xcconfig */,
+ 0C432EF610DB15C0F47A66BB /* Pods-HelloWorld.release.xcconfig */,
+ );
+ name = Pods;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 5E36905F1B2A23800040F884 /* HelloWorld */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 5E3690831B2A23810040F884 /* Build configuration list for PBXNativeTarget "HelloWorld" */;
+ buildPhases = (
+ ACF9162361FB8F24C70657DE /* Check Pods Manifest.lock */,
+ 5E36905C1B2A23800040F884 /* Sources */,
+ 5E36905D1B2A23800040F884 /* Frameworks */,
+ 5E36905E1B2A23800040F884 /* Resources */,
+ 4C7D815378D98AB3BFC1A7D5 /* Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = HelloWorld;
+ productName = HelloWorld;
+ productReference = 5E3690601B2A23800040F884 /* HelloWorld.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 5E3690581B2A23800040F884 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0620;
+ ORGANIZATIONNAME = Google;
+ TargetAttributes = {
+ 5E36905F1B2A23800040F884 = {
+ CreatedOnToolsVersion = 6.2;
+ };
+ };
+ };
+ buildConfigurationList = 5E36905B1B2A23800040F884 /* Build configuration list for PBXProject "HelloWorld" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 5E3690571B2A23800040F884;
+ productRefGroup = 5E3690611B2A23800040F884 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 5E36905F1B2A23800040F884 /* HelloWorld */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 5E36905E1B2A23800040F884 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 5E36906F1B2A23800040F884 /* Main.storyboard in Resources */,
+ 5E3690711B2A23800040F884 /* Images.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 4C7D815378D98AB3BFC1A7D5 /* Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-HelloWorld/Pods-HelloWorld-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ ACF9162361FB8F24C70657DE /* Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Check Pods Manifest.lock";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 5E36905C1B2A23800040F884 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 5E36906C1B2A23800040F884 /* ViewController.m in Sources */,
+ 5E3690691B2A23800040F884 /* AppDelegate.m in Sources */,
+ 5E3690661B2A23800040F884 /* main.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ 5E36906D1B2A23800040F884 /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 5E36906E1B2A23800040F884 /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 5E3690811B2A23810040F884 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.2;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 5E3690821B2A23810040F884 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.2;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 5E3690841B2A23810040F884 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = DBDE3E48389499064CD664B8 /* Pods-HelloWorld.debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = HelloWorld/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 5E3690851B2A23810040F884 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 0C432EF610DB15C0F47A66BB /* Pods-HelloWorld.release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = HelloWorld/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 5E36905B1B2A23800040F884 /* Build configuration list for PBXProject "HelloWorld" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 5E3690811B2A23810040F884 /* Debug */,
+ 5E3690821B2A23810040F884 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 5E3690831B2A23810040F884 /* Build configuration list for PBXNativeTarget "HelloWorld" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 5E3690841B2A23810040F884 /* Debug */,
+ 5E3690851B2A23810040F884 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 5E3690581B2A23800040F884 /* Project object */;
+}
diff --git a/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000000..174a04ecb8
--- /dev/null
+++ b/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:HelloWorld.xcodeproj">
+ </FileRef>
+</Workspace>
diff --git a/examples/objective-c/helloworld/HelloWorld/AppDelegate.h b/examples/objective-c/helloworld/HelloWorld/AppDelegate.h
new file mode 100644
index 0000000000..102e7f3ade
--- /dev/null
+++ b/examples/objective-c/helloworld/HelloWorld/AppDelegate.h
@@ -0,0 +1,38 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+@property (strong, nonatomic) UIWindow *window;
+@end
diff --git a/examples/objective-c/helloworld/HelloWorld/AppDelegate.m b/examples/objective-c/helloworld/HelloWorld/AppDelegate.m
new file mode 100644
index 0000000000..a38e36651e
--- /dev/null
+++ b/examples/objective-c/helloworld/HelloWorld/AppDelegate.m
@@ -0,0 +1,37 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import "AppDelegate.h"
+
+@implementation AppDelegate
+@end
diff --git a/examples/objective-c/helloworld/HelloWorld/Base.lproj/Main.storyboard b/examples/objective-c/helloworld/HelloWorld/Base.lproj/Main.storyboard
new file mode 100644
index 0000000000..f56d2f3bb5
--- /dev/null
+++ b/examples/objective-c/helloworld/HelloWorld/Base.lproj/Main.storyboard
@@ -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>
diff --git a/examples/objective-c/helloworld/HelloWorld/Images.xcassets/AppIcon.appiconset/Contents.json b/examples/objective-c/helloworld/HelloWorld/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000000..36d2c80d88
--- /dev/null
+++ b/examples/objective-c/helloworld/HelloWorld/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -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"
+ }
+} \ No newline at end of file
diff --git a/examples/objective-c/helloworld/HelloWorld/Info.plist b/examples/objective-c/helloworld/HelloWorld/Info.plist
new file mode 100644
index 0000000000..1078fff723
--- /dev/null
+++ b/examples/objective-c/helloworld/HelloWorld/Info.plist
@@ -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>Google.$(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>Main</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>
diff --git a/examples/objective-c/helloworld/HelloWorld/ViewController.m b/examples/objective-c/helloworld/HelloWorld/ViewController.m
new file mode 100644
index 0000000000..090fd93689
--- /dev/null
+++ b/examples/objective-c/helloworld/HelloWorld/ViewController.m
@@ -0,0 +1,40 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+
+@interface ViewController : UIViewController
+@end
+
+@implementation ViewController
+@end
diff --git a/examples/objective-c/helloworld/Podfile b/examples/objective-c/helloworld/Podfile
new file mode 100644
index 0000000000..2934ebc2c8
--- /dev/null
+++ b/examples/objective-c/helloworld/Podfile
@@ -0,0 +1,7 @@
+source 'https://github.com/CocoaPods/Specs.git'
+platform :ios, '8.0'
+
+target 'HelloWorld' do
+ # Depend on the generated HelloWorld library.
+ pod 'HelloWorld', :path => '.'
+end
diff --git a/examples/objective-c/helloworld/README.md b/examples/objective-c/helloworld/README.md
new file mode 100644
index 0000000000..3b852f857f
--- /dev/null
+++ b/examples/objective-c/helloworld/README.md
@@ -0,0 +1,56 @@
+#gRPC in 3 minutes (Objective-C)
+
+## Installation
+
+To run this example you should have [Cocoapods](https://cocoapods.org/#install) installed, as well
+as the relevant tools to generate the client library code (and a server in another language, for
+testing). You can obtain the latter by following [these setup instructions](https://github.com/grpc/homebrew-grpc).
+
+## Hello Objective-C gRPC!
+
+Here's how to build and run the Objective-C implementation of the [Hello World](examples/protos/helloworld.proto)
+example used in [Getting started](https://github.com/grpc/grpc/tree/master/examples).
+
+The example code for this and our other examples lives in the `examples` directory. Clone
+this repository to your local machine by running the following command:
+
+
+```sh
+$ git clone https://github.com/grpc/grpc.git
+```
+
+Change your current directory to `examples/objective-c/helloworld`
+
+```sh
+$ cd examples/objective-c/helloworld
+```
+
+### Try it!
+To try the sample app, we need a gRPC server running locally. Let's compile and run, for example,
+the C++ server in this repository:
+
+```shell
+$ pushd ../../cpp/helloworld
+$ make
+$ ./greeter_server &
+$ popd
+```
+
+Now have Cocoapods generate and install the client library for our .proto files:
+
+```shell
+$ pod install
+```
+
+(This might have to compile OpenSSL, which takes around 15 minutes if Cocoapods doesn't have it yet
+on your computer's cache.)
+
+Finally, open the XCode workspace created by Cocoapods, and run the app. You can check the calling
+code in `main.m` and see the results in XCode's log console.
+
+The code sends a `HLWHelloRequest` containing the string "Objective-C" to a local server. The server
+responds with a `HLWHelloResponse`, which contains a string that is then output to the log.
+
+## Tutorial
+
+You can find a more detailed tutorial in [gRPC Basics: Objective-C](examples/objective-c/route_guide/README.md).
diff --git a/examples/objective-c/helloworld/main.m b/examples/objective-c/helloworld/main.m
new file mode 100644
index 0000000000..458580be30
--- /dev/null
+++ b/examples/objective-c/helloworld/main.m
@@ -0,0 +1,51 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import "AppDelegate.h"
+
+#import <HelloWorld/Helloworld.pbrpc.h>
+
+static NSString * const kHostAddress = @"http://localhost:50051";
+
+int main(int argc, char * argv[]) {
+ @autoreleasepool {
+ HLWGreeter *client = [[HLWGreeter alloc] initWithHost:kHostAddress];
+ HLWHelloRequest *request = [HLWHelloRequest message];
+ request.name = @"Objective-C";
+ [client sayHelloWithRequest:request handler:^(HLWHelloReply *response, NSError *error) {
+ NSLog(@"%@", response.message);
+ }];
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+ }
+}
diff --git a/examples/objective-c/route_guide/Misc/AppDelegate.h b/examples/objective-c/route_guide/Misc/AppDelegate.h
new file mode 100644
index 0000000000..102e7f3ade
--- /dev/null
+++ b/examples/objective-c/route_guide/Misc/AppDelegate.h
@@ -0,0 +1,38 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+@property (strong, nonatomic) UIWindow *window;
+@end
diff --git a/examples/objective-c/route_guide/Misc/AppDelegate.m b/examples/objective-c/route_guide/Misc/AppDelegate.m
new file mode 100644
index 0000000000..a38e36651e
--- /dev/null
+++ b/examples/objective-c/route_guide/Misc/AppDelegate.m
@@ -0,0 +1,37 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import "AppDelegate.h"
+
+@implementation AppDelegate
+@end
diff --git a/examples/objective-c/route_guide/Misc/Base.lproj/Main.storyboard b/examples/objective-c/route_guide/Misc/Base.lproj/Main.storyboard
new file mode 100644
index 0000000000..9bf9498d62
--- /dev/null
+++ b/examples/objective-c/route_guide/Misc/Base.lproj/Main.storyboard
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7702" systemVersion="14D131" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="49e-Tb-3d3">
+ <dependencies>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/>
+ </dependencies>
+ <scenes>
+ <!--Get Feature-->
+ <scene sceneID="hNz-n2-bh7">
+ <objects>
+ <viewController id="9pv-A4-QxB" customClass="GetFeatureViewController" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="Ia1-K6-d13"/>
+ <viewControllerLayoutGuide type="bottom" id="4ug-Mw-9AY"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="tsR-hK-woN">
+ <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" text="Get Feature Demo" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="KQZ-1w-vlD">
+ <rect key="frame" x="150" y="279" width="299" height="42"/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ <fontDescription key="fontDescription" name="Helvetica" family="Helvetica" pointSize="36"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="See ViewControllers.m and this app's log in XCode" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="A5M-7J-77L">
+ <rect key="frame" x="136" y="329" width="329" height="17"/>
+ <fontDescription key="fontDescription" type="system" pointSize="14"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ </subviews>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ <constraints>
+ <constraint firstAttribute="centerX" secondItem="KQZ-1w-vlD" secondAttribute="centerX" id="6BV-lF-sBN"/>
+ <constraint firstItem="A5M-7J-77L" firstAttribute="top" secondItem="KQZ-1w-vlD" secondAttribute="bottom" constant="8" symbolic="YES" id="cfb-er-3JN"/>
+ <constraint firstItem="A5M-7J-77L" firstAttribute="centerX" secondItem="KQZ-1w-vlD" secondAttribute="centerX" id="e1l-AV-tCB"/>
+ <constraint firstAttribute="centerY" secondItem="KQZ-1w-vlD" secondAttribute="centerY" id="exm-UA-ej4"/>
+ </constraints>
+ </view>
+ <tabBarItem key="tabBarItem" title="Get Feature" image="first" id="acW-dT-cKf"/>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="W5J-7L-Pyd" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="718" y="-660"/>
+ </scene>
+ <!--List Features-->
+ <scene sceneID="wg7-f3-ORb">
+ <objects>
+ <viewController id="8rJ-Kc-sve" customClass="ListFeaturesViewController" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="L7p-HK-0SC"/>
+ <viewControllerLayoutGuide type="bottom" id="Djb-ko-YwX"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="QS5-Rx-YEW">
+ <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" text="List Features Demo" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="zEq-FU-wV5">
+ <rect key="frame" x="143" y="279" width="315" height="42"/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <fontDescription key="fontDescription" name="Helvetica" family="Helvetica" pointSize="36"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="See ViewControllers.m and this app's log in XCode" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="NDk-cv-Gan">
+ <rect key="frame" x="136" y="329" width="329" height="17"/>
+ <fontDescription key="fontDescription" type="system" pointSize="14"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ </subviews>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ <constraints>
+ <constraint firstItem="NDk-cv-Gan" firstAttribute="top" secondItem="zEq-FU-wV5" secondAttribute="bottom" constant="8" symbolic="YES" id="Day-4N-Vmt"/>
+ <constraint firstItem="NDk-cv-Gan" firstAttribute="centerX" secondItem="zEq-FU-wV5" secondAttribute="centerX" id="JgO-Fn-dHn"/>
+ <constraint firstAttribute="centerX" secondItem="zEq-FU-wV5" secondAttribute="centerX" id="qqM-NS-xev"/>
+ <constraint firstAttribute="centerY" secondItem="zEq-FU-wV5" secondAttribute="centerY" id="qzY-Ky-pLD"/>
+ </constraints>
+ </view>
+ <tabBarItem key="tabBarItem" title="List Features" image="second" id="cPa-gy-q4n"/>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="4Nw-L8-lE0" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="1466" y="-386"/>
+ </scene>
+ <!--Tab Bar Controller-->
+ <scene sceneID="yl2-sM-qoP">
+ <objects>
+ <tabBarController id="49e-Tb-3d3" sceneMemberID="viewController">
+ <nil key="simulatedBottomBarMetrics"/>
+ <tabBar key="tabBar" contentMode="scaleToFill" id="W28-zg-YXA">
+ <rect key="frame" x="0.0" y="975" width="768" height="49"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+ </tabBar>
+ <connections>
+ <segue destination="9pv-A4-QxB" kind="relationship" relationship="viewControllers" id="u7Y-xg-7CH"/>
+ <segue destination="8rJ-Kc-sve" kind="relationship" relationship="viewControllers" id="lzU-1b-eKA"/>
+ <segue destination="YIR-e4-hjB" kind="relationship" relationship="viewControllers" id="L0R-vl-fT4"/>
+ <segue destination="6mc-1d-hJy" kind="relationship" relationship="viewControllers" id="C2G-Se-4Fe"/>
+ </connections>
+ </tabBarController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="HuB-VB-40B" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="0.0" y="0.0"/>
+ </scene>
+ <!--Record Route-->
+ <scene sceneID="kS4-Oa-mxG">
+ <objects>
+ <viewController id="YIR-e4-hjB" userLabel="Record Route" customClass="RecordRouteViewController" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="jR8-0x-GjY"/>
+ <viewControllerLayoutGuide type="bottom" id="4Q5-sW-A9H"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="Wvj-mg-YnO">
+ <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" text="Record Route Demo" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="Nqv-Vr-o8P">
+ <rect key="frame" x="136" y="279" width="329" height="42"/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <fontDescription key="fontDescription" name="Helvetica" family="Helvetica" pointSize="36"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="See ViewControllers.m and this app's log in XCode" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xjS-0N-tLe">
+ <rect key="frame" x="136" y="329" width="329" height="17"/>
+ <fontDescription key="fontDescription" type="system" pointSize="14"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ </subviews>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ <constraints>
+ <constraint firstAttribute="centerX" secondItem="Nqv-Vr-o8P" secondAttribute="centerX" id="1wf-uc-57y"/>
+ <constraint firstItem="xjS-0N-tLe" firstAttribute="centerX" secondItem="Nqv-Vr-o8P" secondAttribute="centerX" id="Gnh-rN-EQ3"/>
+ <constraint firstItem="xjS-0N-tLe" firstAttribute="top" secondItem="Nqv-Vr-o8P" secondAttribute="bottom" constant="8" symbolic="YES" id="Xhj-u3-th9"/>
+ <constraint firstAttribute="centerY" secondItem="Nqv-Vr-o8P" secondAttribute="centerY" id="xqU-v8-Bb3"/>
+ </constraints>
+ </view>
+ <tabBarItem key="tabBarItem" title="Record Route" image="first" id="PLK-Jm-UyM"/>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="9RW-dt-a4q" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="1466" y="264"/>
+ </scene>
+ <!--Route Chat-->
+ <scene sceneID="M4k-TV-RZJ">
+ <objects>
+ <viewController id="6mc-1d-hJy" userLabel="Route Chat" customClass="RouteChatViewController" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="Sl7-r2-TON"/>
+ <viewControllerLayoutGuide type="bottom" id="e7m-SC-g06"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="c9d-af-OMP">
+ <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" text="Route Chat Demo" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="zUL-Bo-wJt">
+ <rect key="frame" x="156" y="279" width="289" height="42"/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <fontDescription key="fontDescription" name="Helvetica" family="Helvetica" pointSize="36"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="See ViewControllers.m and this app's log in XCode" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="CgS-1q-Od9">
+ <rect key="frame" x="136" y="329" width="329" height="17"/>
+ <fontDescription key="fontDescription" type="system" pointSize="14"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ </subviews>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ <constraints>
+ <constraint firstAttribute="centerY" secondItem="zUL-Bo-wJt" secondAttribute="centerY" id="5hM-q1-ZjM"/>
+ <constraint firstItem="CgS-1q-Od9" firstAttribute="top" secondItem="zUL-Bo-wJt" secondAttribute="bottom" constant="8" symbolic="YES" id="AqI-Ra-a5O"/>
+ <constraint firstItem="CgS-1q-Od9" firstAttribute="centerX" secondItem="zUL-Bo-wJt" secondAttribute="centerX" id="K8f-KI-bc6"/>
+ <constraint firstAttribute="centerX" secondItem="zUL-Bo-wJt" secondAttribute="centerX" id="n8b-x8-Yze"/>
+ </constraints>
+ </view>
+ <tabBarItem key="tabBarItem" title="Route Chat" image="second" id="p2G-IC-yAR"/>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="yUz-se-Cfi" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="718" y="594"/>
+ </scene>
+ </scenes>
+ <resources>
+ <image name="first" width="30" height="30"/>
+ <image name="second" width="30" height="30"/>
+ </resources>
+</document>
diff --git a/examples/objective-c/route_guide/Misc/Images.xcassets/AppIcon.appiconset/Contents.json b/examples/objective-c/route_guide/Misc/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000000..36d2c80d88
--- /dev/null
+++ b/examples/objective-c/route_guide/Misc/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -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"
+ }
+} \ No newline at end of file
diff --git a/examples/objective-c/route_guide/Misc/Images.xcassets/first.imageset/Contents.json b/examples/objective-c/route_guide/Misc/Images.xcassets/first.imageset/Contents.json
new file mode 100644
index 0000000000..33a745102c
--- /dev/null
+++ b/examples/objective-c/route_guide/Misc/Images.xcassets/first.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "first.pdf"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/examples/objective-c/route_guide/Misc/Images.xcassets/first.imageset/first.pdf b/examples/objective-c/route_guide/Misc/Images.xcassets/first.imageset/first.pdf
new file mode 100644
index 0000000000..47d911dea6
--- /dev/null
+++ b/examples/objective-c/route_guide/Misc/Images.xcassets/first.imageset/first.pdf
Binary files differ
diff --git a/examples/objective-c/route_guide/Misc/Images.xcassets/second.imageset/Contents.json b/examples/objective-c/route_guide/Misc/Images.xcassets/second.imageset/Contents.json
new file mode 100644
index 0000000000..03bd9c927f
--- /dev/null
+++ b/examples/objective-c/route_guide/Misc/Images.xcassets/second.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "second.pdf"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/examples/objective-c/route_guide/Misc/Images.xcassets/second.imageset/second.pdf b/examples/objective-c/route_guide/Misc/Images.xcassets/second.imageset/second.pdf
new file mode 100644
index 0000000000..401614e288
--- /dev/null
+++ b/examples/objective-c/route_guide/Misc/Images.xcassets/second.imageset/second.pdf
Binary files differ
diff --git a/examples/objective-c/route_guide/Misc/Info.plist b/examples/objective-c/route_guide/Misc/Info.plist
new file mode 100644
index 0000000000..33ad4800f6
--- /dev/null
+++ b/examples/objective-c/route_guide/Misc/Info.plist
@@ -0,0 +1,57 @@
+<?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>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>Main</string>
+ <key>UIMainStoryboardFile</key>
+ <string>Main</string>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>armv7</string>
+ </array>
+ <key>UIStatusBarTintParameters</key>
+ <dict>
+ <key>UINavigationBar</key>
+ <dict>
+ <key>Style</key>
+ <string>UIBarStyleDefault</string>
+ <key>Translucent</key>
+ <false/>
+ </dict>
+ </dict>
+ <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>
diff --git a/examples/objective-c/route_guide/Misc/main.m b/examples/objective-c/route_guide/Misc/main.m
new file mode 100644
index 0000000000..fb701005d1
--- /dev/null
+++ b/examples/objective-c/route_guide/Misc/main.m
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import "AppDelegate.h"
+
+int main(int argc, char * argv[]) {
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+ }
+}
diff --git a/examples/objective-c/route_guide/Podfile b/examples/objective-c/route_guide/Podfile
new file mode 100644
index 0000000000..a97f414685
--- /dev/null
+++ b/examples/objective-c/route_guide/Podfile
@@ -0,0 +1,7 @@
+source 'https://github.com/CocoaPods/Specs.git'
+platform :ios, '8.0'
+
+target 'RouteGuideClient' do
+ # Depend on the generated RouteGuide library.
+ pod 'RouteGuide', :path => '.'
+end
diff --git a/examples/objective-c/route_guide/README.md b/examples/objective-c/route_guide/README.md
new file mode 100644
index 0000000000..dd20a07995
--- /dev/null
+++ b/examples/objective-c/route_guide/README.md
@@ -0,0 +1,360 @@
+#gRPC Basics: Objective-C
+
+This tutorial provides a basic Objective-C programmer's introduction to working with gRPC. By
+walking through this example you'll learn how to:
+
+- Define a service in a .proto file.
+- Generate client code using the protocol buffer compiler.
+- Use the Objective-C gRPC API to write a simple client for your service.
+
+It assumes a passing familiarity with [protocol buffers](https://developers.google.com/protocol-buffers/docs/overview).
+Note that the example in this tutorial uses the proto3 version of the protocol buffers language,
+which is currently in alpha release: you can find out more in the [proto3 language guide](https://developers.google.com/protocol-buffers/docs/proto3)
+and see the [release notes](https://github.com/google/protobuf/releases) for the new version in the
+protocol buffers Github repository.
+
+This isn't a comprehensive guide to using gRPC in Objective-C: more reference documentation is
+coming soon.
+
+- [Why use gRPC?](#why-grpc)
+- [Example code and setup](#setup)
+- [Try it out!](#try)
+- [Defining the service](#proto)
+- [Generating client code](#protoc)
+- [Creating the client](#client)
+
+<a name="why-grpc"></a>
+## Why use gRPC?
+
+With gRPC you can define your service once in a .proto file and implement clients and servers in any
+of gRPC's supported languages, which in turn can be run in environments ranging from servers inside
+Google to your own tablet - all the complexity of communication between different languages and
+environments is handled for you by gRPC. You also get all the advantages of working with protocol
+buffers, including efficient serialization, a simple IDL, and easy interface updating.
+
+gRPC and proto3 are specially suited for mobile clients: gRPC is implemented on top of HTTP/2, which
+results in network bandwidth savings over using HTTP/1.1. Serialization and parsing of the proto
+binary format is more efficient than the equivalent JSON, resulting in CPU and battery savings. And
+proto3 uses a runtime that has been optimized over the years at Google to keep code size to a
+minimum. The latter is important in Objective-C, because the ability of the compiler to strip unused
+code is limited by the dynamic nature of the language.
+
+
+<a name="setup"></a>
+## Example code and setup
+
+The example code for our tutorial is in [examples/objective-c/route_guide](examples/objective-c/route_guide).
+To download the example, clone this repository by running the following command:
+```shell
+$ git clone https://github.com/grpc/grpc.git
+```
+
+Then change your current directory to `examples/objective-c/route_guide`:
+```shell
+$ cd examples/objective-c/route_guide
+```
+
+Our example is a simple route mapping application that lets clients get information about features
+on their route, create a summary of their route, and exchange route information such as traffic
+updates with the server and other clients.
+
+You also should have [Cocoapods](https://cocoapods.org/#install) installed, as well as the relevant
+tools to generate the client library code (and a server in another language, for testing). You can
+obtain the latter by following [these setup instructions](https://github.com/grpc/homebrew-grpc).
+
+
+<a name="try"></a>
+## Try it out!
+
+To try the sample app, we need a gRPC server running locally. Let's compile and run, for example,
+the C++ server in this repository:
+
+```shell
+$ pushd ../../cpp/route_guide
+$ make
+$ ./route_guide_server &
+$ popd
+```
+
+Now have Cocoapods generate and install the client library for our .proto files:
+
+```shell
+$ pod install
+```
+
+(This might have to compile OpenSSL, which takes around 15 minutes if Cocoapods doesn't have it yet
+on your computer's cache).
+
+Finally, open the XCode workspace created by Cocoapods, and run the app. You can check the calling
+code in `ViewControllers.m` and see the results in XCode's log console.
+
+The next sections guide you step-by-step through how this proto service is defined, how to generate
+a client library from it, and how to create an app that uses that library.
+
+
+<a name="proto"></a>
+## Defining the service
+
+First let's look at how the service we're using is defined. A gRPC *service* and its method
+*request* and *response* types using [protocol buffers](https://developers.google.com/protocol-buffers/docs/overview).
+You can see the complete .proto file for our example in [`examples/protos/route_guide.proto`](examples/protos/route_guide.proto).
+
+To define a service, you specify a named `service` in your .proto file:
+
+```protobuf
+service RouteGuide {
+ ...
+}
+```
+
+Then you define `rpc` methods inside your service definition, specifying their request and response
+types. Protocol buffers let you define four kinds of service method, all of which are used in the
+`RouteGuide` service:
+
+- A *simple RPC* where the client sends a request to the server and receives a response later, just
+like a normal remote procedure call.
+```protobuf
+ // Obtains the feature at a given position.
+ rpc GetFeature(Point) returns (Feature) {}
+```
+
+- A *response-streaming RPC* where the client sends a request to the server and gets back a stream
+of response messages. You specify a response-streaming method by placing the `stream` keyword before
+the *response* type.
+```protobuf
+ // Obtains the Features available within the given Rectangle. Results are
+ // streamed rather than returned at once (e.g. in a response message with a
+ // repeated field), as the rectangle may cover a large area and contain a
+ // huge number of features.
+ rpc ListFeatures(Rectangle) returns (stream Feature) {}
+```
+
+- A *request-streaming RPC* where the client sends a sequence of messages to the server. Once the
+client has finished writing the messages, it waits for the server to read them all and return its
+response. You specify a request-streaming method by placing the `stream` keyword before the
+*request* type.
+```protobuf
+ // Accepts a stream of Points on a route being traversed, returning a
+ // RouteSummary when traversal is completed.
+ rpc RecordRoute(stream Point) returns (RouteSummary) {}
+```
+
+- A *bidirectional streaming RPC* where both sides send a sequence of messages to the other. The two
+streams operate independently, so clients and servers can read and write in whatever order they
+like: for example, the server could wait to receive all the client messages before writing its
+responses, or it could alternately read a message then write a message, or some other combination of
+reads and writes. The order of messages in each stream is preserved. You specify this type of method
+by placing the `stream` keyword before both the request and the response.
+```protobuf
+ // Accepts a stream of RouteNotes sent while a route is being traversed,
+ // while receiving other RouteNotes (e.g. from other users).
+ rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
+```
+
+Our .proto file also contains protocol buffer message type definitions for all the request and
+response types used in our service methods - for example, here's the `Point` message type:
+```protobuf
+// Points are represented as latitude-longitude pairs in the E7 representation
+// (degrees multiplied by 10**7 and rounded to the nearest integer).
+// Latitudes should be in the range +/- 90 degrees and longitude should be in
+// the range +/- 180 degrees (inclusive).
+message Point {
+ int32 latitude = 1;
+ int32 longitude = 2;
+}
+```
+
+You can specify a prefix to be used for your generated classes by adding the `objc_class_prefix`
+option at the top of the file. For example:
+```protobuf
+option objc_class_prefix = "RTG";
+```
+
+
+<a name="protoc"></a>
+## Generating client code
+
+Next we need to generate the gRPC client interfaces from our .proto service definition. We do this
+using the protocol buffer compiler (`protoc`) with a special gRPC Objective-C plugin.
+
+For simplicity, we've provided a [Podspec file](examples/objective-c/route_guide/RouteGuide.podspec)
+that runs `protoc` for you with the appropriate plugin, input, and output, and describes how to
+compile the generated files. You just need to run in this directory (`examples/objective-c/route_guide`):
+
+```shell
+$ pod install
+```
+
+which, before installing the generated library in the XCode project of this sample, runs:
+
+```shell
+$ protoc -I ../../protos --objc_out=Pods/RouteGuide --objcgrpc_out=Pods/RouteGuide ../../protos/route_guide.proto
+```
+
+Running this command generates the following files under `Pods/RouteGuide/`:
+- `RouteGuide.pbobjc.h`, the header which declares your generated message classes.
+- `RouteGuide.pbobjc.m`, which contains the implementation of your message classes.
+- `RouteGuide.pbrpc.h`, the header which declares your generated service classes.
+- `RouteGuide.pbrpc.m`, which contains the implementation of your service classes.
+
+These contain:
+- All the protocol buffer code to populate, serialize, and retrieve our request and response message
+types.
+- A class called `RTGRouteGuide` that lets clients call the methods defined in the `RouteGuide`
+service.
+
+You can also use the provided Podspec file to generate client code from any other proto service
+definition; just replace the name (matching the file name), version, and other metadata.
+
+
+<a name="client"></a>
+## Creating the client
+
+In this section, we'll look at creating an Objective-C client for our `RouteGuide` service. You can
+see our complete example client code in [examples/objective-c/route_guide/ViewControllers.m](examples/objective-c/route_guide/ViewControllers.m).
+(Note: In your apps, for maintainability and readability reasons, you shouldn't put all of your view
+controllers in a single file; it's done here only to simplify the learning process).
+
+### Constructing a client object
+
+To call service methods, we first need to create a client object, an instance of the generated
+`RTGRouteGuide` class. The designated initializer of the class expects a `NSString *` with the
+server address and port we want to connect to:
+
+```objective-c
+#import <RouteGuide/RouteGuide.pbrpc.h>
+
+static NSString * const kHostAddress = @"http://localhost:50051";
+
+...
+
+RTGRouteGuide *client = [[RTGRouteGuide alloc] initWithHost:kHostAddress];
+```
+
+Notice that we've specified the HTTP scheme in the host address. This is because the server we will
+be using to test our client doesn't use [TLS](http://en.wikipedia.org/wiki/Transport_Layer_Security).
+This is fine because it will be running locally on our development machine. The most common case,
+though, is connecting with a gRPC server on the internet, running gRPC over TLS. For that case, the
+HTTPS scheme can be specified (or no scheme at all, as HTTPS is the default value). The default
+value of the port is that of the scheme selected: 443 for HTTPS and 80 for HTTP.
+
+
+### Calling service methods
+
+Now let's look at how we call our service methods. As you will see, all these methods are
+asynchronous, so you can call them from the main thread of your app without worrying about freezing
+your UI or the OS killing your app.
+
+#### Simple RPC
+
+Calling the simple RPC `GetFeature` is nearly as straightforward as calling any other asynchronous
+method on Cocoa.
+
+```objective-c
+RTGPoint *point = [RTGPoint message];
+point.latitude = 40E7;
+point.longitude = -74E7;
+
+[client getFeatureWithRequest:point handler:^(RTGFeature *response, NSError *error) {
+ if (response) {
+ // Successful response received
+ } else {
+ // RPC error
+ }
+}];
+```
+
+As you can see, we create and populate a request protocol buffer object (in our case `RTGPoint`).
+Then, we call the method on the client object, passing it the request, and a block to handle the
+response (or any RPC error). If the RPC finishes successfully, the handler block is called with a
+`nil` error argument, and we can read the response information from the server from the response
+argument. If, instead, some RPC error happens, the handler block is called with a `nil` response
+argument, and we can read the details of the problem from the error argument.
+
+```objective-c
+NSLog(@"Found feature called %@ at %@.", response.name, response.location);
+```
+
+#### Streaming RPCs
+
+Now let's look at our streaming methods. Here's where we call the response-streaming method
+`ListFeatures`, which results in our client receiving a stream of geographical `RTGFeature`s:
+
+```objective-c
+[client listFeaturesWithRequest:rectangle
+ eventHandler:^(BOOL done, RTGFeature *response, NSError *error) {
+ if (response) {
+ // Element of the stream of responses received
+ } else if (error) {
+ // RPC error; the stream is over.
+ }
+ if (done) {
+ // The stream is over (all the responses were received, or an error occured). Do any cleanup.
+ }
+}];
+```
+
+Notice how the signature of the `eventHandler` block now includes a `BOOL done` parameter. The
+`eventHandler` block can be called any number of times; only on the last call is the `done` argument
+value set to `YES`. If an error occurs, the RPC finishes and the block is called with the arguments
+`(YES, nil, error)`.
+
+The request-streaming method `RecordRoute` expects a stream of `RTGPoint`s from the cient. This
+stream is passed to the method as an object of class `GRXWriter`. The simplest way to create one is
+to initialize one from a `NSArray` object:
+
+
+```objective-c
+#import <RxLibrary/GRXWriter+Immediate.h>
+
+...
+
+RTGPoint *point1 = [RTGPoint message];
+point.latitude = 40E7;
+point.longitude = -74E7;
+
+RTGPoint *point2 = [RTGPoint message];
+point.latitude = 40E7;
+point.longitude = -74E7;
+
+GRXWriter *locationsWriter = [GRXWriter writerWithContainer:@[point1, point2]];
+
+[client recordRouteWithRequestsWriter:locationsWriter
+ handler:^(RTGRouteSummary *response, NSError *error) {
+ if (response) {
+ NSLog(@"Finished trip with %i points", response.pointCount);
+ NSLog(@"Passed %i features", response.featureCount);
+ NSLog(@"Travelled %i meters", response.distance);
+ NSLog(@"It took %i seconds", response.elapsedTime);
+ } else {
+ NSLog(@"RPC error: %@", error);
+ }
+}];
+
+```
+
+The `GRXWriter` class is generic enough to allow for asynchronous streams, streams of future values,
+or even infinite streams.
+
+Finally, let's look at our bidirectional streaming RPC `RouteChat()`. The way to call a
+bidirectional streaming RPC is just a combination of how to call request-streaming RPCs and
+response-streaming RPCs.
+
+```objective-c
+[client routeChatWithRequestsWriter:notesWriter
+ eventHandler:^(BOOL done, RTGRouteNote *note, NSError *error) {
+ if (note) {
+ NSLog(@"Got message %@ at %@", note.message, note.location);
+ } else if (error) {
+ NSLog(@"RPC error: %@", error);
+ }
+ if (done) {
+ NSLog(@"Chat ended.");
+ }
+}];
+```
+
+The semantics for the handler block and the `GRXWriter` argument here are exactly the same as for
+our request-streaming and response-streaming methods. Although both client and server will always
+get the other's messages in the order they were written, the two streams operate completely
+independently.
diff --git a/examples/objective-c/route_guide/RouteGuide.podspec b/examples/objective-c/route_guide/RouteGuide.podspec
new file mode 100644
index 0000000000..7b99a6c6a7
--- /dev/null
+++ b/examples/objective-c/route_guide/RouteGuide.podspec
@@ -0,0 +1,35 @@
+Pod::Spec.new do |s|
+ s.name = "RouteGuide"
+ s.version = "0.0.1"
+ s.license = "New BSD"
+
+ s.ios.deployment_target = "6.0"
+ s.osx.deployment_target = "10.8"
+
+ # Base directory where the .proto files are.
+ src = "../../protos"
+
+ # Directory where the generated files will be place.
+ dir = "Pods/" + s.name
+
+ # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
+ s.prepare_command = <<-CMD
+ mkdir -p #{dir}
+ protoc -I #{src} --objc_out=#{dir} --objcgrpc_out=#{dir} #{src}/route_guide.proto
+ CMD
+
+ s.subspec "Messages" do |ms|
+ ms.source_files = "#{dir}/*.pbobjc.{h,m}", "#{dir}/**/*.pbobjc.{h,m}"
+ ms.header_mappings_dir = dir
+ ms.requires_arc = false
+ ms.dependency "Protobuf", "~> 3.0.0-alpha-3"
+ end
+
+ s.subspec "Services" do |ss|
+ ss.source_files = "#{dir}/*.pbrpc.{h,m}", "#{dir}/**/*.pbrpc.{h,m}"
+ ss.header_mappings_dir = dir
+ ss.requires_arc = true
+ ss.dependency "gRPC", "~> 0.6"
+ ss.dependency "#{s.name}/Messages"
+ end
+end
diff --git a/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.pbxproj b/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.pbxproj
new file mode 100644
index 0000000000..6ab6b27a1b
--- /dev/null
+++ b/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.pbxproj
@@ -0,0 +1,366 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 124E20A2FC8EAE54460D4ED2 /* libPods-RouteGuideClient.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 71CEE03D66D40FC37264D6E4 /* libPods-RouteGuideClient.a */; };
+ 632527831B1D0396003073D9 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 632527821B1D0396003073D9 /* main.m */; };
+ 632527861B1D0396003073D9 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 632527851B1D0396003073D9 /* AppDelegate.m */; };
+ 6325278F1B1D0396003073D9 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6325278D1B1D0396003073D9 /* Main.storyboard */; };
+ 632527911B1D0396003073D9 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 632527901B1D0396003073D9 /* Images.xcassets */; };
+ 6367B55B1B223AFA008861F5 /* route_guide_db.json in Resources */ = {isa = PBXBuildFile; fileRef = 6367B55A1B223AFA008861F5 /* route_guide_db.json */; };
+ 63A6015C1B1DAB5000FA5B86 /* ViewControllers.m in Sources */ = {isa = PBXBuildFile; fileRef = 63A6015B1B1DAB5000FA5B86 /* ViewControllers.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 6325277D1B1D0396003073D9 /* RouteGuideClient.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RouteGuideClient.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 632527811B1D0396003073D9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 632527821B1D0396003073D9 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ 632527841B1D0396003073D9 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+ 632527851B1D0396003073D9 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+ 6325278E1B1D0396003073D9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+ 632527901B1D0396003073D9 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
+ 6367B55A1B223AFA008861F5 /* route_guide_db.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = route_guide_db.json; sourceTree = "<group>"; };
+ 63A6015B1B1DAB5000FA5B86 /* ViewControllers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewControllers.m; sourceTree = "<group>"; };
+ 71CEE03D66D40FC37264D6E4 /* libPods-RouteGuideClient.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RouteGuideClient.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ ADA4C647BAE906F79AD9A45E /* Pods-RouteGuideClient.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RouteGuideClient.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RouteGuideClient/Pods-RouteGuideClient.debug.xcconfig"; sourceTree = "<group>"; };
+ C83C5A54D1A4EA07569F1AED /* Pods-RouteGuideClient.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RouteGuideClient.release.xcconfig"; path = "Pods/Target Support Files/Pods-RouteGuideClient/Pods-RouteGuideClient.release.xcconfig"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 6325277A1B1D0395003073D9 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 124E20A2FC8EAE54460D4ED2 /* libPods-RouteGuideClient.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 56849C29DC376BF4B902CD77 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ ADA4C647BAE906F79AD9A45E /* Pods-RouteGuideClient.debug.xcconfig */,
+ C83C5A54D1A4EA07569F1AED /* Pods-RouteGuideClient.release.xcconfig */,
+ );
+ name = Pods;
+ sourceTree = "<group>";
+ };
+ 631C63891B1DBC41001295D5 /* Misc */ = {
+ isa = PBXGroup;
+ children = (
+ 632527841B1D0396003073D9 /* AppDelegate.h */,
+ 632527851B1D0396003073D9 /* AppDelegate.m */,
+ 632527901B1D0396003073D9 /* Images.xcassets */,
+ 632527801B1D0396003073D9 /* Supporting Files */,
+ );
+ path = Misc;
+ sourceTree = "<group>";
+ };
+ 632527741B1D0395003073D9 = {
+ isa = PBXGroup;
+ children = (
+ 6325277F1B1D0396003073D9 /* RouteGuideClient */,
+ 6325277E1B1D0396003073D9 /* Products */,
+ 56849C29DC376BF4B902CD77 /* Pods */,
+ 7482B8A18481F7B13ADE4530 /* Frameworks */,
+ );
+ sourceTree = "<group>";
+ };
+ 6325277E1B1D0396003073D9 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 6325277D1B1D0396003073D9 /* RouteGuideClient.app */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 6325277F1B1D0396003073D9 /* RouteGuideClient */ = {
+ isa = PBXGroup;
+ children = (
+ 63A6015B1B1DAB5000FA5B86 /* ViewControllers.m */,
+ 6367B55A1B223AFA008861F5 /* route_guide_db.json */,
+ 6325278D1B1D0396003073D9 /* Main.storyboard */,
+ 631C63891B1DBC41001295D5 /* Misc */,
+ );
+ name = RouteGuideClient;
+ sourceTree = SOURCE_ROOT;
+ };
+ 632527801B1D0396003073D9 /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ 632527811B1D0396003073D9 /* Info.plist */,
+ 632527821B1D0396003073D9 /* main.m */,
+ );
+ name = "Supporting Files";
+ sourceTree = "<group>";
+ };
+ 7482B8A18481F7B13ADE4530 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 71CEE03D66D40FC37264D6E4 /* libPods-RouteGuideClient.a */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 6325277C1B1D0395003073D9 /* RouteGuideClient */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 632527A31B1D0396003073D9 /* Build configuration list for PBXNativeTarget "RouteGuideClient" */;
+ buildPhases = (
+ C6FC30AD2376EC04317237C5 /* Check Pods Manifest.lock */,
+ 632527791B1D0395003073D9 /* Sources */,
+ 6325277A1B1D0395003073D9 /* Frameworks */,
+ 6325277B1B1D0395003073D9 /* Resources */,
+ FFE0BCF30339E7A50A989EAB /* Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = RouteGuideClient;
+ productName = RouteGuideClient;
+ productReference = 6325277D1B1D0396003073D9 /* RouteGuideClient.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 632527751B1D0395003073D9 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0630;
+ ORGANIZATIONNAME = gRPC;
+ TargetAttributes = {
+ 6325277C1B1D0395003073D9 = {
+ CreatedOnToolsVersion = 6.3.1;
+ };
+ };
+ };
+ buildConfigurationList = 632527781B1D0395003073D9 /* Build configuration list for PBXProject "RouteGuideClient" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 632527741B1D0395003073D9;
+ productRefGroup = 6325277E1B1D0396003073D9 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 6325277C1B1D0395003073D9 /* RouteGuideClient */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 6325277B1B1D0395003073D9 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 6325278F1B1D0396003073D9 /* Main.storyboard in Resources */,
+ 632527911B1D0396003073D9 /* Images.xcassets in Resources */,
+ 6367B55B1B223AFA008861F5 /* route_guide_db.json in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ C6FC30AD2376EC04317237C5 /* Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Check Pods Manifest.lock";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
+ showEnvVarsInLog = 0;
+ };
+ FFE0BCF30339E7A50A989EAB /* Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RouteGuideClient/Pods-RouteGuideClient-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 632527791B1D0395003073D9 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 632527861B1D0396003073D9 /* AppDelegate.m in Sources */,
+ 632527831B1D0396003073D9 /* main.m in Sources */,
+ 63A6015C1B1DAB5000FA5B86 /* ViewControllers.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ 6325278D1B1D0396003073D9 /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 6325278E1B1D0396003073D9 /* Base */,
+ );
+ name = Main.storyboard;
+ path = Misc;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 632527A11B1D0396003073D9 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.3;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 632527A21B1D0396003073D9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.3;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 632527A41B1D0396003073D9 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = ADA4C647BAE906F79AD9A45E /* Pods-RouteGuideClient.debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = Misc/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 632527A51B1D0396003073D9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = C83C5A54D1A4EA07569F1AED /* Pods-RouteGuideClient.release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = Misc/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 632527781B1D0395003073D9 /* Build configuration list for PBXProject "RouteGuideClient" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 632527A11B1D0396003073D9 /* Debug */,
+ 632527A21B1D0396003073D9 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 632527A31B1D0396003073D9 /* Build configuration list for PBXNativeTarget "RouteGuideClient" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 632527A41B1D0396003073D9 /* Debug */,
+ 632527A51B1D0396003073D9 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 632527751B1D0395003073D9 /* Project object */;
+}
diff --git a/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000000..f208589e44
--- /dev/null
+++ b/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:RouteGuideClient.xcodeproj">
+ </FileRef>
+</Workspace>
diff --git a/examples/objective-c/route_guide/ViewControllers.m b/examples/objective-c/route_guide/ViewControllers.m
new file mode 100644
index 0000000000..cfc3338bca
--- /dev/null
+++ b/examples/objective-c/route_guide/ViewControllers.m
@@ -0,0 +1,228 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <RouteGuide/RouteGuide.pbrpc.h>
+#import <RxLibrary/GRXWriter+Immediate.h>
+#import <RxLibrary/GRXWriter+Transformations.h>
+
+static NSString * const kHostAddress = @"http://localhost:50051";
+
+// Category to override RTGPoint's description.
+@interface RTGPoint (Description)
+- (NSString *)description;
+@end
+
+@implementation RTGPoint (Description)
+- (NSString *)description {
+ NSString *verticalDirection = self.latitude >= 0 ? @"N" : @"S";
+ NSString *horizontalDirection = self.longitude >= 0 ? @"E" : @"W";
+ return [NSString stringWithFormat:@"%.02f%@ %.02f%@",
+ abs(self.latitude) / 1E7f, verticalDirection,
+ abs(self.longitude) / 1E7f, horizontalDirection];
+}
+@end
+
+// Category to give RTGRouteNote a convenience constructor.
+@interface RTGRouteNote (Constructors)
++ (instancetype)noteWithMessage:(NSString *)message
+ latitude:(float)latitude
+ longitude:(float)longitude;
+@end
+
+@implementation RTGRouteNote (Constructors)
++ (instancetype)noteWithMessage:(NSString *)message
+ latitude:(float)latitude
+ longitude:(float)longitude {
+ RTGRouteNote *note = [self message];
+ note.message = message;
+ note.location.latitude = (int32_t) latitude * 1E7;
+ note.location.longitude = (int32_t) longitude * 1E7;
+ return note;
+}
+@end
+
+
+#pragma mark Demo: Get Feature
+
+// Run the getFeature demo. Calls getFeature with a point known to have a feature and a point known
+// not to have a feature.
+
+@interface GetFeatureViewController : UIViewController
+@end
+
+@implementation GetFeatureViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+
+ RTGRouteGuide *client = [[RTGRouteGuide alloc] initWithHost:kHostAddress];
+
+ void (^handler)(RTGFeature *response, NSError *error) = ^(RTGFeature *response, NSError *error) {
+ if (response.name.length) {
+ NSLog(@"Found feature called %@ at %@.", response.name, response.location);
+ } else if (response) {
+ NSLog(@"Found no features at %@", response.location);
+ } else {
+ NSLog(@"RPC error: %@", error);
+ }
+ };
+
+ RTGPoint *point = [RTGPoint message];
+ point.latitude = 409146138;
+ point.longitude = -746188906;
+
+ [client getFeatureWithRequest:point handler:handler];
+ [client getFeatureWithRequest:[RTGPoint message] handler:handler];
+}
+
+@end
+
+
+#pragma mark Demo: List Features
+
+// Run the listFeatures demo. Calls listFeatures with a rectangle containing all of the features in
+// the pre-generated database. Prints each response as it comes in.
+
+@interface ListFeaturesViewController : UIViewController
+@end
+
+@implementation ListFeaturesViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+
+ RTGRouteGuide *client = [[RTGRouteGuide alloc] initWithHost:kHostAddress];
+
+ RTGRectangle *rectangle = [RTGRectangle message];
+ rectangle.lo.latitude = 405E6;
+ rectangle.lo.longitude = -750E6;
+ rectangle.hi.latitude = 410E6;
+ rectangle.hi.longitude = -745E6;
+
+ NSLog(@"Looking for features between %@ and %@", rectangle.lo, rectangle.hi);
+ [client listFeaturesWithRequest:rectangle
+ eventHandler:^(BOOL done, RTGFeature *response, NSError *error) {
+ if (response) {
+ NSLog(@"Found feature at %@ called %@.", response.location, response.name);
+ } else if (error) {
+ NSLog(@"RPC error: %@", error);
+ }
+ }];
+}
+
+@end
+
+
+#pragma mark Demo: Record Route
+
+// Run the recordRoute demo. Sends several randomly chosen points from the pre-generated feature
+// database with a variable delay in between. Prints the statistics when they are sent from the
+// server.
+
+@interface RecordRouteViewController : UIViewController
+@end
+
+@implementation RecordRouteViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+
+ NSString *dataBasePath = [NSBundle.mainBundle pathForResource:@"route_guide_db"
+ ofType:@"json"];
+ NSData *dataBaseContent = [NSData dataWithContentsOfFile:dataBasePath];
+ NSArray *features = [NSJSONSerialization JSONObjectWithData:dataBaseContent options:0 error:NULL];
+
+ GRXWriter *locations = [[GRXWriter writerWithContainer:features] map:^id(id feature) {
+ RTGPoint *location = [RTGPoint message];
+ location.longitude = [((NSNumber *) feature[@"location"][@"longitude"]) intValue];
+ location.latitude = [((NSNumber *) feature[@"location"][@"latitude"]) intValue];
+ NSLog(@"Visiting point %@", location);
+ return location;
+ }];
+
+ RTGRouteGuide *client = [[RTGRouteGuide alloc] initWithHost:kHostAddress];
+
+ [client recordRouteWithRequestsWriter:locations handler:^(RTGRouteSummary *response, NSError *error) {
+ if (response) {
+ NSLog(@"Finished trip with %i points", response.pointCount);
+ NSLog(@"Passed %i features", response.featureCount);
+ NSLog(@"Travelled %i meters", response.distance);
+ NSLog(@"It took %i seconds", response.elapsedTime);
+ } else {
+ NSLog(@"RPC error: %@", error);
+ }
+ }];
+}
+
+@end
+
+
+#pragma mark Demo: Route Chat
+
+// Run the routeChat demo. Send some chat messages, and print any chat messages that are sent from
+// the server.
+
+@interface RouteChatViewController : UIViewController
+@end
+
+@implementation RouteChatViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+
+ NSArray *notes = @[[RTGRouteNote noteWithMessage:@"First message" latitude:0 longitude:0],
+ [RTGRouteNote noteWithMessage:@"Second message" latitude:0 longitude:1],
+ [RTGRouteNote noteWithMessage:@"Third message" latitude:1 longitude:0],
+ [RTGRouteNote noteWithMessage:@"Fourth message" latitude:0 longitude:0]];
+ GRXWriter *notesWriter = [[GRXWriter writerWithContainer:notes] map:^id(RTGRouteNote *note) {
+ NSLog(@"Sending message %@ at %@", note.message, note.location);
+ return note;
+ }];
+
+ RTGRouteGuide *client = [[RTGRouteGuide alloc] initWithHost:kHostAddress];
+
+ [client routeChatWithRequestsWriter:notesWriter
+ eventHandler:^(BOOL done, RTGRouteNote *note, NSError *error) {
+ if (note) {
+ NSLog(@"Got message %@ at %@", note.message, note.location);
+ } else if (error) {
+ NSLog(@"RPC error: %@", error);
+ }
+ if (done) {
+ NSLog(@"Chat ended.");
+ }
+ }];
+}
+
+@end
diff --git a/examples/objective-c/route_guide/route_guide_db.json b/examples/objective-c/route_guide/route_guide_db.json
new file mode 100644
index 0000000000..9caebaa433
--- /dev/null
+++ b/examples/objective-c/route_guide/route_guide_db.json
@@ -0,0 +1,121 @@
+[{
+ "location": {
+ "latitude": 407838351,
+ "longitude": -746143763
+ },
+ "name": "Patriots Path, Mendham, NJ 07945, USA"
+}, {
+ "location": {
+ "latitude": 408122808,
+ "longitude": -743999179
+ },
+ "name": "101 New Jersey 10, Whippany, NJ 07981, USA"
+}, {
+ "location": {
+ "latitude": 413628156,
+ "longitude": -749015468
+ },
+ "name": "U.S. 6, Shohola, PA 18458, USA"
+}, {
+ "location": {
+ "latitude": 419999544,
+ "longitude": -740371136
+ },
+ "name": "5 Conners Road, Kingston, NY 12401, USA"
+}, {
+ "location": {
+ "latitude": 414008389,
+ "longitude": -743951297
+ },
+ "name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA"
+}, {
+ "location": {
+ "latitude": 419611318,
+ "longitude": -746524769
+ },
+ "name": "287 Flugertown Road, Livingston Manor, NY 12758, USA"
+}, {
+ "location": {
+ "latitude": 406109563,
+ "longitude": -742186778
+ },
+ "name": "4001 Tremley Point Road, Linden, NJ 07036, USA"
+}, {
+ "location": {
+ "latitude": 416802456,
+ "longitude": -742370183
+ },
+ "name": "352 South Mountain Road, Wallkill, NY 12589, USA"
+}, {
+ "location": {
+ "latitude": 412950425,
+ "longitude": -741077389
+ },
+ "name": "Bailey Turn Road, Harriman, NY 10926, USA"
+}, {
+ "location": {
+ "latitude": 412144655,
+ "longitude": -743949739
+ },
+ "name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA"
+}, {
+ "location": {
+ "latitude": 404306372,
+ "longitude": -741079661
+ },
+ "name": ""
+}, {
+ "location": {
+ "latitude": 403966326,
+ "longitude": -748519297
+ },
+ "name": ""
+}, {
+ "location": {
+ "latitude": 405002031,
+ "longitude": -748407866
+ },
+ "name": ""
+}, {
+ "location": {
+ "latitude": 409532885,
+ "longitude": -742200683
+ },
+ "name": ""
+}, {
+ "location": {
+ "latitude": 416851321,
+ "longitude": -742674555
+ },
+ "name": ""
+}, {
+ "location": {
+ "latitude": 406411633,
+ "longitude": -741722051
+ },
+ "name": "3387 Richmond Terrace, Staten Island, NY 10303, USA"
+}, {
+ "location": {
+ "latitude": 413069058,
+ "longitude": -744597778
+ },
+ "name": "261 Van Sickle Road, Goshen, NY 10924, USA"
+}, {
+ "location": {
+ "latitude": 418465462,
+ "longitude": -746859398
+ },
+ "name": ""
+}, {
+ "location": {
+ "latitude": 411733222,
+ "longitude": -744228360
+ },
+ "name": ""
+}, {
+ "location": {
+ "latitude": 410248224,
+ "longitude": -747127767
+ },
+ "name": "3 Hasta Way, Newton, NJ 07860, USA"
+}]