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 deste ano.
Uma 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.
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 em que escrevi este texto – 31 de março; 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 neste link 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.
Na próxima tela, preencha as informações solicitadas para Product Name, Organization Name, Organization Identifier, Language e Devices.
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 artigo ensinar o desenvolvimento em Swift, vou tentar explicar os códigos utilizados.
O projeto inteiro está disponível no meu GitHub, 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 desse 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. Essa função tem o código para mostrar os dados do manancial na tela.
O resultado final da app podemos ver na imagem abaixo:
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.







