{"id":2075,"date":"2015-12-16T01:04:39","date_gmt":"2015-12-16T01:04:39","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=2075"},"modified":"2024-09-12T01:44:14","modified_gmt":"2024-09-12T08:44:14","slug":"display-sync-progress-indicator-ios","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/","title":{"rendered":"Displaying a Sync Progress Indicator in an iOS app"},"content":{"rendered":"<p><code>NSProgress<\/code>\u00a0is an object in Foundation that represents the completion of some work. That work could be downloading a file, installing an app or something your own application is doing.<\/p>\n<p>The <code>NSProgress<\/code> exists to let you easily report progress in your application across various components both for the UI and the system. With Couchbase Mobile, data is exchanged by initiating replications and with those come change events that can inform you of the progress.<\/p>\n<p>In this tutorial, you&#8217;ll import data from the Google Places API to Sync Gateway and replicate them to an iOS app.<\/p>\n<p>&gt; <a href=\"https:\/\/developers.google.com\/places\/\" data-cke-saved-href=\"https:\/\/developers.google.com\/places\/\">https:\/\/developers.google.com\/places\/<\/a><\/p>\n<p>Along the way, you&#8217;ll learn how to:<\/p>\n<ul>\n<li>Use the Sync Gateway Admin REST API to import data from an external source.<\/li>\n<li>Setup a pull replication with the iOS SDK.<\/li>\n<li>Use replication change notifications to display a progress bar in the UI.<\/li>\n<\/ul>\n<p>Let&#8217;s get started!<\/p>\n<h2>Getting Started<\/h2>\n<p>To use the Google Places API in this tutorial, you will first create a new project in the Google Developer Console and then generate a Server API Key.<\/p>\n<p>Open the Google Developer Console and log into your account:<\/p>\n<p>&gt;\u00a0<a href=\"https:\/\/console.developers.google.com\/\" data-cke-saved-href=\"https:\/\/console.developers.google.com\">https:\/\/console.developers.google.com<\/a><\/p>\n<p>Create a new Project called <strong>City Explorer<\/strong>:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-10371\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2015\/12\/create_app.gif\" alt=\"\" width=\"596\" height=\"540\" \/><br \/>\nOnce the new project appears in the list, click on it and navigate to <strong>APIs &amp; auth &gt; APIs<\/strong>\u00a0in the left navigation drawer. Enable the <strong>Google Places API Web Service<\/strong>.<\/p>\n<p>Once enabled, go to the <strong>Credentials<\/strong>\u00a0tab in the left navigation drawer, create a new Key (Server key) and copy down the API key as you will need it throughout this tutorial.<\/p>\n<p>In the next section, you will use a couple libraries and the Admin REST API to sync the Places data to Sync Gateway.<\/p>\n<h2>Sync Gateway<\/h2>\n<p>Download Sync Gateway and unzip the file:<\/p>\n<p>&gt; <a href=\"https:\/\/www.couchbase.com\/nosql-databases\/downloads#Couchbase\\_Mobile\" data-cke-saved-href=\"https:\/\/www.couchbase.com\/nosql-databases\/downloads#Couchbase\\_Mobile\">https:\/\/www.couchbase.com\/nosql-databases\/downloads#Couchbase\\_Mobile<\/a><\/p>\n<p>You can find the Sync Gateway binary in the <strong>bin<\/strong>\u00a0folder and examples of configuration files in the <strong>examples<\/strong>\u00a0folder. Copy the <strong>basic-walrus-bucket.json<\/strong>\u00a0file to the root of your project:<\/p>\n<pre class=\"whitespace-before:1 whitespace-after:1 lang:default decode:true \">$ cp \/Downloads\/couchbase-sync-gateway\/examples\/basic-walrus-bucket.json \/path\/to\/proj\/sync-gateway-config.json<\/pre>\n<p>Start Sync Gateway:<\/p>\n<div class=\"cke_widget_wrapper cke_widget_block cke_widget_selected\" tabindex=\"-1\" contenteditable=\"false\" data-cke-widget-wrapper=\"1\" data-cke-filter=\"off\" data-cke-display-name=\"code snippet\" data-cke-widget-id=\"9\">\n<pre data-cke-widget-data=\"%7B%22lang%22%3A%22bash%22%2C%22code%22%3A%22%5Cn%24%20~%2FDownloads%2Fcouchbase-sync-gateway%2Fbin%2Fsync_gateway%5Cn%5Cn%22%2C%22classes%22%3Anull%7D\" data-cke-widget-upcasted=\"1\" data-cke-widget-keep-attr=\"0\" data-widget=\"codeSnippet\" class=\"cke_widget_element\"><code class=\"language-bash hljs\">\r\n$ ~\/Downloads\/couchbase-sync-gateway\/bin\/sync_gateway\r\n<\/code><\/pre>\n<\/div>\n<p>Open the Admin Dashboard to monitor the documents that were saved to Sync Gateway.<\/p>\n<p>&gt;\u00a0<a href=\"https:\/\/localhost:4985\/_admin\/\" data-cke-saved-href=\"https:\/\/localhost:4985\/_admin\/\">https:\/\/localhost:4985\/_admin\/<\/a><\/p>\n<p>In the next section, you will write a small NodeJS app with the RxJS and Request modules to import the Places data to Sync Gateway.<\/p>\n<h2>Places API \u2192 Sync Gateway<\/h2>\n<p>Before you start scripting the app server, check that your API Key is working correctly, open the following url in your browser, you should see the JSON response.<\/p>\n<p>&gt;\u00a0https:\/\/maps.googleapis.com\/maps\/api\/place\/textsearch\/json?query=restaurants+in+London&amp;key=API_KEY<\/p>\n<p><strong>NOTE<\/strong>: Don\u2019t forget to add your API Key in the URL.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-10372\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2015\/12\/diagram-1024x501.png\" alt=\"\" width=\"900\" height=\"440\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/diagram-1024x501.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/diagram-300x147.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/diagram-768x376.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/diagram-1536x752.png 1536w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/diagram-20x10.png 20w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/diagram-1320x646.png 1320w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/diagram.png 1600w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<p>To build the app server that will import the data from the Places API to Sync Gateway, you will use <a href=\"https:\/\/github.com\/Reactive-Extensions\/RxJS\" data-cke-saved-href=\"https:\/\/github.com\/Reactive-Extensions\/RxJS\">RxJS<\/a>\u00a0and <a href=\"https:\/\/github.com\/request\/request\" data-cke-saved-href=\"https:\/\/github.com\/request\/request\">Request<\/a>. Code that deals with more than one event or asynchronous computation gets complicated quickly. RxJS makes these computations <em>first-class citizens<\/em>\u00a0and provides a model that allows for readable and composable APIs to deal with these asynchronous computations. The Request module is the de-facto library to make http requests in NodeJS simpler than ever. Go ahead and install the dependencies:<\/p>\n<div class=\"cke_widget_wrapper cke_widget_block cke_widget_selected\" tabindex=\"-1\" contenteditable=\"false\" data-cke-widget-wrapper=\"1\" data-cke-filter=\"off\" data-cke-display-name=\"code snippet\" data-cke-widget-id=\"8\">\n<pre data-cke-widget-data=\"%7B%22lang%22%3A%22bash%22%2C%22code%22%3A%22%5Cn%24%20npm%20install%20request%20rx%20--save%5Cn%5Cn%22%2C%22classes%22%3Anull%7D\" data-cke-widget-upcasted=\"1\" data-cke-widget-keep-attr=\"0\" data-widget=\"codeSnippet\" class=\"cke_widget_element\"><code class=\"language-bash hljs\">\r\n$ npm install request rx --save\r\n<\/code><\/pre>\n<\/div>\n<p>Copy <strong>requestRx.js<\/strong>\u00a0from the <a href=\"https:\/\/github.com\/couchbaselabs\/Couchbase-by-Example\/blob\/master\/04-ios-sync-progress-indicator\/requestRx.js\" data-cke-saved-href=\"https:\/\/github.com\/couchbaselabs\/Couchbase-by-Example\/blob\/master\/04-ios-sync-progress-indicator\/requestRx.js\">GitHub repo<\/a>\u00a0to your project folder. We\u2019re simply wrapping the Request api in RxJS constructs (flatMap, filter, subscribe&#8230;). For example, instead of using `request.get`, you will use `requestRx.get`.<\/p>\n<p>Create a new file called <strong>sync.js<\/strong>, require the <code>requestRx<\/code> and <code>Rx<\/code> modules. Define a couple constants:<\/p>\n<div class=\"cke_widget_wrapper cke_widget_block cke_widget_selected\" tabindex=\"-1\" contenteditable=\"false\" data-cke-widget-wrapper=\"1\" data-cke-filter=\"off\" data-cke-display-name=\"code snippet\" data-cke-widget-id=\"7\">\n<pre data-cke-widget-data=\"%7B%22lang%22%3A%22javascript%22%2C%22code%22%3A%22%5Cn%20%20%20%20const%20api_key%20%3D%20'AIzaSyBGRQzQ2Sy1zgIrMrbYUknd1L25idYOoII'%3B%5Cn%20%20%20%20const%20url%20%3D%20'https%3A%2F%2Fmaps.googleapis.com%2Fmaps%2Fapi%2Fplace'%3B%5Cn%20%20%20%20const%20gateway%20%3D%20'http%3A%2F%2Flocalhost%3A4985%2Fdb'%3B%5Cn%5Cn%22%2C%22classes%22%3Anull%7D\" data-cke-widget-upcasted=\"1\" data-cke-widget-keep-attr=\"0\" data-widget=\"codeSnippet\" class=\"cke_widget_element\"><code class=\"language-javascript hljs\">\r\n    const api_key = 'AIzaSyBGRQzQ2Sy1zgIrMrbYUknd1L25idYOoII';\r\n    const url = 'https:\/\/maps.googleapis.com\/maps\/api\/place';\r\n    const gateway = 'https:\/\/localhost:4985\/db';\r\n<\/code><\/pre>\n<\/div>\n<p><strong>NOTE<\/strong>: You will use the JavaScript ES 6 syntax (more specifically string interpolation and arrow functions) which will make your program shorter and more readable.<\/p>\n<p>Next, use the <code>requestRx<\/code> method to follow the chain of requests describe in the diagram.<\/p>\n<p>If you are wondering how to use Reactive Extensions, I strongly encourage you to follow <a href=\"https:\/\/reactive-extensions.github.io\/learnrx\/\" data-cke-saved-href=\"https:\/\/reactive-extensions.github.io\/learnrx\/\">this tutorial<\/a>. It will take a couple hours to complete but you will come out of it with a very clear understanding of Reactive Extensions.<\/p>\n<p>This might be a lot to take in but the best think to do is experiment with the different operators (flatMap, zip, subscribe, fromArray):<\/p>\n<pre class=\"whitespace-after:1 lang:default decode:true \">\/\/ 1. Search for Places\r\nrequestRx.get(`${url}\/textsearch\/json?key=${api_key}&amp;query=restaurants+in+london`)\r\n  .subscribe((res) =&gt; {\r\n      var places = JSON.parse(res.body).results;\r\n      var placesStream = Rx.Observable.fromArray(places);\r\n      \/\/ 2. Send the Places in bulk to Sync Gateway\r\n      requestRx({uri: `${gateway}\/_bulk_docs`, method: 'POST', json: {docs: places}})\r\n        .flatMap((docsRes) =&gt; {\r\n            var docsStream = Rx.Observable.fromArray(docsRes.body);\r\n            \/\/ Merge the place's photoreference with the doc id and rev\r\n            return Rx.Observable.zip(placesStream, docsStream, (place, doc) =&gt; {\r\n                return {\r\n                    id: doc.id,\r\n                    rev: doc.rev,\r\n                    ref: place.photos[0].photo_reference\r\n                }\r\n            });\r\n        })\r\n        .flatMap((doc) =&gt; {\r\n            \/\/ 3. Get the binary jpg photo using the ref property (i.e. photoreference)\r\n            var options = {\r\n                uri: `${url}\/photo?key=${api_key}&amp;maxwidth=400&amp;photoreference=${doc.ref}`,\r\n                encoding: null\r\n            };\r\n            return requestRx.get(options)\r\n              .flatMap((photo) =&gt; {\r\n                  \/\/ 4. Save the photo as an attachment on the corresponding document\r\n                  return requestRx({\r\n                      uri: `${gateway}\/${doc.id}\/photo?rev=${doc.rev}`,\r\n                      method: 'PUT',\r\n                      headers: {'Content-Type': 'image\/jpg'},\r\n                      body: photo.body\r\n                  })\r\n              })\r\n        })\r\n        .subscribe((res) =&gt; {\r\n        });\r\n  });<\/pre>\n<ol>\n<li>Get the Places that match the query <code>restaurants in London<\/code>. Use the ES 6 string interpolation feature in the url.<\/li>\n<li>The <code>_bulk_docs<\/code> endpoint is very convenient for importing large datasets to a Sync Gateway instance. Read more about it in the <a href=\"https:\/\/developer.couchbase.com\/mobile\/develop\/references\/sync-gateway\/rest-api\/database\/post-bulk-docs\/index.html\" data-cke-saved-href=\"https:\/\/developer.couchbase.com\/mobile\/develop\/references\/sync-gateway\/rest-api\/database\/post-bulk-docs\/index.html\">docs<\/a>.<\/li>\n<li>After saving the document, you save the photo as an attachment, you must first get the image from the Places API. Notice the <code>encoding<\/code> property is set to `null`. This is required by the Request module for any response body that isn\u2019t a string. Read more about it in the <a href=\"https:\/\/github.com\/request\/request#user-content-requestoptions-callback\" data-cke-saved-href=\"https:\/\/github.com\/request\/request#user-content-requestoptions-callback\">Request docs<\/a>.<\/li>\n<li>You must tell Sync Gateway which document (by specifying the document id) and revision of that document (by specifying the revision number) to save this attachment on.<\/li>\n<\/ol>\n<p>To run your NodeJS app written with the JavaScript ES 6 syntax, you can use <a href=\"https:\/\/babeljs.io\/\" data-cke-saved-href=\"https:\/\/babeljs.io\/\">Babel<\/a>. Install it and run it with the <strong>sync.js<\/strong>\u00a0file:<\/p>\n<div class=\"cke_widget_wrapper cke_widget_block cke_widget_selected\" tabindex=\"-1\" contenteditable=\"false\" data-cke-widget-wrapper=\"1\" data-cke-filter=\"off\" data-cke-display-name=\"code snippet\" data-cke-widget-id=\"5\">\n<pre data-cke-widget-data=\"%7B%22lang%22%3A%22bash%22%2C%22code%22%3A%22%5Cn%20%20%20%20%24%20npm%20install%20babel%20-g%5Cn%20%20%20%20%24%20babel-node%20sync.js%5Cn%5Cn%22%2C%22classes%22%3Anull%7D\" data-cke-widget-upcasted=\"1\" data-cke-widget-keep-attr=\"0\" data-widget=\"codeSnippet\" class=\"cke_widget_element\"><code class=\"language-bash hljs\">\r\n    $ npm install babel -g\r\n    $ babel-node sync.js\r\n\r\n<\/code><\/pre>\n<\/div>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-10373\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2015\/12\/sync_docs.gif\" alt=\"\" width=\"960\" height=\"528\" \/><\/p>\n<p>Now that you have documents including images stored in the in-memory bucket of Sync Gateway, you will start coding the iOS app to include a progress bar managed by the replication change notification.<\/p>\n<h2>iOS application<\/h2>\n<p>In Xcode, create a new <strong>Single View Application<\/strong>\u00a0called <strong>CityExplorer<\/strong>:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-10374\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2015\/12\/new_project-1024x641.png\" alt=\"\" width=\"900\" height=\"563\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/new_project-1024x641.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/new_project-300x188.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/new_project-768x481.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/new_project-1536x962.png 1536w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/new_project-20x13.png 20w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/new_project-1320x827.png 1320w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/new_project.png 1600w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<p>Close the project and install the Couchbase Lite iOS SDK via Cocoapods:<\/p>\n<div class=\"cke_widget_wrapper cke_widget_block cke_widget_selected\" tabindex=\"-1\" contenteditable=\"false\" data-cke-widget-wrapper=\"1\" data-cke-filter=\"off\" data-cke-display-name=\"code snippet\" data-cke-widget-id=\"4\">\n<pre data-cke-widget-data=\"%7B%22lang%22%3A%22bash%22%2C%22code%22%3A%22%5Cn%20%20%20%20%24%20pod%20init%5Cn%20%20%20%20%24%20pod%20search%20couchbase%5Cn%5Cn%22%2C%22classes%22%3Anull%7D\" data-cke-widget-upcasted=\"1\" data-cke-widget-keep-attr=\"0\" data-widget=\"codeSnippet\" class=\"cke_widget_element\"><code class=\"language-bash hljs\">\r\n    $ pod init\r\n    $ pod search couchbase\r\n\r\n<\/code><\/pre>\n<\/div>\n<p>Add the dependency to the <strong>Podfile<\/strong>\u00a0in the root of the project, then run install:<\/p>\n<div class=\"cke_widget_wrapper cke_widget_block cke_widget_selected\" tabindex=\"-1\" contenteditable=\"false\" data-cke-widget-wrapper=\"1\" data-cke-filter=\"off\" data-cke-display-name=\"code snippet\" data-cke-widget-id=\"3\">\n<pre data-cke-widget-data=\"%7B%22lang%22%3A%22bash%22%2C%22code%22%3A%22%5Cn%20%20%20%20%24%20pod%20install%5Cn%5Cn%22%2C%22classes%22%3Anull%7D\" data-cke-widget-upcasted=\"1\" data-cke-widget-keep-attr=\"0\" data-widget=\"codeSnippet\" class=\"cke_widget_element\"><code class=\"language-bash hljs\">\r\n    $ pod install\r\n\r\n<\/code><\/pre>\n<\/div>\n<p>Open <strong>CityExplorer.workspace<\/strong>\u00a0this time and create a bridging header:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-10375\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2015\/12\/bridging_header.gif\" alt=\"\" width=\"616\" height=\"540\" \/><\/p>\n<p>Navigate to build settings to add the bridging header:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-10376\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2015\/12\/build_settings.gif\" alt=\"\" width=\"616\" height=\"540\" \/><\/p>\n<p>Open <code>ViewController.swift<\/code> and add a property <code>pull<\/code> of type <code>CBLReplication?<\/code>. In the <code>viewDidLoad<\/code> method, add the following:<\/p>\n<div class=\"cke_widget_wrapper cke_widget_block cke_widget_selected\" tabindex=\"-1\" contenteditable=\"false\" data-cke-widget-wrapper=\"1\" data-cke-filter=\"off\" data-cke-display-name=\"code snippet\" data-cke-widget-id=\"2\">\n<pre data-cke-widget-data=\"%7B%22code%22%3A%22%5Cn%20%20%20%20%2F%2F%201%5Cn%20%20%20%20let%20manager%20%3D%20CBLManager.sharedInstance()%5Cn%20%20%20%20%2F%2F%202%5Cn%20%20%20%20let%20databaseExists%20%3D%20manager.databaseExistsNamed(%5C%22cityexplorer%5C%22)%5Cn%20%20%20%20var%20database%20%3D%20manager.databaseNamed(%5C%22cityexplorer%5C%22%2C%20error%3A%20nil)%5Cn%20%20%20%20if%20databaseExists%20%7B%5Cn%20%20%20%20%20%20%20%20database%3F.deleteDatabase(nil)%5Cn%20%20%20%20%20%20%20%20database%20%3D%20manager.databaseNamed(%5C%22cityexplorer%5C%22%2C%20error%3A%20nil)%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20let%20gateway%20%3D%20NSURL(string%3A%20%5C%22http%3A%2F%2Flocalhost%3A4984%2Fdb%5C%22)!%5Cn%20%20%20%20%5Cn%20%20%20%20%2F%2F%203%5Cn%20%20%20%20pull%20%3D%20database%3F.createPullReplication(gateway)%5Cn%20%20%20%20%5Cn%20%20%20%20let%20nctr%20%3D%20NSNotificationCenter.defaultCenter()%5Cn%20%20%20%20nctr.addObserver(self%2C%20selector%3A%20%5C%22replicationProgress%3A%5C%22%2C%20name%3A%20kCBLReplicationChangeNotification%2C%20object%3A%20pull)%5Cn%20%20%20%20%5Cn%20%20%20%20%2F%2F%204%5Cn%20%20%20%20pull%3F.start()%5Cn%5Cn%22%2C%22classes%22%3Anull%7D\" data-cke-widget-upcasted=\"1\" data-cke-widget-keep-attr=\"0\" data-widget=\"codeSnippet\" class=\"cke_widget_element\"><code class=\"hljs\">\r\n    \/\/ 1\r\n    let manager = CBLManager.sharedInstance()\r\n    \/\/ 2\r\n    let databaseExists = manager.databaseExistsNamed(\"cityexplorer\")\r\n    var database = manager.databaseNamed(\"cityexplorer\", error: nil)\r\n    if databaseExists {\r\n        database?.deleteDatabase(nil)\r\n        database = manager.databaseNamed(\"cityexplorer\", error: nil)\r\n    }\r\n    \r\n    let gateway = NSURL(string: \"https:\/\/localhost:4984\/db\")!\r\n    \r\n    \/\/ 3\r\n    pull = database?.createPullReplication(gateway)\r\n    \r\n    let nctr = NSNotificationCenter.defaultCenter()\r\n    nctr.addObserver(self, selector: \"replicationProgress:\", name: kCBLReplicationChangeNotification, object: pull)\r\n    \r\n    \/\/ 4\r\n    pull?.start()\r\n\r\n<\/code><\/pre>\n<\/div>\n<p>A couple of things are happening above:<\/p>\n<ol>\n<li>You get the shared instance of the manager.<\/li>\n<li>With the manager instance, you delete the content of the database. This will ensure that the replication starts from scratch every time you run the app.<\/li>\n<li>You instantiate a pull replication and register as an oberserver on the notification named <code>kCBLReplicationChangeNotification<\/code>.<\/li>\n<li>You start the replication.<\/li>\n<\/ol>\n<p>And add the <code>replicationProgress<\/code> method to simply log the changesCount and completedChangesCount properties:<\/p>\n<div class=\"cke_widget_wrapper cke_widget_block cke_widget_selected\" tabindex=\"-1\" contenteditable=\"false\" data-cke-widget-wrapper=\"1\" data-cke-filter=\"off\" data-cke-display-name=\"code snippet\" data-cke-widget-id=\"1\">\n<pre data-cke-widget-data=\"%7B%22code%22%3A%22%5Cn%20%20%20%20func%20replicationProgress(notification%3A%20NSNotification)%20%7B%5Cn%20%20%20%20%20%20%20%20println(%5C%22Changes%20count%20%5C%5C(pull%3F.changesCount)%5C%22)%5Cn%20%20%20%20%20%20%20%20println(%5C%22Completed%20%5C%5C(pull%3F.completedChangesCount)%5C%22)%5Cn%20%20%20%20%7D%5Cn%5Cn%22%2C%22classes%22%3Anull%7D\" data-cke-widget-upcasted=\"1\" data-cke-widget-keep-attr=\"0\" data-widget=\"codeSnippet\" class=\"cke_widget_element\"><code class=\"hljs\">\r\n    func replicationProgress(notification: NSNotification) {\r\n        println(\"Changes count \\(pull?.changesCount)\")\r\n        println(\"Completed \\(pull?.completedChangesCount)\")\r\n    }\r\n\r\n<\/code><\/pre>\n<\/div>\n<p>In the next section, you will add a progress view in the Storyboard, then will connect it to the View Controller.<\/p>\n<h2>Progress Bar<\/h2>\n<p>In the Storyboard, add a Progress View in the centre of the View:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-10377\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2015\/12\/storyboard-1024x893.png\" alt=\"\" width=\"900\" height=\"785\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/storyboard-1024x893.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/storyboard-300x262.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/storyboard-768x669.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/storyboard-20x17.png 20w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/storyboard.png 1200w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<p>Connect the UI handle to the controller property:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-10378\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2015\/12\/storyboard_connect-1024x640.png\" alt=\"\" width=\"900\" height=\"563\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/storyboard_connect-1024x640.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/storyboard_connect-300x188.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/storyboard_connect-768x480.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/storyboard_connect-1536x960.png 1536w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/storyboard_connect-20x13.png 20w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/storyboard_connect-1320x825.png 1320w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2015\/12\/storyboard_connect.png 1600w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<p>In the <code>replicationProgress<\/code> method, update the progressView&#8217;s <code>progress<\/code> property accordingly:<\/p>\n<pre class=\"whitespace-before:01 whitespace-after:1 lang:default decode:true\">let active = pull?.status == .Active\r\nlet completed = pull?.status == .Stopped\r\n\r\nprintln(\"Status : \\(pull?.status.rawValue)\")\r\nprintln(\"Changes Count: \\(pull?.changesCount)\")\r\nprintln(\"Completed Count: \\(pull?.completedChangesCount)\")\r\nprintln(\"======\")\r\n\r\nif pull!.changesCount &gt; 0 {\r\n    let number = Float(pull!.completedChangesCount) \/ Float(pull!.changesCount)\r\n    self.progressView.progress = number\r\n}<\/pre>\n<p>Run the app and you should see the progress bar updating as the documents are replicated:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-10379\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2015\/12\/final_demo.gif\" alt=\"\" width=\"876\" height=\"540\" \/><\/p>\n<p>You can run the <strong>sync.js<\/strong>\u00a0script a couple times to have more documents to pull. The Places API returns a maximum of 20 results in one response.<\/p>\n<h2>Conclusion<\/h2>\n<p>In this tutorial, you learned how to set up a project to use the Google Places API and a NodeJS program to import data as documents and attachments in Sync Gateway. You also used the <code>NSNotification<\/code> api on iOS to register for the <code>kCBLReplicationChangeNotification<\/code> notification and update the progress view in your iOS application.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>NSProgress\u00a0is an object in Foundation that represents the completion of some work. That work could be downloading a file, installing an app or something your own application is doing. The NSProgress exists to let you easily report progress in your [&hellip;]<\/p>\n","protected":false},"author":51,"featured_media":13873,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1810],"tags":[],"ppma_author":[9028],"class_list":["post-2075","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-couchbase-mobile"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.7.1 (Yoast SEO v25.7) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Displaying a Sync Progress Indicator in an iOS app - The Couchbase Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Displaying a Sync Progress Indicator in an iOS app\" \/>\n<meta property=\"og:description\" content=\"NSProgress\u00a0is an object in Foundation that represents the completion of some work. That work could be downloading a file, installing an app or something your own application is doing. The NSProgress exists to let you easily report progress in your [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2015-12-16T01:04:39+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-09-12T08:44:14+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2015\/12\/create_app.gif\" \/>\n<meta name=\"author\" content=\"James Nocentini, Technical Writer, Mobile, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"James Nocentini, Technical Writer, Mobile, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/\"},\"author\":{\"name\":\"James Nocentini, Technical Writer, Mobile, Couchbase\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/ec4dfbd349cb4a321fb6a92b71a9a7f6\"},\"headline\":\"Displaying a Sync Progress Indicator in an iOS app\",\"datePublished\":\"2015-12-16T01:04:39+00:00\",\"dateModified\":\"2024-09-12T08:44:14+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/\"},\"wordCount\":1151,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"articleSection\":[\"Couchbase Mobile\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/\",\"name\":\"Displaying a Sync Progress Indicator in an iOS app - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2015-12-16T01:04:39+00:00\",\"dateModified\":\"2024-09-12T08:44:14+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"width\":1800,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Displaying a Sync Progress Indicator in an iOS app\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/ec4dfbd349cb4a321fb6a92b71a9a7f6\",\"name\":\"James Nocentini, Technical Writer, Mobile, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/09977bdd14473dc23a125f2f74c3e816\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/0aa80108e5c81e282d705199edae5a25f8ef92abf15cd64f8ff19837abcee09a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/0aa80108e5c81e282d705199edae5a25f8ef92abf15cd64f8ff19837abcee09a?s=96&d=mm&r=g\",\"caption\":\"James Nocentini, Technical Writer, Mobile, Couchbase\"},\"description\":\"James Nocentini is the Technical Writer in charge of the documentation for Couchbase Mobile. Previously, he worked as a Developer Advocate and before that as a front-end developer for HouseTrip. He also enjoys writing Android tutorials for raywenderlich.com in his spare time.\",\"url\":\"https:\/\/www.couchbase.com\/blog\/author\/james-nocentini\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Displaying a Sync Progress Indicator in an iOS app - The Couchbase Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/","og_locale":"en_US","og_type":"article","og_title":"Displaying a Sync Progress Indicator in an iOS app","og_description":"NSProgress\u00a0is an object in Foundation that represents the completion of some work. That work could be downloading a file, installing an app or something your own application is doing. The NSProgress exists to let you easily report progress in your [&hellip;]","og_url":"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/","og_site_name":"The Couchbase Blog","article_published_time":"2015-12-16T01:04:39+00:00","article_modified_time":"2024-09-12T08:44:14+00:00","og_image":[{"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2015\/12\/create_app.gif","type":"","width":"","height":""}],"author":"James Nocentini, Technical Writer, Mobile, Couchbase","twitter_card":"summary_large_image","twitter_misc":{"Written by":"James Nocentini, Technical Writer, Mobile, Couchbase","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/"},"author":{"name":"James Nocentini, Technical Writer, Mobile, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/ec4dfbd349cb4a321fb6a92b71a9a7f6"},"headline":"Displaying a Sync Progress Indicator in an iOS app","datePublished":"2015-12-16T01:04:39+00:00","dateModified":"2024-09-12T08:44:14+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/"},"wordCount":1151,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","articleSection":["Couchbase Mobile"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/","url":"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/","name":"Displaying a Sync Progress Indicator in an iOS app - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2015-12-16T01:04:39+00:00","dateModified":"2024-09-12T08:44:14+00:00","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","width":1800,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/display-sync-progress-indicator-ios\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Displaying a Sync Progress Indicator in an iOS app"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"The Couchbase Blog","description":"Couchbase, the NoSQL Database","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/ec4dfbd349cb4a321fb6a92b71a9a7f6","name":"James Nocentini, Technical Writer, Mobile, Couchbase","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/09977bdd14473dc23a125f2f74c3e816","url":"https:\/\/secure.gravatar.com\/avatar\/0aa80108e5c81e282d705199edae5a25f8ef92abf15cd64f8ff19837abcee09a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/0aa80108e5c81e282d705199edae5a25f8ef92abf15cd64f8ff19837abcee09a?s=96&d=mm&r=g","caption":"James Nocentini, Technical Writer, Mobile, Couchbase"},"description":"James Nocentini is the Technical Writer in charge of the documentation for Couchbase Mobile. Previously, he worked as a Developer Advocate and before that as a front-end developer for HouseTrip. He also enjoys writing Android tutorials for raywenderlich.com in his spare time.","url":"https:\/\/www.couchbase.com\/blog\/author\/james-nocentini\/"}]}},"authors":[{"term_id":9028,"user_id":51,"is_guest":0,"slug":"james-nocentini","display_name":"James Nocentini, Technical Writer, Mobile, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/0aa80108e5c81e282d705199edae5a25f8ef92abf15cd64f8ff19837abcee09a?s=96&d=mm&r=g","author_category":"","last_name":"Nocentini","first_name":"James","job_title":"","user_url":"","description":"James Nocentini is the Technical Writer in charge of the documentation for Couchbase Mobile. Previously, he worked as a Developer Advocate and before that as a front-end developer for HouseTrip. He also enjoys writing Android tutorials for raywenderlich.com in his spare time."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/2075","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/users\/51"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=2075"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/2075\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=2075"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=2075"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=2075"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=2075"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}