Tratamento de erro de conexão no IOS

(Last Updated On: 25 de setembro de 2018)

Nesse post, trabalharemos com um aplicativo que lista filmes:

Fomos contratados para desenvolver um aplicativo que contém um catálogo de filmes. Quando o usuário acessa o aplicativo, uma lista com os filmes é apresentada:

Para listar os filmes, foi consumida a API do The Movie DB.

Vamos começar criando o método que vai fazer a requisição para a API do The Movie:


func getFilmes(sucesso: @escaping(_ resultado: [Movie]) -> Void, falha: @escaping(_ erro: Error) -> Void) {  
        Alamofire.request(Session.urlDefault() + "movie/popular?api_key=\(Session.getAuthorizationToken())&language=pt-BR&page=1", method: .get).responseJSON { (resposta) in
            // Verificar retorno do servidor
        }
}

Em seguida, precisamos verificar o status da requisição. Ou seja, se o servidor conseguiu retornar os filmes ou ocorreu alguma falha:


func getFilmes(sucesso: @escaping(_ resultado: [Movie]) -> Void, falha: @escaping(_ erro: Error) -> Void) {
        
        Alamofire.request(Session.urlDefault() + "movie/popular?api_key=\(Session.getAuthorizationToken())&language=pt-BR&page=1", method: .get).responseJSON { (resposta) in
            
            switch resposta.result {
            case .success:
                guard let json = resposta.result.value as? Dictionary<String, Any> else { return }
                if let movieList = json["results"] as? Array<Dictionary<String, Any>> {
                    sucesso(Movie.serializeObject(movieList))
                }
                break
            case .failure:
                print(resposta.error!)
                break
            }
        }
}

Vamos criar o método recuperaFilmes e chamá-lo no método viewDidLoad() do ViewController:


func recuperaFilmes() {
        FilmeQueryAPI().getFilmes(sucesso: { (listaDeFilmes) in
            self.filmes = listaDeFilmes
 self.filmesCollectionView.reloadData()
        }) { (error) in
            print(error)
        }
}

Agora temos a lista de filmes:

Legal! Conseguimos exibir os filmes na CollectionView. Criamos uma requisição utilizando o Alamofire, chamamos a API e ela nos devolveu as informações necessárias. Mas, o que acontece se tentarmos utilizar o app e o iPhone não tiver conexão com a internet?

Hum… o aplicativo fica carregando, carregando, mas não aparece a listagem. Será que ocorreu algum erro?

Avisando o usuário

Provavelmente você já utilizou algum aplicativo que te deixou esperando sem saber de fato o que estava acontecendo. Ou pior, você ficou esperando por um bom tempo e na verdade tinha ocorrido uma falha em alguma requisição.

Deixar as pessoas esperando por um longo tempo, e pior, sem mostrar o que está acontecendo é péssimo para a usabilidade do usuário.

Se você já implementou alguma requisição HTTP no seu aplicativo, seja de forma nativa ou utilizando alguma biblioteca como o Alamofire (https://github.com/Alamofire/Alamofire), por exemplo, você já deve ter visto um print(response.error.localizedDescription) espalhado pelo código.

O problema é o print que temos no caso de erro, onde simplesmente estamos imprimindo o erro do servidor no console.

Vamos dar uma olhada na mensagem de erro:

A mensagem nos diz que a conexão com a internet parece estar offline.

Para quem trabalha com desenvolvimento, é ótimo ver essa mensagem no console, assim conseguimos rapidamente saber qual é o problema. Porém, a pessoa ficará aguardando em um load infinito sem saber o que está acontecendo:

Para resolver esse problema, começaremos criando uma classe que implementará um alerta:


import UIKit
 
class Alerta: NSObject {
    
    func exibir(_ controller: UIViewController, _ titulo: String, _ mensagem: String) {
        let alerta = UIAlertController(title: titulo, message: mensagem, preferredStyle: .alert)
        let botao = UIAlertAction(title: "Ok", style: .default, handler: nil)
        alerta.addAction(botao)
        
        controller.present(alerta, animated: true, completion: nil)
    }
 
}

Agora que temos essa classe, no call back de erro do método recuperaFilmes() vamos implementá-la:


func recuperaFilmes() {
        FilmeQueryAPI().getFilmes(sucesso: { (listaDeFilmes) in
            self.filmes = listaDeFilmes
            self.filmesCollectionView.reloadData()
        }) { (error) in
            Alerta().exibir(self, "Atenção", error.localizedDescription)
        }
}

Vamos testar novamente:

Ótimo, agora estamos apresentando um alerta para o usuário indicando qual foi o problema.

Requisições e avisos

Fazer requisições para buscar informações é uma tarefa comum no desenvolvimento. Seja em aplicações mobile, web, e até mesmo em algumas aplicações desktops.

Porém, algumas vezes não existe a conexão com a internet. Então como fazemos? Uma forma, é mostrar uma mensagem para o usuário falando que a conexão com a internet é requerida.

Além dessa forma, existem diversas outras que podemos utilizar para tratar esse tipo de erro. Como, por exemplo, fazendo um cache da última requisição e utilizar esses dados para compor a tela que desejamos.

Aqui na Alura, temos uma carreira para o desenvolvimento de aplicativos para o IOS. Nela você aprenderá técnicas de construção de layouts que ajudem na experiência do usuário, formatar dados como CPF, CNPJ, e até comunicação com web services.

FIQUE POR DENTRO

Próximo ArtigoOrganizando o CSS no seu projeto