{"id":1977,"date":"2015-10-23T08:09:45","date_gmt":"2015-10-23T08:09:44","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=1977"},"modified":"2025-06-13T20:09:56","modified_gmt":"2025-06-14T03:09:56","slug":"couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/pt\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/","title":{"rendered":"Couchbase Mobile 101: Como criar seu primeiro aplicativo [Couchbase LIVE New York]."},"content":{"rendered":"<p style=\"text-align: center\"><a href=\"https:\/\/bit.ly\/CBNYC2015\"><img decoding=\"async\" src=\"\/wp-content\/original-assets\/2015\/october\/couchbase-live-new-york-couchbase-101---how-to-build-your-first-couchbase-mobile-app\/events.cbliveny.bannerheader.lockup.png\" \/><\/a><\/p>\n<p style=\"text-align: justify\">Da sess\u00e3o 101 no <a href=\"https:\/\/bit.ly\/couchbaseNYC01\">Couchbase LIVE New York pista m\u00f3vel<\/a>No artigo \"Couchbase Lite\", falamos sobre como come\u00e7ar a integrar o Couchbase Lite aos seus projetos iOS e Android.  A partir do <a href=\"https:\/\/www.slideshare.net\/Couchbase\/couchbase-mobile-101-couchbase-live-new-york?\">Slides \"Couchbase Mobile 101: Como criar seu primeiro aplicativo m\u00f3vel\"<\/a>No primeiro dia, exploramos as APIs do Couchbase Mobile, percorrendo o aplicativo de amostra Grocery Sync, que pode ser encontrado no reposit\u00f3rio do Github para <a href=\"https:\/\/github.com\/couchbaselabs\/Grocery-Sync-iOS\">iOS<\/a> e <a href=\"https:\/\/github.com\/couchbaselabs\/GrocerySync-Android\">Android<\/a>.  Neste blog, vamos recapitular em alto n\u00edvel os recursos e as APIs do Couchbase Lite que foram apresentados na sess\u00e3o Couchbase 101, bem como alguns dos c\u00f3digos encontrados na amostra Grocery Sync.  Para come\u00e7ar, voc\u00ea deve <a href=\"https:\/\/bit.ly\/couchbase_downloads\">baixar o Couchbase Lite<\/a> Enterprise Edition para a plataforma em que voc\u00ea est\u00e1 desenvolvendo e siga o tutorial para iOS ou o tutorial para Android para integrar o Couchbase Lite aos seus projetos m\u00f3veis.<\/p>\n<p style=\"text-align: justify\">Depois de trazer o Couchbase Lite para seus projetos m\u00f3veis, precisaremos inicializar o Couchbase Lite e recuperar ou criar um banco de dados.  Abaixo est\u00e3o alguns conceitos e requisitos do Couchbase Mobile que precisamos.<\/p>\n<p style=\"text-align: justify\"><strong>[1] Gerente<\/strong><\/p>\n<p style=\"text-align: justify\">O <a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/1.1.0\/develop\/references\/couchbase-lite\/couchbase-lite\/manager\/index.html\">Gerente<\/a> \u00e9 a classe de n\u00edvel superior a ser referenciada na cria\u00e7\u00e3o de um namespace para bancos de dados.  Criar um banco de dados \u00e9 simplesmente fazer refer\u00eancia a um nome de cadeia de caracteres, como abaixo:<\/p>\n<p style=\"text-align: justify\"><strong>iOS<\/strong><\/p>\n<pre><code class=\"language-objc\">\r\n    NSError* error;\r\n    self.database = [[CBLManager sharedInstance] databaseNamed: kDatabaseName\r\n                                                         error: &amp;error];\r\n    if (!self.database) {\r\n        [self showAlert: @\"Couldn't open database\" error: error fatal: YES];\r\n        return NO;\r\n    }\r\n<\/code><\/pre>\n<p style=\"text-align: justify\"><strong>Android<\/strong><\/p>\n<pre><code class=\"language-java\">\r\nmanager = new Manager(new AndroidContext(this), Manager.DEFAULT_OPTIONS);\r\ndatabase = manager.getDatabase(DATABASE_NAME);\r\n<\/code><\/pre>\n<p style=\"text-align: justify\">Com esse c\u00f3digo em vigor, podemos recuperar os documentos que cont\u00eam JSON do banco de dados adequadamente.  O banco de dados tamb\u00e9m serve como fonte e destino para a replica\u00e7\u00e3o.   Cada um dos documentos tem seu respectivo nome e ID exclusivos.  Al\u00e9m disso, eles t\u00eam JSON como suas propriedades, sendo que o objeto JSON \u00e9 um conjunto de propriedades de nome em que seus valores podem ser nomes ou cadeias de caracteres, n\u00fameros, matrizes, dicion\u00e1rios etc.<\/p>\n<p style=\"text-align: justify\"><strong>[2] Documentos<\/strong><\/p>\n<p style=\"text-align: justify\">O <a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/1.1.0\/develop\/guides\/couchbase-lite\/native-api\/document\/index.html\">Documento<\/a> inclui um ID de documento imut\u00e1vel no banco de dados, no qual o corpo do documento assume a forma de um objeto JSON aninhado de pares de valores-chave.  Para permitir a coexist\u00eancia de diferentes tipos de documentos em um banco de dados, a conven\u00e7\u00e3o comumente usada \u00e9 incluir uma propriedade chamada \"type\" (tipo), que tem uma cadeia de caracteres que define o tipo de seus documentos.  Essa \u00e9 uma t\u00e9cnica usada para manter o controle dos diferentes tipos de documentos se houver mais de um tipo em um banco de dados e tamb\u00e9m para ajudar na indexa\u00e7\u00e3o.  Os documentos tamb\u00e9m cont\u00eam <a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/1.1.0\/develop\/guides\/couchbase-lite\/native-api\/revision\/index.html\">revis\u00f5es<\/a> para fins de rastreamento de hist\u00f3ricos de altera\u00e7\u00f5es e conflitos, portanto, \u00e9 fundamental para o funcionamento da replica\u00e7\u00e3o.<\/p>\n<p style=\"text-align: justify\">Para inserir documentos, o bot\u00e3o '<a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/1.1.0\/develop\/references\/couchbase-lite\/couchbase-lite\/database\/database\/index.html\">createDocument()<\/a>' retornar\u00e1 um ID de um documento que est\u00e1 na forma de um UUID gerado aleatoriamente.  No aplicativo de amostra para iOS, um \"NSDictionary\" \u00e9 criado para corresponder a um \"NSObject\" em Objective-C com propriedades de \"text\", \"check\" e \"created_at\" definidas.  Abaixo para ...<\/p>\n<p style=\"text-align: justify\"><strong>iOS<\/strong><\/p>\n<pre><code>\r\n    NSDictionary *document = @{@\"text\":       text,\r\n                               @\"check\":      @NO,\r\n                               @\"created_at\": [CBLJSON JSONObjectWithDate:\r\n                                                                   [NSDate date]]};\r\n    \/\/ Save the document:\r\n    CBLDocument* doc = [database createDocument];\r\n    NSError* error;\r\n    if (![doc putProperties: document error: &amp;error]) {\r\n        [self showErrorAlert: @\"Couldn't save new item\" forError: error];\r\n    }\r\n<\/code><\/pre>\n<p>criamos as propriedades do novo documento e, em seguida, salvamos o documento fazendo refer\u00eancia \u00e0 base de dados para o m\u00e9todo 'createDocument()'.  O \"JSONObjectWithDate\" \u00e9 uma fun\u00e7\u00e3o utilit\u00e1ria que pega um objeto de data do Cocao e o converte em um formato de cadeia de caracteres ISO8601, pois as datas n\u00e3o podem ser armazenadas como objetos nativos no JSON.<\/p>\n<p>Para o Android, a classe \"SimpleDateFormat\" est\u00e1 criando o \"currentTimeString\" para o objeto em que o ID do documento \u00e9 constru\u00eddo pela combina\u00e7\u00e3o do \"currentTime\" da classe \"Calendar\" e o UUID do m\u00e9todo \"randomUUID()\".  Fazendo refer\u00eancia ao \"banco de dados\" que foi criado a partir da classe Manager, um documento \u00e9 criado chamando o mesmo m\u00e9todo \"createDocument()\" do iOS.  No Android, os pares de chave-valor se assemelham a uma estrutura de objeto HashMap e, portanto, criamos um mapa que \u00e9 o equivalente em Java do objeto JSON na vari\u00e1vel \"properties\".  As mesmas tr\u00eas propriedades s\u00e3o inseridas no mapa Java pelo m\u00e9todo 'put()' e, em seguida, para persistir no disco, o objeto Map \u00e9 passado para o m\u00e9todo 'putProperties()'.  Isso \u00e9 ilustrado abaixo:<\/p>\n<p><strong>Android<\/strong><\/p>\n<pre><code>\r\n    SimpleDateFormat dateFormatter = new SimpleDateFormat(\r\n                                                   \"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'\");\r\n    UUID uuid = UUID.randomUUID();\r\n    Calendar calendar = GregorianCalendar.getInstance();\r\n    long currentTime = calendar.getTimeInMillis();\r\n    String currentTimeString = dateFormatter.format(calendar.getTime());\r\n    String id = currentTime + \"-\" + uuid.toString();\r\n\r\n    Document document = database.createDocument();\r\n    Map(String, Object) properties = new HashMap(String, Object)();\r\n    properties.put(\"_id\", id);\r\n    properties.put(\"text\", text);\r\n    properties.put(\"check\", Boolean.FALSE);\r\n    properties.put(\"created_at\", currentTimeString);\r\n\r\n    document.putProperties(properties);\r\n<\/code><\/pre>\n<p style=\"text-align: justify\"><strong>[3] Anexos<\/strong><\/p>\n<p style=\"text-align: justify\">O <a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/current\/develop\/guides\/couchbase-lite\/native-api\/attachment\/index.html\">Anexo<\/a> O recurso JSON, embora n\u00e3o seja usado na amostra, permite que os documentos anexem qualquer blob bin\u00e1rio de tamanho arbitr\u00e1rio e, portanto, \u00e9 uma t\u00e9cnica de otimiza\u00e7\u00e3o para replica\u00e7\u00e3o em que as atualiza\u00e7\u00f5es de documentos s\u00e3o independentes das atualiza\u00e7\u00f5es de anexos, pois s\u00e3o armazenadas separadamente do corpo JSON.  Por exemplo, esse pode ser um caso de uso para quando os metadados, o JSON do documento, s\u00e3o alterados em um anexo associado e, portanto, se um documento for atualizado sem altera\u00e7\u00f5es em um anexo, o replicador poder\u00e1 ignorar o envio do anexo.<\/p>\n<p style=\"text-align: justify\"><strong>[4] Visualiza\u00e7\u00f5es<\/strong><\/p>\n<p style=\"text-align: justify\">O <a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/1.1.0\/develop\/guides\/couchbase-lite\/native-api\/view\/index.html\">Ver<\/a> permite que os aplicativos criem e mantenham \u00edndices secund\u00e1rios usando a t\u00e9cnica map &amp; reduce.  Come\u00e7amos com um documento JSON e a fun\u00e7\u00e3o de mapa \u00e9 a fun\u00e7\u00e3o que voc\u00ea escreve que recebe esse documento como entrada e gera um conjunto de pares de valores-chave.  A sa\u00edda dessa fun\u00e7\u00e3o de mapa que \u00e9 executada em todos os documentos do banco de dados gera um \u00edndice.  No aplicativo de amostra Grocery Sync, estamos definindo uma visualiza\u00e7\u00e3o com uma fun\u00e7\u00e3o de mapa que indexa os itens de tarefas por data de cria\u00e7\u00e3o.  Criando uma visualiza\u00e7\u00e3o para...<\/p>\n<p style=\"text-align: justify\"><strong>iOS<\/strong><\/p>\n<pre><code class=\"language-objective-c\">\r\n[[theDatabase viewNamed: @\"byDate\"] setMapBlock: MAPBLOCK({\r\n        id date = doc[@\"created_at\"];\r\n        if (date)\r\n            emit(date, nil);\r\n    }) version: @\"1.1\"];\r\n<\/code><\/pre>\n<p>Para o iOS, primeiro estamos criando uma \"visualiza\u00e7\u00e3o\" no banco de dados.  O banco de dados tamb\u00e9m \u00e9 um cont\u00eainer ou namespace para as 'visualiza\u00e7\u00f5es', portanto, dizemos 'viewNamed: @\"byDate\"' onde, se a visualiza\u00e7\u00e3o ainda n\u00e3o existir, n\u00f3s a criaremos e, se existir, n\u00f3s a retornaremos.  O restante do bloco de c\u00f3digo \u00e9 para definir seu bloco de mapas.  Portanto, essa \u00e9 uma visualiza\u00e7\u00e3o MapReduce, o que significa que ela tem uma fun\u00e7\u00e3o de mapa.  Obtemos a data do documento observando a propriedade \"created_at\".  E se o documento tiver uma, n\u00f3s a emitimos como a chave. No aplicativo Grocery Sync, ele n\u00e3o est\u00e1 emitindo nada para o valor porque, na verdade, est\u00e1 voltando para pegar o pr\u00f3prio documento para obter o restante dos dados.  A cadeia de caracteres de vers\u00e3o, '@\"1.1\u2033' no final, \u00e9 usada para se comunicar com o banco de dados sobre se a fun\u00e7\u00e3o de mapa foi alterada ou n\u00e3o.  Como o banco de dados n\u00e3o sabe dizer quando a fun\u00e7\u00e3o de mapa foi alterada de uma execu\u00e7\u00e3o para outra, uma t\u00e9cnica \u00e9 aumentar a string de vers\u00e3o para dizer ao banco de dados que jogue fora o \u00edndice atual e o reconstrua.<\/p>\n<p style=\"text-align: justify\"><strong>Android<\/strong><\/p>\n<pre><code class=\"language-objc\">\r\n    com.couchbase.lite.View viewItemsByDate = \r\n            database.getView(String.format(\"%s\/%s\", designDocName, byDateViewName));\r\n    viewItemsByDate.setMap(new Mapper() {\r\n        @Override\r\n        public void map(Map(String, Object) document, Emitter emitter) {\r\n            Object createdAt = document.get(\"created_at\");\r\n            if (createdAt != null) {\r\n                emitter.emit(createdAt.toString(), null);\r\n            }\r\n        }\r\n    }, \"1.0\");\r\n\r\n<\/code><\/pre>\n<p>Essa \u00e9 a vers\u00e3o Java-Android em que, de forma semelhante ao iOS, chamamos 'database.getView()' e, em seguida, criamos a 'fun\u00e7\u00e3o map' usando alguma sintaxe de classe interna que, em Java, existe como um objeto 'Mapper()'.  Os \u00edndices podem ser atualizados sob demanda e informa\u00e7\u00f5es \u00fateis podem ser extra\u00eddas do documento que voc\u00ea deseja indexar, onde o valor-chave pode ser emitido.  Toda vez que algo muda, a fun\u00e7\u00e3o map \u00e9 alimentada com esse documento. A fun\u00e7\u00e3o map chama uma fun\u00e7\u00e3o chamada 'emit()' que recebe a 'chave e o valor' como par\u00e2metros.<\/p>\n<p>O que o aplicativo Grocery Sync est\u00e1 fazendo aqui \u00e9 gerar o \u00edndice de todos os itens de tarefas que s\u00e3o abreviados por \"chave\" e, como a chave \u00e9 o carimbo de data\/hora, os itens ser\u00e3o ordenados cronologicamente, onde as cadeias de valores s\u00e3o os nomes dos itens de tarefas.  O \u00edndice tamb\u00e9m lembra o ID do documento que emitiu esse par chave-valor.  Assim, quando voc\u00ea estiver consultando e tiver uma linha na consulta, poder\u00e1 us\u00e1-la para voltar ao documento e buscar essa linha inteira no banco de dados, se desejar.  A ideia aqui \u00e9 que, uma vez que voc\u00ea tenha esse \u00edndice, voc\u00ea o consulte. A mentalidade de consulta \u00e9 feita dizendo: \"Quero todas as entradas de \u00edndice com uma chave espec\u00edfica, um conjunto de chaves ou um intervalo de chaves\".<\/p>\n<p style=\"text-align: justify\"><strong>[5] Consultas<\/strong><\/p>\n<p style=\"text-align: justify\">As consultas podem, ent\u00e3o, procurar um intervalo de linhas em uma visualiza\u00e7\u00e3o e usar as chaves e os valores das linhas diretamente ou obter os documentos de onde vieram a partir do ID do documento.  No c\u00f3digo abaixo, estamos conduzindo a tabela a partir de uma consulta de visualiza\u00e7\u00e3o, criando uma consulta classificada por data decrescente em que os itens mais recentes s\u00e3o exibidos primeiro.<\/p>\n<p style=\"text-align: justify\"><strong>iOS<\/strong><\/p>\n<pre><code class=\"language-objc\">\r\n    CBLLiveQuery* query = [[[database viewNamed:@\"byDate\"] query] asLiveQuery];\r\n    query.descending = YES;\r\n\r\n    \/\/ Plug the query into the CBLUITableSource, which uses it to drive the table.\r\n    \/\/ (The CBLUITableSource uses KVO to observe the query's .rows property.)\r\n    self.dataSource.query = query;\r\n    self.dataSource.labelProperty = @\"text\";\r\n<\/code><\/pre>\n<p>Com os itens no \u00edndice, queremos usar esse \u00edndice para conduzir a exibi\u00e7\u00e3o de tabela, que \u00e9 a principal interface do usu\u00e1rio do Grocery Sync.  No iOS, geramos uma consulta que \u00e9 'viewNamed: @\"byDate\"' e chamamos a consulta que cria uma consulta sobre ela.  Em seguida, vemos \"LiveQuery\", que \u00e9 um subconjunto especial de consulta que realmente rastrear\u00e1 a visualiza\u00e7\u00e3o ao longo do tempo.  Definimos a propriedade \"descending\" (descendente) na consulta como \"yes\" (sim), pois queremos obter as linhas em ordem descendente das datas para que os itens criados mais recentemente fiquem no topo.  Por fim, com o c\u00f3digo espec\u00edfico do iOS, estamos informando ao 'dataSource' sobre a consulta e indicando qual propriedade deve ser exibida como r\u00f3tulo na exibi\u00e7\u00e3o de tabela.<\/p>\n<p style=\"text-align: justify\"><strong>Android<\/strong><\/p>\n<pre><code>\r\n    liveQuery = view.createQuery().toLiveQuery();\r\n\r\n    liveQuery.addChangeListener(new LiveQuery.ChangeListener() {\r\n        public void changed(final LiveQuery.ChangeEvent event) {\r\n            runOnUiThread(new Runnable() {\r\n                public void run() {\r\n                    grocerySyncArrayAdapter.clear();\r\n                    for (Iterator(QueryRow) it = event.getRows(); it.hasNext();) {\r\n                        grocerySyncArrayAdapter.add(it.next());\r\n                    }\r\n                    grocerySyncArrayAdapter.notifyDataSetChanged();\r\n<\/code><\/pre>\n<p style=\"text-align: justify\">Da mesma forma, a vers\u00e3o Java-Android \u00e9 iniciada da mesma forma, com a cria\u00e7\u00e3o de uma consulta por meio da chamada da visualiza\u00e7\u00e3o \"toLiveQuery()\" para gerar a \"liveQuery\".  E, em seguida, \"addChangeListener()\" \u00e9 executado nessa liveQuery, seguido pelo m\u00e9todo \"changed()\" sendo chamado para as atualiza\u00e7\u00f5es da consulta, que \u00e9 sempre que o resultado dessa consulta \u00e9 alterado.  E a sa\u00edda para quando voc\u00ea executa a consulta \u00e9 uma matriz de \"QueryRows\", em que cada QueryRow \u00e9 um objeto e tem propriedades como Key e Value e DocumentID, mas tamb\u00e9m uma propriedade de documento que carregar\u00e1 o documento de volta do banco de dados.  Ele est\u00e1 passando por um \"Iterator()\" para obter todas as linhas da consulta e adicion\u00e1-las ao \"grocerySyncArrayAdapter\", que \u00e9 uma classe personalizada que ele tem para armazenar o conjunto de dados.<br \/>\n<strong>[6] LiveQuery<\/strong><\/p>\n<p style=\"text-align: justify\">Podemos pensar no LiveQuery como um inv\u00f3lucro em torno da consulta que escuta as notifica\u00e7\u00f5es de altera\u00e7\u00e3o do banco de dados.  Assim, quando o banco de dados for alterado, o LiveQuery iniciar\u00e1 a consulta novamente, executando-a em segundo plano de forma ass\u00edncrona.  E, em seguida, compara os resultados da consulta com os resultados anteriores que j\u00e1 tinha.  Se os resultados tiverem sido alterados, o LiveQuery sinalizar\u00e1 seus pr\u00f3prios eventos de notifica\u00e7\u00e3o, que o aplicativo poder\u00e1 tratar adequadamente, como redesenhar a interface do usu\u00e1rio com base nessa nova consulta.  Abaixo, o c\u00f3digo ilustra como exibir as c\u00e9lulas da tabela para...<\/p>\n<p style=\"text-align: justify\"><strong>iOS<\/strong><\/p>\n<pre><code>\r\n- (void)couchTableSource:(CBLUITableSource*)source\r\n              willUseCell:(UITableViewCell*)cell\r\n                   forRow:(CBLQueryRow*)row\r\n{\r\n    \/\/ Set the cell background and font:\r\n    \u2026\u2026\u2026\r\n    \r\n    \/\/ Configure the cell contents. Map function (above) copies the doc properties\r\n    \/\/ into its value, so we can read them without having to load the document.\r\n    NSDictionary* rowValue = row.value;\r\n    BOOL checked = [rowValue[@\"check\"] boolValue];\r\n    if (checked) {\r\n        cell.textLabel.textColor = [UIColor grayColor];\r\n        cell.imageView.image = [UIImage imageNamed:@\"checked\"];\r\n    } else {\r\n        cell.textLabel.textColor = [UIColor blackColor];\r\n        cell.imageView.image = [UIImage imageNamed: @\"unchecked\"];\r\n    }\r\n    \/\/ cell.textLabel.text is already set, thanks to setting up labelProperty\r\n<\/code><\/pre>\n<p style=\"text-align: justify\">Para o aplicativo de amostra aqui, o \"CBLUITableSource\" do Couchbase Lite atuar\u00e1 como intermedi\u00e1rio entre o LiveQuery e o UITableView, recebendo notifica\u00e7\u00f5es de altera\u00e7\u00e3o e, assim, conduzindo a tabela com base em uma consulta.  Ele tamb\u00e9m atua como o objeto de fonte de dados para o tableView, o que significa que \u00e9 o objeto que o tableView solicitar\u00e1 para fornecer todos os dados das linhas.  Seu objeto \"controller\" torna-se ent\u00e3o o delegado do UITableView, onde receber\u00e1 notifica\u00e7\u00f5es do TableView sobre quando o usu\u00e1rio tocar em uma das linhas.<\/p>\n<p style=\"text-align: justify\"><strong>Android<\/strong><\/p>\n<pre><code>\r\npublic View getView(int position, View itemView, ViewGroup parent) {\r\n \/\/...\r\n TextView label = ((ViewHolder)itemView.getTag()).label;\r\n QueryRow row = getItem(position);\r\n SavedRevision currentRevision = row.getDocument().getCurrentRevision();\r\n \/\/ Check box\r\n Object check = (Object) currentRevision.getProperty(\"check\");\r\n boolean isGroceryItemChecked = false;\r\n if (check != null &amp;&amp; check instanceof Boolean)\r\n     isGroceryItemChecked = ((Boolean)check).booleanValue();\r\n \/\/ Text\r\n String groceryItemText = (String) currentRevision.getProperty(\"text\");\r\n label.setText(groceryItemText);\r\n<\/code><\/pre>\n<p style=\"text-align: justify\">Aqui est\u00e1 o equivalente para Android na classe Grocery Sync Adapter.  Ele est\u00e1 obtendo o \"QueryRow\" chamando \"getItem()\" com base no n\u00famero da linha na tabela.  Em seguida, ele obt\u00e9m o documento da linha de consulta e obt\u00e9m sua revis\u00e3o atual. Em seguida, ele usa as propriedades de verifica\u00e7\u00e3o e texto para preencher os controles de IU na linha.<\/p>\n<p style=\"text-align: justify\">Por fim, no caso do aplicativo de amostra Grocery Sync, precisamos responder a um toque em uma linha da tabela, como, por exemplo, alternar a marca de sele\u00e7\u00e3o.  Abaixo, ilustramos como isso \u00e9 feito fazendo refer\u00eancia ao QueryRow em um \u00edndice espec\u00edfico e recuperando o documento a partir dele.<\/p>\n<p style=\"text-align: justify\"><strong>iOS<\/strong><\/p>\n<pre><code>\r\n- (void)tableView:(UITableView *)tableView \r\n         didSelectRowAtIndexPath:(NSIndexPath *)indexPath\r\n{\r\n    \/\/ Ask CBLUITableSource for the corresponding query row, and get its document:\r\n    CBLQueryRow *row = [self.dataSource rowAtIndex:indexPath.row];\r\n    CBLDocument *doc = row.document;\r\n\r\n    \/\/ Toggle the document's 'checked' property:\r\n    NSMutableDictionary *docContent = [doc.properties mutableCopy];\r\n    BOOL wasChecked = [docContent[@\"check\"] boolValue];\r\n    docContent[@\"check\"] = @(!wasChecked);\r\n\r\n    \/\/ Save changes:\r\n    NSError* error;\r\n    if (![doc.currentRevision putProperties: docContent error: &amp;error]) {\r\n        [self showErrorAlert: @\"Failed to update item\" forError: error];\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>Essa \u00e9 uma chamada de m\u00e9todo para o pr\u00f3prio UITableView em seu delegado.  Dizendo que uma linha foi selecionada, o que significa \"TAPPED\", ele vai para a fonte de dados. Que \u00e9 o objeto UI Table Source, e solicitar\u00e1 a Query Row nesse \u00edndice e obter\u00e1 o documento a partir dele. Portanto, agora ele est\u00e1 basicamente fazendo um ciclo de leitura, grava\u00e7\u00e3o e modifica\u00e7\u00e3o nesse documento. Ele obt\u00e9m as propriedades, faz uma c\u00f3pia mut\u00e1vel das propriedades e agora temos um dicion\u00e1rio mut\u00e1vel que pode ser atualizado.  L\u00ea a propriedade verificada como um booleano e a grava de volta como o oposto. Portanto, isso est\u00e1 invertendo o valor booleano da propriedade verificada. Em seguida, ele chama putProperties no final para salvar esse valor de volta.<\/p>\n<p style=\"text-align: justify\"><strong>Android<\/strong><\/p>\n<pre><code>\r\npublic void onItemClick(AdapterView(?) adapterView, View view, int position, long id) \r\n{\r\n    QueryRow row = (QueryRow) adapterView.getItemAtPosition(position);\r\n    Document document = row.getDocument();\r\n    Map(String, Object) newProperties = \r\n                              new HashMap(String, Object)(document.getProperties());\r\n\r\n    boolean checked = ((Boolean) newProperties.get(\"check\")).booleanValue();\r\n    newProperties.put(\"check\", !checked);\r\n\r\n    try {\r\n        document.putProperties(newProperties);\r\n        grocerySyncArrayAdapter.notifyDataSetChanged();\r\n    } catch (Exception e) {\r\n<\/code><\/pre>\n<p>Passando agora para a vers\u00e3o Android, temos um 'onItemClick()' que \u00e9 chamado pela GUI do Android.  Ela obter\u00e1 seu QueryRow nessa posi\u00e7\u00e3o, obter\u00e1 o documento, extrair\u00e1 as propriedades e, em seguida, colocar\u00e1 as propriedades.  Nas APIs Java, \u00e9 idiom\u00e1tico usar exce\u00e7\u00f5es, o que n\u00e3o acontece no Objective C. Portanto, h\u00e1 uma tentativa de captura em torno da al\u00e7a para salvar o documento.   Se, na janela de tempo, outra coisa modificasse o documento, provavelmente o replicador, isso geraria um erro. Voc\u00ea receberia um erro de conflito.<\/p>\n<p style=\"text-align: justify\">Em seguida, veremos a classe Replicator do Couchbase Lite e a classe <a href=\"https:\/\/www.couchbase.com\/blog\/pt\/developers\/mobile\/\">Portal do desenvolvedor do Couchbase Mobile<\/a> \u00e9 um \u00f3timo recurso para come\u00e7ar.<\/p>\n<p style=\"text-align: center\"><a href=\"https:\/\/bit.ly\/CBNYC2015\"><img decoding=\"async\" src=\"\/wp-content\/original-assets\/2015\/october\/couchbase-live-new-york-couchbase-101---how-to-build-your-first-couchbase-mobile-app\/events.cbliveny.blog.banner.jpg\" \/><\/a><\/p>\n<p>\u00a0A partir da\u00ed, vamos nos aprofundar em <a href=\"https:\/\/bit.ly\/sync_gateway\">Gateway de sincroniza\u00e7\u00e3o do Couchbase<\/a> em nossa sess\u00e3o 102, onde falarei sobre <a href=\"https:\/\/bit.ly\/CBNYC2015_102\">\"Como adicionar o Secure Sync ao seu aplicativo m\u00f3vel\".<\/a>\u00a0 Concluiremos o dia mostrando como ativar o recurso Peer-to-Peer do Couchbase Mobile na sess\u00e3o 103 com <a href=\"https:\/\/twitter.com\/agonyou\">Austin Gonyou<\/a>onde voc\u00ea pode criar experi\u00eancias sociais exclusivas no aplicativo com \"Building a Peer-to-Peer App with Couchbase Mobile\".<\/p>","protected":false},"excerpt":{"rendered":"<p>From the 101 session in the Couchbase LIVE New York mobile track, we went over on how to get started with integrating Couchbase Lite to your iOS and Android projects.\u00a0 From the &#8220;Couchbase Mobile 101: How to Build Your First [&hellip;]<\/p>","protected":false},"author":30,"featured_media":13873,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[7667,1810,9410],"tags":[],"ppma_author":[8983],"class_list":["post-1977","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-couchbase-lite","category-couchbase-mobile","category-objective-c"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.1 (Yoast SEO v26.1.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Couchbase Mobile 101 - How to Build Your First App<\/title>\n<meta name=\"description\" content=\"Check the Couchbase Lite features and APIs that were presented at the Couchbase 101 session as well as some of the code found in the Grocery Sync sample.\" \/>\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\/pt\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/\" \/>\n<meta property=\"og:locale\" content=\"pt_BR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Couchbase Mobile 101: How to Build Your First App [Couchbase LIVE New York]\" \/>\n<meta property=\"og:description\" content=\"Check the Couchbase Lite features and APIs that were presented at the Couchbase 101 session as well as some of the code found in the Grocery Sync sample.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/pt\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2015-10-23T08:09:44+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T03:09:56+00:00\" \/>\n<meta name=\"author\" content=\"William Hoang, Mobile Developer Advocate, 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=\"William Hoang, Mobile Developer Advocate, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/\"},\"author\":{\"name\":\"William Hoang, Mobile Developer Advocate, Couchbase\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/425717456c198fdf9aaa5d7a6d42ad32\"},\"headline\":\"Couchbase Mobile 101: How to Build Your First App [Couchbase LIVE New York]\",\"datePublished\":\"2015-10-23T08:09:44+00:00\",\"dateModified\":\"2025-06-14T03:09:56+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/\"},\"wordCount\":2141,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"articleSection\":[\"Couchbase Lite\",\"Couchbase Mobile\",\"Objective-C\"],\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/\",\"name\":\"Couchbase Mobile 101 - How to Build Your First App\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2015-10-23T08:09:44+00:00\",\"dateModified\":\"2025-06-14T03:09:56+00:00\",\"description\":\"Check the Couchbase Lite features and APIs that were presented at the Couchbase 101 session as well as some of the code found in the Grocery Sync sample.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#breadcrumb\"},\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#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\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Couchbase Mobile 101: How to Build Your First App [Couchbase LIVE New York]\"}]},{\"@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\":\"pt-BR\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@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\/425717456c198fdf9aaa5d7a6d42ad32\",\"name\":\"William Hoang, Mobile Developer Advocate, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/650445f1ea30314c4f3555dd680154f5\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/b912c9a97568a859697ee195432d0bd7cc3ed67d720ae2e6588b67313fa49e08?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/b912c9a97568a859697ee195432d0bd7cc3ed67d720ae2e6588b67313fa49e08?s=96&d=mm&r=g\",\"caption\":\"William Hoang, Mobile Developer Advocate, Couchbase\"},\"description\":\"William was a Developer Advocate on the Mobile Engineering\/Developer Experience team at Couchbase. His love for coffee and code has transcended him into the world of mobile while appreciating the offline in-person experiences. Prior, William worked on the Developer Relations team over at Twitter, BlackBerry, and Microsoft while also having been a Software Embedded GPS engineer at Research In Motion. William graduated from McGill University in Electrical Software Engineering\",\"url\":\"https:\/\/www.couchbase.com\/blog\/pt\/author\/william-hoang\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Couchbase Mobile 101 - How to Build Your First App","description":"Confira os recursos e as APIs do Couchbase Lite que foram apresentados na sess\u00e3o Couchbase 101, bem como alguns dos c\u00f3digos encontrados na amostra Grocery Sync.","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\/pt\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/","og_locale":"pt_BR","og_type":"article","og_title":"Couchbase Mobile 101: How to Build Your First App [Couchbase LIVE New York]","og_description":"Check the Couchbase Lite features and APIs that were presented at the Couchbase 101 session as well as some of the code found in the Grocery Sync sample.","og_url":"https:\/\/www.couchbase.com\/blog\/pt\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/","og_site_name":"The Couchbase Blog","article_published_time":"2015-10-23T08:09:44+00:00","article_modified_time":"2025-06-14T03:09:56+00:00","author":"William Hoang, Mobile Developer Advocate, Couchbase","twitter_card":"summary_large_image","twitter_misc":{"Written by":"William Hoang, Mobile Developer Advocate, Couchbase","Est. reading time":"10 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/"},"author":{"name":"William Hoang, Mobile Developer Advocate, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/425717456c198fdf9aaa5d7a6d42ad32"},"headline":"Couchbase Mobile 101: How to Build Your First App [Couchbase LIVE New York]","datePublished":"2015-10-23T08:09:44+00:00","dateModified":"2025-06-14T03:09:56+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/"},"wordCount":2141,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","articleSection":["Couchbase Lite","Couchbase Mobile","Objective-C"],"inLanguage":"pt-BR","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/","url":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/","name":"Couchbase Mobile 101 - How to Build Your First App","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2015-10-23T08:09:44+00:00","dateModified":"2025-06-14T03:09:56+00:00","description":"Confira os recursos e as APIs do Couchbase Lite que foram apresentados na sess\u00e3o Couchbase 101, bem como alguns dos c\u00f3digos encontrados na amostra Grocery Sync.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#breadcrumb"},"inLanguage":"pt-BR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/"]}]},{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#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\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Couchbase Mobile 101: How to Build Your First App [Couchbase LIVE New York]"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"Blog do Couchbase","description":"Couchbase, o banco de dados NoSQL","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":"pt-BR"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"Blog do Couchbase","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"pt-BR","@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\/425717456c198fdf9aaa5d7a6d42ad32","name":"William Hoang, defensor do desenvolvedor m\u00f3vel, Couchbase","image":{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/650445f1ea30314c4f3555dd680154f5","url":"https:\/\/secure.gravatar.com\/avatar\/b912c9a97568a859697ee195432d0bd7cc3ed67d720ae2e6588b67313fa49e08?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/b912c9a97568a859697ee195432d0bd7cc3ed67d720ae2e6588b67313fa49e08?s=96&d=mm&r=g","caption":"William Hoang, Mobile Developer Advocate, Couchbase"},"description":"William foi um defensor do desenvolvedor na equipe de engenharia m\u00f3vel\/experi\u00eancia do desenvolvedor na Couchbase. Seu amor por caf\u00e9 e c\u00f3digo o levou ao mundo dos dispositivos m\u00f3veis, ao mesmo tempo em que apreciava as experi\u00eancias presenciais off-line. Antes disso, William trabalhou na equipe de rela\u00e7\u00f5es com desenvolvedores do Twitter, BlackBerry e Microsoft, al\u00e9m de ter sido engenheiro de GPS incorporado a software na Research In Motion. William se formou na McGill University em Engenharia El\u00e9trica de Software","url":"https:\/\/www.couchbase.com\/blog\/pt\/author\/william-hoang\/"}]}},"authors":[{"term_id":8983,"user_id":30,"is_guest":0,"slug":"william-hoang","display_name":"William Hoang, Mobile Developer Advocate, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/b912c9a97568a859697ee195432d0bd7cc3ed67d720ae2e6588b67313fa49e08?s=96&d=mm&r=g","author_category":"","last_name":"Hoang","first_name":"William","job_title":"","user_url":"","description":"William foi um defensor do desenvolvedor na equipe de engenharia m\u00f3vel\/experi\u00eancia do desenvolvedor na Couchbase. Seu amor por caf\u00e9 e c\u00f3digo o levou ao mundo dos dispositivos m\u00f3veis, ao mesmo tempo em que apreciava as experi\u00eancias presenciais off-line. Antes disso, William trabalhou na equipe de rela\u00e7\u00f5es com desenvolvedores do Twitter, BlackBerry e Microsoft, al\u00e9m de ter sido engenheiro de GPS incorporado a software na Research In Motion. William se formou na McGill University em Engenharia El\u00e9trica de Software"}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/1977","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/users\/30"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/comments?post=1977"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/1977\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/media?parent=1977"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/categories?post=1977"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/tags?post=1977"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/ppma_author?post=1977"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}