Concrete Logo
Hamburger button

Criando um app iOS da Marvel desde o início – Parte 1

  • Blog
  • 13 de Dezembro de 2016
Share

Esse post foi originalmente publicado (em inglês) na Cocoa Academy, no Medium. Veja aqui.

Vamos começar hoje aqui no Blog uma série de posts para mostrar como criar um app iOS do início usando muitas pods e ferramentas para deixar sua vida mais fácil. A ideia é cobrir vários tópicos importantes ao longo desse e dos próximos posts. Provavelmente você pode achar todas essas informações espalhadas pela internet, cada uma em um tutorial diferente. Minha intenção aqui é passar tudo em um projeto só. Se você quiser ver o código, pode acessar aqui. Vou usar tags diferentes para diferentes pontos no tempo, cobrindo a primeira parte, a segunda e assim por diante.

lioy

O plano é esse:

– Criar uma camada de rede usando Moya + RxSwift;

– Como criar modelos a partir de um Json usando um framework de mapeamento;

– Como evitar view controllers massivas, usando datasources e delegates externos. Isso vai manter o código “boilerplate” da CollectionView e TableView onde deveria;

– Como lidar com storyboards e view controllers usando Enums com SwiftGen, deixando tudo mais seguro e organizado;

– Um jeito melhor de lidar com células de tableView e CollectionView;

– Como lidar com downloads de imagens usando o Kingfisher;

– Lidar com necessidades de segurança nas especificações da API da Marvel usando CryptoSwift;

– Usar cocoapods-keys pra manter dados e chaves sensíveis fora do seu repositório.

Nos próximos posts vamos falar sobre:

– Como testar as camadas do seu app (redes, modelos, viewControllers, datasources e etc.);

– Como gerar um relatório de cobertura;

– Automatizar seu pipeline de desenvolvimento com o Fastlane;

– Como configurar integração contínua para projetos do GitHub com o Travis;

– Criar regras de Pull Request para seu repositório usando o Danger;

– Skecth para desenvolvedores! Como podemos criar designs “bootstrapeds”.

O app

Para esse projeto eu decidi criar um app Marvel, usando a API deles. Esta primeira parte está toda na tag v0.1. Você só precisa clonar o repositório e trocar para a tag v0.1.

Aviso: Vamos melhorar bastante o layout em um próximo post, quando formos falar sobre sketch e design para desenvolvedores. Por enquanto ainda está bastante simples, como você pode ver abaixo.

appios1

Começando pelo início: O Podfile

Podemos notar abaixo diversos pods que vamos usar nessa primeira parte.

Tem uma coisa importante sobre esse Podfile: estamos usando, como foi mencionado, o plugin cocoapods-keys. Ele vai nos permitir definir no nosso keychain os valores das chaves na primeira vez que instalarmos o pod. Depois desse passo de configuração, nós podemos injetar no nosso código as chaves sem precisar adicioná-las ao nosso repositório. E não é só isso, dessa forma cada um de vocês poderá usar suas próprias chaves da API da Marvel, que  podem ser geradas aqui. Legal, né? Obrigado orta!

Depois de criar as chaves da API e configurar o projeto, vamos para a próxima parte.

Camada de rede com Moya

Moya é um ótimo pod para gerenciar todo o boilerplate e a complexidade de ter que criar sua própria camada de abstração de rede de projeto para projeto. Embora não seja obrigatório usá-lo com RxSwift, para esse tutorial vou combinar os dois.

E é isso! Muito fácil definir as configurações da API, os endpoints, parâmetros, métodos e todo o resto. Vou usar a propriedade sampleData mais tarde, em um post sobre testes. Também vale mencionar que a estrutura MarvelAPIConfig e o método authParameters  estão aqui por uma necessidade específica da API da Marvel. O authParameters é mergeado com os parâmetros do usuário, podemos facilmente fazer isso usando um pod legal chamado Dollar, que tem vários métodos úteis.

Depois de criar as configurações da API nós ainda precisamos criar um provider do Moya para usar a API. Isso pode ser feito em qualquer lugar, mas recomendo fortemente criar outra abstração para lidar com esse tipo de lógica.

Tem muita coisa acontecendo aqui. Eu criei dois métodos genéricos (um para array, outro para objeto) para abstrair como interagir com a API e lidar com as resposta. Depois, esses métodos podem ser usados para fazer chamadas mais específicas  a API, como:

Aviso: eu sei que não estou usando nem 1% do RxSwift, só para fazer o “unwrap” da resposta da API (a API da Marvel tem duas camadas de objetos, que eu realmente não me importo, para esse tutorial, pelo menos), “parsear” em modelos e lidar com o fluxo de sucesso ou erro. Muitos podem argumentar, e eles estão certos por isso, que eu deveria retornar uma lista de Observables que podem ser, mais tarde, combinados com outras chamadas da API, filtradas e etc., ao invés de lidar com isso dentro da minha abstração  da API e prover um bloco de “completion”. A questão é que não há certo ou errado aqui. Tudo é um trade off, e este projeto não tem tais necessidades. Sendo assim, não pede por tal implementação, portanto vamos manter as coisas simples.

Agora nós podemos fazer chamadas à API sem se preocupar com nenhum detalhe de implementação, simples assim:

Essa explicação não pretende ser um Guia completo, é muito mais como um guideline, um exemplo. É importante que você clone o repositório e vá brincando com ele.

Datasources externos + Reusable

Agora vamos dar uma olhada nos datasources e em como podemos extrair um monte de código das nossas view controllers. Vamos criar um protocolo pra definir um contrato, e assim podemos repetir esse padrão ao longo de todo o projeto.

Agora nós podemos implementar facilmente qualquer datasource, de uma forma padrão. Tudo o que precisamos é estar de acordo com o protocolo.

Aqui, você pode ver métodos como register(cellType: ) e dequeReusableCell. Eles pertencem ao pod Reusable, que se adotado no projeto pode realmente melhorar a forma como lidamos com células de TableView e CollectionView no nosso código. Na verdade é bastante fácil implementar um comportamento similar usando protocolos. Tudo o que precisamos fazer é:

É claro que o pod Reusable faz algumas outras coisas a mais também, mas você entendeu. Só para manter a sanidade, acredito de fato que devemos usar o pod ao invés de implementar por nós mesmos. Não reinvente a roda!

Fazendo o download de imagens

Mais frequentemente do que gostaríamos nos pegamos recriando o mesmo código várias vezes. Um desses padrões repetitivos está relacionado ao download de imagens e como carregá-las dentro da imageView. No exemplo abaixo, você pode ver uma interface simples chamada download(image:), que leva um parâmetro de string com a URL da imagem.

Essa interface é definida em uma extensão da classe UIImageView, uma solução simples que pode ajudar a centralizar o comportamento. Claro que existem diversas outras maneiras, melhores que essa de fato, para resolver essa situação, estou apenas mostrando um jeito criativo de usar as extensões do Swift.

SwiftGen e Storyboards enum

Se você é como eu, e “meio” que não gosta de segues (para dizer o mínimo), você pode acabar repetindo a mesma receita de código toda vez que você precisar navegar entre uma view controller e outra. Instanciar o storyboard, recuperar a view controler usando uma string “hardcoded”  e assim por diante. Esses passos, além de chatos, são propensos a erros e tendem a produzir comportamentos inesperados.

Entretanto, não precisa ser assim. Ferramentas como swiftGen podem nos ajudar a criar um Storyboard Enum e nos proporcionar o mesmo comportamento, com muito menos ou nenhuma dor. Tudo o que precisamos fazer é adicionar uma “run script phase” em nossa build, com esse código:

lioy3

Depois disso só precisamos adicionar o arquivo Storyboard.swift ao nosso projeto e resolver o problema, like a boss.

Finalizando…

Chegamos ao fim da primeira parte dessa série de posts. Ainda estou testando esse formato, ou seja, é possível que esse conteúdo possa mudar um pouco, talvez eu siga na linha de screencasts. Por isso, é muito importante que você  clone o projeto e brinque com ele. Não seria prático nem benéfico colocar todas as informações aqui, senão seria um post gigante e impossível de ler, por isso novamente enfatizo a importância de clonar o repositório e meter a “mão na massa”.

Como sempre, qualquer dúvida, comentário ou feedback são mais que bem-vindos! =) Aproveite os campos abaixo.

Update: Veja a Parte 2 aqui.

Temos vagas para desenvolvedores iOS! Quer saber mais? Clique aqui.