mirror of https://github.com/grpc/grpc.io.git
507 lines
31 KiB
HTML
507 lines
31 KiB
HTML
|
|
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
|
|
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400" rel="stylesheet">
|
|
<link rel="stylesheet" type="text/css" href="/css/style.css">
|
|
<title>
|
|
gRPC Basics - Objective-C – gRPC
|
|
</title>
|
|
|
|
|
|
<link rel="apple-touch-icon" href="/favicons/apple-touch-icon.png" sizes="180x180">
|
|
<link rel="icon" type="image/png" href="/favicons/android-chrome-192x192.png" sizes="192x192" >
|
|
<link rel="icon" type="image/png" href="/favicons/favicon-32x32.png" sizes="32x32">
|
|
<link rel="icon" type="image/png" href="/favicons/favicon-16x16.png" sizes="16x16">
|
|
<link rel="manifest" href="/favicons/manifest.json">
|
|
<link rel="mask-icon" href="/favicons/safari-pinned-tab.svg" color="#2DA6B0">
|
|
<meta name="msapplication-TileColor" content="#ffffff">
|
|
<meta name="msapplication-TileImage" content="/favicons/mstile-150x150.png">
|
|
|
|
|
|
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-60127042-1"></script>
|
|
<script>
|
|
window.dataLayer = window.dataLayer || [];
|
|
function gtag(){dataLayer.push(arguments);}
|
|
gtag('js', new Date());
|
|
|
|
gtag('config', 'UA-60127042-1');
|
|
</script>
|
|
|
|
</head>
|
|
<body>
|
|
<div id="landing-content">
|
|
<div class="row">
|
|
<div class="topbannersub">
|
|
<nav class="navbar navbar-expand-md navbar-dark topnav">
|
|
<a class="navbar-brand" href="https://cjyabraham.github.io/">
|
|
<img src="https://cjyabraham.github.io/img/grpc-logo.png" width="114" height="50">
|
|
</a>
|
|
|
|
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
|
<span class="navbar-toggler-icon"></span>
|
|
</button>
|
|
|
|
<div class="topnav, collapse navbar-collapse" id="navbarSupportedContent" style="float:right !important">
|
|
<ul class="navbar-nav ml-auto">
|
|
<li class="nav-item ">
|
|
<a class="nav-link" href="https://cjyabraham.github.io/about/">About</a>
|
|
</li>
|
|
<li class="nav-item dropdown active">
|
|
<a class="nav-link dropdown-toggle" href="https://cjyabraham.github.io/docs/" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
Docs
|
|
</a>
|
|
|
|
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
|
|
|
|
|
<a class="dropdown-item" href="/docs">
|
|
Overview
|
|
</a>
|
|
|
|
|
|
<a class="dropdown-item" href="/docs/quickstart/">
|
|
Quick Start
|
|
</a>
|
|
|
|
|
|
<a class="dropdown-item" href="/docs/guides/">
|
|
Guides
|
|
</a>
|
|
|
|
|
|
<a class="dropdown-item" href="/docs/tutorials/">
|
|
Tutorials
|
|
</a>
|
|
|
|
|
|
<a class="dropdown-item" href="/docs/reference/">
|
|
Reference
|
|
</a>
|
|
|
|
|
|
<a class="dropdown-item" href="/docs/samples/">
|
|
Samples
|
|
</a>
|
|
|
|
|
|
<a class="dropdown-item" href="/docs/talks">
|
|
Presentations
|
|
</a>
|
|
|
|
</div>
|
|
</li>
|
|
<li class="nav-item ">
|
|
<a class="nav-link" href="/blog">
|
|
Blog
|
|
</a>
|
|
</li>
|
|
<li class="nav-item ">
|
|
<a class="nav-link" href="/community">Community</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="https://packages.grpc.io/">
|
|
Packages
|
|
</a>
|
|
</li>
|
|
<li class="nav-item ">
|
|
<a class="nav-link" href="https://cjyabraham.github.io/faq/">FAQ</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
|
|
|
|
<div class="headertext">Documentation</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="subnav d-none d-md-block">
|
|
<a href="https://cjyabraham.github.io/docs/" >Overview</a>
|
|
| <a href="https://cjyabraham.github.io/docs/quickstart/" >Quick Start</a>
|
|
| <a href="https://cjyabraham.github.io/docs/guides/" >Guides</a>
|
|
| <a href="https://cjyabraham.github.io/docs/tutorials/" class="active">Tutorials</a>
|
|
| <a href="https://cjyabraham.github.io/docs/reference/" >Reference</a>
|
|
| <a href="https://cjyabraham.github.io/docs/samples/" >Samples</a>
|
|
| <a href="https://cjyabraham.github.io/docs/talks/" >Presentations</a>
|
|
</div>
|
|
|
|
|
|
<div class="quickstartcols">
|
|
|
|
<div class="quickstartcol1">
|
|
|
|
<h8>Tutorials</h8>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/async/helloasync-cpp/" >Async - C++</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/auth/oauth2-objective-c/" >Auth - Objective C</a>
|
|
<h8>Basic</h8>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/c/" >C++</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/csharp/" >C#</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/dart/" >Dart</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/go/" >Go</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/java/" >Java</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/android/" >Android Java</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/node/" >Node</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/objective-c/" class="active">Objective-C</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/php/" >PHP</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/python/" >Python</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/ruby/" >Ruby</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/web/" >Web</a>
|
|
|
|
</div>
|
|
|
|
<div class="quickstartcol2" style="margin-top:4%">
|
|
<h3 style="margin-top:0px;">gRPC Basics - Objective-C</h3>
|
|
|
|
|
|
|
|
<p>This tutorial provides a basic Objective-C programmer’s
|
|
introduction to working with gRPC.</p>
|
|
|
|
<p>By walking through this example you’ll learn how to:</p>
|
|
|
|
<ul>
|
|
<li>Define a service in a .proto file.</li>
|
|
<li>Generate client code using the protocol buffer compiler.</li>
|
|
<li>Use the Objective-C gRPC API to write a simple client for your service.</li>
|
|
</ul>
|
|
|
|
<p>It assumes a passing familiarity with <a href="https://developers.google.com/protocol-buffers/docs/overview">protocol
|
|
buffers</a>. Note
|
|
that the example in this tutorial uses the proto3 version of the protocol
|
|
buffers language: you can find out more in
|
|
the <a href="https://developers.google.com/protocol-buffers/docs/proto3">proto3 language
|
|
guide</a> and the
|
|
<a href="https://developers.google.com/protocol-buffers/docs/reference/objective-c-generated">Objective-C generated code
|
|
guide</a>.</p>
|
|
|
|
<div id="toc"></div>
|
|
|
|
<p><a name="why-grpc"></a></p>
|
|
|
|
<h3 id="why-use-grpc">Why use gRPC?</h3>
|
|
|
|
<p>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.</p>
|
|
|
|
<p>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.</p>
|
|
|
|
<p><a name="setup"></a></p>
|
|
|
|
<h3 id="example-code-and-setup">Example code and setup</h3>
|
|
|
|
<p>The example code for our tutorial is in
|
|
<a href="https://github.com/grpc/grpc/tree/v1.20.0/examples/objective-c/route_guide">grpc/grpc/examples/objective-c/route_guide</a>.
|
|
To download the example, clone the <code>grpc</code> repository by running the following
|
|
commands:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">$ git clone -b v1.20.0 https://github.com/grpc/grpc
|
|
$ cd grpc
|
|
$ git submodule update --init</code></pre></div>
|
|
<p>Then change your current directory to <code>examples/objective-c/route_guide</code>:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">$ cd examples/objective-c/route_guide</code></pre></div>
|
|
<p>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.</p>
|
|
|
|
<p>You also should have <a href="https://cocoapods.org/#install">Cocoapods</a> 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 <a href="https://github.com/grpc/homebrew-grpc">these
|
|
setup instructions</a>.</p>
|
|
|
|
<p><a name="try"></a></p>
|
|
|
|
<h2 id="try-it-out">Try it out!</h2>
|
|
|
|
<p>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:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">$ pushd ../../cpp/route_guide
|
|
$ make
|
|
$ ./route_guide_server &
|
|
$ popd</code></pre></div>
|
|
<p>Now have Cocoapods generate and install the client library for our .proto files:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">$ pod install</code></pre></div>
|
|
<p>(This might have to compile OpenSSL, which takes around 15 minutes if Cocoapods
|
|
doesn’t have it yet on your computer’s cache).</p>
|
|
|
|
<p>Finally, open the XCode workspace created by Cocoapods, and run the app. You can
|
|
check the calling code in <code>ViewControllers.m</code> and see the results in XCode’s log
|
|
console.</p>
|
|
|
|
<p>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.</p>
|
|
|
|
<p><a name="proto"></a></p>
|
|
|
|
<h3 id="defining-the-service">Defining the service</h3>
|
|
|
|
<p>First let’s look at how the service we’re using is defined. A gRPC <em>service</em> and
|
|
its method <em>request</em> and <em>response</em> types using <a href="https://developers.google.com/protocol-buffers/docs/overview">protocol
|
|
buffers</a>. You can
|
|
see the complete .proto file for our example in
|
|
<a href="https://github.com/grpc/grpc/blob/v1.20.0/examples/protos/route_guide.proto"><code>examples/protos/route_guide.proto</code></a>.</p>
|
|
|
|
<p>To define a service, you specify a named <code>service</code> in your .proto file:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-protobuf" data-lang="protobuf"><span style="color:#66d9ef">service</span> RouteGuide {<span style="color:#960050;background-color:#1e0010">
|
|
</span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#f92672">...</span><span style="color:#960050;background-color:#1e0010">
|
|
</span><span style="color:#960050;background-color:#1e0010"></span>}</code></pre></div>
|
|
<p>Then you define <code>rpc</code> 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 <code>RouteGuide</code> service:</p>
|
|
|
|
<ul>
|
|
<li>A <em>simple RPC</em> where the client sends a request to the server and receives a
|
|
response later, just like a normal remote procedure call.</li>
|
|
</ul>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-protobuf" data-lang="protobuf"><span style="color:#75715e">// Obtains the feature at a given position.
|
|
</span><span style="color:#75715e"></span><span style="color:#66d9ef">rpc</span> GetFeature(Point) <span style="color:#66d9ef">returns</span> (Feature) {}</code></pre></div>
|
|
<ul>
|
|
<li>A <em>response-streaming RPC</em> 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 <code>stream</code> keyword before the <em>response</em> type.</li>
|
|
</ul>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-protobuf" data-lang="protobuf"><span style="color:#75715e">// Obtains the Features available within the given Rectangle. Results are
|
|
</span><span style="color:#75715e">// streamed rather than returned at once (e.g. in a response message with a
|
|
</span><span style="color:#75715e">// repeated field), as the rectangle may cover a large area and contain a
|
|
</span><span style="color:#75715e">// huge number of features.
|
|
</span><span style="color:#75715e"></span><span style="color:#66d9ef">rpc</span> ListFeatures(Rectangle) <span style="color:#66d9ef">returns</span> (stream Feature) {}</code></pre></div>
|
|
<ul>
|
|
<li>A <em>request-streaming RPC</em> 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 <code>stream</code> keyword before the <em>request</em>
|
|
type.</li>
|
|
</ul>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-protobuf" data-lang="protobuf"><span style="color:#75715e">// Accepts a stream of Points on a route being traversed, returning a
|
|
</span><span style="color:#75715e">// RouteSummary when traversal is completed.
|
|
</span><span style="color:#75715e"></span><span style="color:#66d9ef">rpc</span> RecordRoute(stream Point) <span style="color:#66d9ef">returns</span> (RouteSummary) {}</code></pre></div>
|
|
<ul>
|
|
<li>A <em>bidirectional streaming RPC</em> 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 <code>stream</code> keyword
|
|
before both the request and the response.</li>
|
|
</ul>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-protobuf" data-lang="protobuf"><span style="color:#75715e">// Accepts a stream of RouteNotes sent while a route is being traversed,
|
|
</span><span style="color:#75715e">// while receiving other RouteNotes (e.g. from other users).
|
|
</span><span style="color:#75715e"></span><span style="color:#66d9ef">rpc</span> RouteChat(stream RouteNote) <span style="color:#66d9ef">returns</span> (stream RouteNote) {}</code></pre></div>
|
|
<p>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 <code>Point</code> message type:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-protobuf" data-lang="protobuf"><span style="color:#75715e">// Points are represented as latitude-longitude pairs in the E7 representation
|
|
</span><span style="color:#75715e">// (degrees multiplied by 10**7 and rounded to the nearest integer).
|
|
</span><span style="color:#75715e">// Latitudes should be in the range +/- 90 degrees and longitude should be in
|
|
</span><span style="color:#75715e">// the range +/- 180 degrees (inclusive).
|
|
</span><span style="color:#75715e"></span><span style="color:#66d9ef">message</span> <span style="color:#a6e22e">Point</span> {<span style="color:#960050;background-color:#1e0010">
|
|
</span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#66d9ef">int32</span> latitude <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span>;<span style="color:#960050;background-color:#1e0010">
|
|
</span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#66d9ef">int32</span> longitude <span style="color:#f92672">=</span> <span style="color:#ae81ff">2</span>;<span style="color:#960050;background-color:#1e0010">
|
|
</span><span style="color:#960050;background-color:#1e0010"></span>}</code></pre></div>
|
|
<p>You can specify a prefix to be used for your generated classes by adding the
|
|
<code>objc_class_prefix</code> option at the top of the file. For example:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-protobuf" data-lang="protobuf"><span style="color:#66d9ef">option</span> objc_class_prefix <span style="color:#f92672">=</span> <span style="color:#e6db74">"RTG"</span>;</code></pre></div>
|
|
<p><a name="protoc"></a></p>
|
|
|
|
<h3 id="generating-client-code">Generating client code</h3>
|
|
|
|
<p>Next we need to generate the gRPC client interfaces from our .proto service
|
|
definition. We do this using the protocol buffer compiler (<code>protoc</code>) with a
|
|
special gRPC Objective-C plugin.</p>
|
|
|
|
<p>For simplicity, we’ve provided a <a href="https://github.com/grpc/grpc/blob/v1.20.0/examples/objective-c/route_guide/RouteGuide.podspec">Podspec
|
|
file</a>
|
|
that runs <code>protoc</code> 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 (<code>examples/objective-c/route_guide</code>):</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">$ pod install</code></pre></div>
|
|
<p>which, before installing the generated library in the XCode project of this sample, runs:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">$ protoc -I ../../protos --objc_out<span style="color:#f92672">=</span>Pods/RouteGuide --objcgrpc_out<span style="color:#f92672">=</span>Pods/RouteGuide ../../protos/route_guide.proto</code></pre></div>
|
|
<p>Running this command generates the following files under <code>Pods/RouteGuide/</code>:</p>
|
|
|
|
<ul>
|
|
<li><code>RouteGuide.pbobjc.h</code>, the header which declares your generated message
|
|
classes.</li>
|
|
<li><code>RouteGuide.pbobjc.m</code>, which contains the implementation of your message
|
|
classes.</li>
|
|
<li><code>RouteGuide.pbrpc.h</code>, the header which declares your generated service
|
|
classes.</li>
|
|
<li><code>RouteGuide.pbrpc.m</code>, which contains the implementation of your service
|
|
classes.</li>
|
|
</ul>
|
|
|
|
<p>These contain:</p>
|
|
|
|
<ul>
|
|
<li>All the protocol buffer code to populate, serialize, and retrieve our request
|
|
and response message types.</li>
|
|
<li>A class called <code>RTGRouteGuide</code> that lets clients call the methods defined in
|
|
the <code>RouteGuide</code> service.</li>
|
|
</ul>
|
|
|
|
<p>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.</p>
|
|
|
|
<p><a name="client"></a></p>
|
|
|
|
<h3 id="creating-the-client-application">Creating the client application</h3>
|
|
|
|
<p>In this section, we’ll look at creating an Objective-C client for our
|
|
<code>RouteGuide</code> service. You can see our complete example client code in
|
|
<a href="https://github.com/grpc/grpc/blob/v1.20.0/examples/objective-c/route_guide/ViewControllers.m">examples/objective-c/route_guide/ViewControllers.m</a>.
|
|
(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).</p>
|
|
|
|
<h4 id="constructing-a-service-object">Constructing a service object</h4>
|
|
|
|
<p>To call service methods, we first need to create a service object, an instance
|
|
of the generated <code>RTGRouteGuide</code> class. The designated initializer of the class
|
|
expects a <code>NSString *</code> with the server address and port we want to connect to:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-objective-c" data-lang="objective-c"><span style="color:#75715e">#import <GRPCClient/GRPCCall+Tests.h>
|
|
</span><span style="color:#75715e">#import <RouteGuide/RouteGuide.pbrpc.h>
|
|
</span><span style="color:#75715e"></span>
|
|
<span style="color:#66d9ef">static</span> NSString <span style="color:#f92672">*</span> <span style="color:#66d9ef">const</span> kHostAddress <span style="color:#f92672">=</span> <span style="color:#e6db74">@"localhost:50051"</span>;
|
|
...
|
|
[GRPCCall useInsecureConnectionsForHost:kHostAddress];
|
|
|
|
RTGRouteGuide <span style="color:#f92672">*</span>service <span style="color:#f92672">=</span> [[RTGRouteGuide alloc] initWithHost:kHostAddress];</code></pre></div>
|
|
<p>Notice that before constructing our service object we’ve told the gRPC library
|
|
to use insecure connections for that host:port pair. This is because the server
|
|
we will be using to test our client doesn’t use
|
|
<a href="https://en.wikipedia.org/wiki/Transport_Layer_Security">TLS</a>. 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 <code>useInsecureConnectionsForHost:</code> call isn’t needed,
|
|
and the port defaults to 443 if absent.</p>
|
|
|
|
<h4 id="calling-service-methods">Calling service methods</h4>
|
|
|
|
<p>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.</p>
|
|
|
|
<h5 id="simple-rpc">Simple RPC</h5>
|
|
|
|
<p>Calling the simple RPC <code>GetFeature</code> is as straightforward as calling any other
|
|
asynchronous method on Cocoa.</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-objective-c" data-lang="objective-c">RTGPoint <span style="color:#f92672">*</span>point <span style="color:#f92672">=</span> [RTGPoint message];
|
|
point.latitude <span style="color:#f92672">=</span> <span style="color:#ae81ff">40E7</span>;
|
|
point.longitude <span style="color:#f92672">=</span> <span style="color:#f92672">-</span><span style="color:#ae81ff">74E7</span>;
|
|
|
|
[service getFeatureWithRequest:point handler:<span style="color:#f92672">^</span>(RTGFeature <span style="color:#f92672">*</span>response, NSError <span style="color:#f92672">*</span>error) {
|
|
<span style="color:#66d9ef">if</span> (response) {
|
|
<span style="color:#75715e">// Successful response received
|
|
</span><span style="color:#75715e"></span> } <span style="color:#66d9ef">else</span> {
|
|
<span style="color:#75715e">// RPC error
|
|
</span><span style="color:#75715e"></span> }
|
|
}];</code></pre></div>
|
|
<p>As you can see, we create and populate a request protocol buffer object (in our
|
|
case <code>RTGPoint</code>). Then, we call the method on the service 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 <code>nil</code> 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 <code>nil</code> response argument, and we can read the details of the problem from the
|
|
error argument.</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-objective-c" data-lang="objective-c">NSLog(<span style="color:#e6db74">@"Found feature called %@ at %@."</span>, response.name, response.location);</code></pre></div>
|
|
<h5 id="streaming-rpcs">Streaming RPCs</h5>
|
|
|
|
<p>Now let’s look at our streaming methods. Here’s where we call the
|
|
response-streaming method <code>ListFeatures</code>, which results in our client app
|
|
receiving a stream of geographical <code>RTGFeature</code>s:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-objective-c" data-lang="objective-c">[service listFeaturesWithRequest:rectangle
|
|
eventHandler:<span style="color:#f92672">^</span>(<span style="color:#66d9ef">BOOL</span> done, RTGFeature <span style="color:#f92672">*</span>response, NSError <span style="color:#f92672">*</span>error) {
|
|
<span style="color:#66d9ef">if</span> (response) {
|
|
NSLog(<span style="color:#e6db74">@"Found feature at %@ called %@."</span>, response.location, response.name);
|
|
} <span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> (error) {
|
|
NSLog(<span style="color:#e6db74">@"RPC error: %@"</span>, error);
|
|
}
|
|
}];</code></pre></div>
|
|
<p>Notice how the signature of the handler block now includes a <code>BOOL done</code>
|
|
parameter. The handler block can be called any number of times; only on the last
|
|
call is the <code>done</code> argument value set to <code>YES</code>. If an error occurs, the RPC
|
|
finishes and the handler is called with the arguments <code>(YES, nil, error)</code>.</p>
|
|
|
|
<p>The request-streaming method <code>RecordRoute</code> expects a stream of <code>RTGPoint</code>s from
|
|
the cient. This stream is passed to the method as an object that conforms to the
|
|
<code>GRXWriter</code> protocol. The simplest way to create one is to initialize one from a
|
|
<code>NSArray</code> object:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-objective-c" data-lang="objective-c"><span style="color:#75715e">#import <gRPC/GRXWriter+Immediate.h>
|
|
</span><span style="color:#75715e"></span>
|
|
...
|
|
|
|
RTGPoint <span style="color:#f92672">*</span>point1 <span style="color:#f92672">=</span> [RTGPoint message];
|
|
point.latitude <span style="color:#f92672">=</span> <span style="color:#ae81ff">40E7</span>;
|
|
point.longitude <span style="color:#f92672">=</span> <span style="color:#f92672">-</span><span style="color:#ae81ff">74E7</span>;
|
|
|
|
RTGPoint <span style="color:#f92672">*</span>point2 <span style="color:#f92672">=</span> [RTGPoint message];
|
|
point.latitude <span style="color:#f92672">=</span> <span style="color:#ae81ff">40E7</span>;
|
|
point.longitude <span style="color:#f92672">=</span> <span style="color:#f92672">-</span><span style="color:#ae81ff">74E7</span>;
|
|
|
|
GRXWriter <span style="color:#f92672">*</span>locationsWriter <span style="color:#f92672">=</span> [GRXWriter writerWithContainer:<span style="color:#ae81ff">@[</span>point1, point2<span style="color:#ae81ff">]</span>];
|
|
|
|
[service recordRouteWithRequestsWriter:locationsWriter handler:<span style="color:#f92672">^</span>(RTGRouteSummary <span style="color:#f92672">*</span>response, NSError <span style="color:#f92672">*</span>error) {
|
|
<span style="color:#66d9ef">if</span> (response) {
|
|
NSLog(<span style="color:#e6db74">@"Finished trip with %i points"</span>, response.pointCount);
|
|
NSLog(<span style="color:#e6db74">@"Passed %i features"</span>, response.featureCount);
|
|
NSLog(<span style="color:#e6db74">@"Travelled %i meters"</span>, response.distance);
|
|
NSLog(<span style="color:#e6db74">@"It took %i seconds"</span>, response.elapsedTime);
|
|
} <span style="color:#66d9ef">else</span> {
|
|
NSLog(<span style="color:#e6db74">@"RPC error: %@"</span>, error);
|
|
}
|
|
}];</code></pre></div>
|
|
<p>The <code>GRXWriter</code> protocol is generic enough to allow for asynchronous streams, streams of future values, or even infinite streams.</p>
|
|
|
|
<p>Finally, let’s look at our bidirectional streaming RPC <code>RouteChat()</code>. The way to
|
|
call a bidirectional streaming RPC is just a combination of how to call
|
|
request-streaming RPCs and response-streaming RPCs.</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-objective-c" data-lang="objective-c">[service routeChatWithRequestsWriter:notesWriter handler:<span style="color:#f92672">^</span>(<span style="color:#66d9ef">BOOL</span> done, RTGRouteNote <span style="color:#f92672">*</span>note, NSError <span style="color:#f92672">*</span>error) {
|
|
<span style="color:#66d9ef">if</span> (note) {
|
|
NSLog(<span style="color:#e6db74">@"Got message %@ at %@"</span>, note.message, note.location);
|
|
} <span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> (error) {
|
|
NSLog(<span style="color:#e6db74">@"RPC error: %@"</span>, error);
|
|
}
|
|
<span style="color:#66d9ef">if</span> (done) {
|
|
NSLog(<span style="color:#e6db74">@"Chat ended."</span>);
|
|
}
|
|
}];</code></pre></div>
|
|
<p>The semantics for the handler block and the <code>GRXWriter</code> 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.</p>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
|
|
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
|
|
|
|
</body>
|
|
</html>
|