Concrete Logo
Hamburger button

Paginando objetos usando enums e generics em Swift

  • Blog
  • 2 de Março de 2016
Share

Recentemente criei uma pequena classe em Swift para trabalhar com objetos paginados. A classe usa generics, portanto não precisa de subclasses para ser usada. Nesse projeto usamos o ObjectMapper para fazer o mapeamento JSON<-> modelo Swift, e inicialmente a classe ficou assim:

Com isso, , data recebe um array com objetos que podem ser mapeados respeitando algum tipo T que também obedece ao protocolo Mappable, criado pelo ObjectMapper.

Digamos que temos uma lista de produtos vindo no array data e que criamos a classe Product, que obedece ao protocolo Mappable. Ao receber o JSON, basta transformar para um objeto local assim:

Mas depois eu passei a usar essa classe em um outro projeto que tinha uma “feature“: o nome do campo array no JSON de resposta do backend não é sempre o mesmo.

Decidi usar enum como forma de forçar segurança de tipo e garantir mais qualidade no código, evitando a “String Oriented Programming“. Criei, então, a variação abaixo:

A linha if let name = PaginatedItemType(rawValue: String(T)) garante que o nome tipo T pode ser usada para inicializar uma variável do tipo PaginatedItemType, ou seja, todo tipo paginado deve estar incluído em PaginatedItemType. Isso força o desenvolvedor – no caso, eu 😀 – a corrigir a implementação e falar qual o nome do campo que vem no JSON dentro do método itemsFieldName().

Os cases do enum PaginatedItemType são os nomes das classes que podem ser passados para Paginated, e como pode ser visto no init? (usado pelo ObjectMapper), se não for uma das classes “suportadas” (case definido no enum e o nome do campo definido no método itemsFieldName()) vai dar problema já na compilação.

String(T) consegue converter o nome da classe usada com esse genérico para uma String. Como defini o enum “herdando” de String, posso usar o PaginatedItemType(rawValue:) para iniciar via o nome da classe, mas se o nome da classe não estiver definida em um case, o enum retorna nil.

A princípio não lembrei um jeito mais direto de converter direto do enum iniciando com o nome do tipo e devolvendo o nome do campo, então resolvi discutir com o pessoal aqui da Concrete Solutions. Foi então que o Daniel sugeriu adotar o protocolo CustomStringConvertible no enum. Tentei, então, esse código:

com a inicialização assim:

Mas não funcionou 🙁

A compilação falhava com a seguinte mensagem: Cast from ‘PaginatedItemType’ to unrelated type ‘String’ always fails.

Apesar de adotar o protocolo CustomStringConvertible, não é possível fazer a conversão direta usando um simples type casting. O correto é inicializar uma String passando como parâmetro um objeto que obedeça ao protocolo CutomStringConvertible. Assim, ficamos com:

Melhorando a implementação com o CustomStringConvertible:

Com isso, acabei com a versão final:

Muito mais seguro e flexível, usando alguns truques que não tínhamos em Objective-C (no passado, porque Objective-C tem evoluído e adicionou recentemente suporte a generics).

Obrigado pela discussão ao Daniel. Espero que gostem 🙂 Qualquer dúvida, sugestão ou comentário, só aproveitar os campos abaixo.