Introdução

Um problema bastante atual (pelo menos em São Paulo) é a falta d’água.

Esse é um problema crônico, porém teve muito impacto no final do ano passado e início desse ano.

Uma API (https://github.com/rafaell-lycan/sabesp-mananciais-api) foi criada para que possamos acompanhar a situação de cada um dos mananciais da SABESP.

Detalhes da API

Essa dica foi enviada pelo meu amigo William Bruno (https://github.com/wbruno).

O endereço da API é https://sabesp-api.herokuapp.com/ e nela temos algumas informações sobre os mananciais da SABESP.

Além do nome do manancial, obtemos os dados de volume armazenado, pluviometria do dia, pluviometria acumulada do mês e média histórica do mês.

A API retorna o seguinte JSON:

[
    {
        "name": "Cantareira",
        "data": [
            {
                "key": "volume armazenado",
                "value": "18,9 %"
            },
            {
                "key": "pluviometria do dia",
                "value": "16,4 mm"
            },
            {
                "key": "pluviometria acumulada no mês",
                "value": "206,3 mm"
            },
            {
                "key": "média histórica do mês",
                "value": "178,0 mm"
            }
        ]
    },
    {
        "name": "Alto Tietê",
        "data": [
            {
                "key": "volume armazenado",
                "value": "22,8 %"
            },
            {
                "key": "pluviometria do dia",
                "value": "7,3 mm"
            },
            {
                "key": "pluviometria acumulada no mês",
                "value": "186,4 mm"
            },
            {
                "key": "média histórica do mês",
                "value": "172,4 mm"
            }
        ]
    },
    {
        "name": "Guarapiranga",
        "data": [
            {
                "key": "volume armazenado",
                "value": "85,0 %"
            },
            {
                "key": "pluviometria do dia",
                "value": "11,2 mm"
            },
            {
                "key": "pluviometria acumulada no mês",
                "value": "200,6 mm"
            },
            {
                "key": "média histórica do mês",
                "value": "153,2 mm"
            }
        ]
    },
    {
        "name": "Alto Cotia",
        "data": [
            {
                "key": "volume armazenado",
                "value": "64,6 %"
            },
            {
                "key": "pluviometria do dia",
                "value": "1,0 mm"
            },
            {
                "key": "pluviometria acumulada no mês",
                "value": "150,4 mm"
            },
            {
                "key": "média histórica do mês",
                "value": "149,1 mm"
            }
        ]
    },
    {
        "name": "Rio Grande",
        "data": [
            {
                "key": "volume armazenado",
                "value": "97,3 %"
            },
            {
                "key": "pluviometria do dia",
                "value": "2,6 mm"
            },
            {
                "key": "pluviometria acumulada no mês",
                "value": "199,4 mm"
            },
            {
                "key": "média histórica do mês",
                "value": "186,3 mm"
            }
        ]
    },
    {
        "name": "Rio Claro",
        "data": [
            {
                "key": "volume armazenado",
                "value": "43,9 %"
            },
            {
                "key": "pluviometria do dia",
                "value": "4,0 mm"
            },
            {
                "key": "pluviometria acumulada no mês",
                "value": "235,2 mm"
            },
            {
                "key": "média histórica do mês",
                "value": "245,9 mm"
            }
        ]
    }
]

Os dados obtidos na requisição acima, são do dia atual; caso queiramos obter dados de dias anteriores, precisamos passar a data que desejamos na URL da API, como por exemplo https://sabesp-api.herokuapp.com/2015-01-01.

Iniciando o Projeto iOS

Eu sempre gosto de testar as APIs com projetos onde posso imaginar uma aplicação real.

Para os testes de hoje escolhi o iOS como destino da aplicação.

Não é meu objetivo ensinar a programar em iOS, porém você pode baixar o projeto https://github.com/rpresb/ios-mananciais-sabesp e se tiver alguma dúvida eu terei o prazer em ajudar.

Abaixo estão as telas com as configurações que escolhi na criação do projeto.

Primeiro escolha a template para seu projeto, nesse caso Single View Application, e clique em Next

Captura de Tela 2015-03-30 às 22.35.13

Na próxima tela, preencha as informações solicitadas para Product Name, Organization Name, Organization Identifier, Language e Devices.

Captura de Tela 2015-03-30 às 22.35.04

Lembre-se de deixar desmarcada a opção Use Core Data e de selecionar a linguagem Swift

Codificando

Apesar de não ser a minha intenção neste post de ensinar o desenvolvimento em Swift, vou tentar explicar os códigos utilizados.

O projeto inteiro está disponível no meu github em https://github.com/rpresb/ios-mananciais-sabesp, fique à vontade para duplicar, melhorar e contribuir.

Arquivo Manancial.swift

import Foundation

struct Manancial {
    var name:String
    var volume:String
    var rainDay:String
    var rainMonth:String
    var rainAvg:String
    
    init(manancialDic:NSDictionary) {
        NSLog("%@", manancialDic);
        
        name = manancialDic["name"] as String
        
        var data = manancialDic["data"] as NSArray
        volume = data[0]["value"] as String
        rainDay = data[1]["value"] as String
        rainMonth = data[2]["value"] as String
        rainAvg = data[3]["value"] as String
    }
    
}

Neste arquivo temos a estrutura que será utilizada para facilitar a manipulação dos dados obtidos da API.

No construtor dessa classe, recebemos um NSDictionary que tem o JSON da API.

Para cada manancial, temos um array chamado data que possui 4 elementos.

Considerando que os elementos sempre serão apresentados na mesma ordem, podemos utilizar os índices fixos para obter os dados de volume, rainDay, rainMonth e rainAvg.

Arquivo ViewController.swift

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var volumeLabel: UILabel!
    @IBOutlet weak var dayLabel: UILabel!
    @IBOutlet weak var monthLabel: UILabel!
    @IBOutlet weak var avgLabel: UILabel!
    @IBOutlet weak var page:UIPageControl!
    @IBOutlet weak var level:UIView!
    
    var mananciais: NSArray!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        nameLabel.text = "Carregando..."
        volumeLabel.hidden = true
        dayLabel.hidden = true
        monthLabel.hidden = true
        avgLabel.hidden = true
        level.hidden = true

        loadData();
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func loadData() {
        let baseURL = NSURL(string: "https://sabesp-api.herokuapp.com/")
        let sharedSession = NSURLSession.sharedSession()
        let downloadTask: NSURLSessionDownloadTask = sharedSession.downloadTaskWithURL(baseURL!, completionHandler: { (location: NSURL!, response:NSURLResponse!, error: NSError!) -> Void in
            if (error == nil) {
                let dataObject = NSData(contentsOfURL: location)
                self.mananciais = NSJSONSerialization.JSONObjectWithData(dataObject!, options: nil, error: nil) as NSArray
                
                dispatch_async(dispatch_get_main_queue(), { () -> Void in
                    self.page.numberOfPages = self.mananciais.count
                    self.showPage(0)
                })
            } else {
                NSLog("%@", error)
                let networkIssueController = UIAlertController(title: "Error", message: "Unable to load data. Connectivity error!", preferredStyle: .Alert)
                let okButton = UIAlertAction(title: "OK", style: .Default, handler: nil)
                networkIssueController.addAction(okButton)
                self.presentViewController(networkIssueController, animated: true, completion: nil)
                
                dispatch_async(dispatch_get_main_queue(), { () -> Void in
                    self.nameLabel.text = "Erro"
                    self.volumeLabel.hidden = true
                    self.dayLabel.hidden = true
                    self.monthLabel.hidden = true
                    self.avgLabel.hidden = true
                    self.level.hidden = true
                })
            }
        })
        
        downloadTask.resume()
    }
    
    func showPage(index:Int) {
        let manancial = Manancial(manancialDic: self.mananciais[index] as NSDictionary)
        
        self.nameLabel.text = "\(manancial.name)"
        self.volumeLabel.text = "\(manancial.volume)"
        self.dayLabel.text = "\(manancial.rainDay)"
        self.monthLabel.text = "\(manancial.rainMonth)"
        self.avgLabel.text = "\(manancial.rainAvg)"
        
        self.volumeLabel.hidden = false
        self.dayLabel.hidden = false
        self.monthLabel.hidden = false
        self.avgLabel.hidden = false
        self.level.hidden = false
        
        var volume:NSDecimalNumber = NSDecimalNumber(string: manancial.volume.stringByReplacingOccurrencesOfString(" %", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil).stringByReplacingOccurrencesOfString(",", withString: ".", options: NSStringCompareOptions.LiteralSearch, range: nil))
        
        var pixel = CGFloat(volume) / 100 * self.view.frame.size.height

        let y:CGFloat = self.view.frame.size.height - pixel;
        
        self.level.frame.origin.y = y
        self.level.frame.size.height = pixel
    }

    @IBAction func pageChanged() {
        showPage(page.currentPage);
    }

}

Na função  viewDidLoad é chamada uma função loadData que é responsável por solicitar os dados para a API.

Após obter o JSON com o resultado da API, fazemos a serialização dele para um objeto do tipo NSArray.

Esse objeto será nossa fonte de dados para executar a paginação e apresentar os dados da tela.

Cada elemento deste array é um NSDictionary que será enviado para a função showPage quando necessário.

O próximo passo é obter a primeira página e para isso passamos o primeiro elemento do array para a função showPage.

Esta função tem o código para mostrar os dados do manancial na tela.

O resultado final da app podemos ver na imagem abaixo

Captura de Tela 2015-03-31 às 21.27.16

 

Conclusão

Conhecemos mais uma API interessante que podemos explorar em muitos formatos.

Decidi usar o iOS com Swift para mostrar que, mesmo com uma API simples, podemos fazer um uso criativo e entregar uma experiência interessante para o usuário.

Ainda que não seja meu objetivo ensinar a programar em swift, esse pode ser um ponto de partida, pois é simples e não tem muita dificuldade para começar a ver algum resultado.

Caso tenha alguma dúvida, crítica ou sugestão, envie sua mensagem que eu responderei com prazer.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s