Swift:获取圣保罗的水位





5.00/5 (4投票s)
创建一个使用 Swift 的 iOS 应用,显示巴西主要水库系统的水位。
引言
我是巴西人,我们正面临一场水危机(尤其是在圣保罗州),这是圣保罗历史上最严重的干旱,人们对了解坎塔雷拉水库系统的水位产生了兴趣。
州水务局 SABESP 有一个 网站,该网站显示当前水位并每日更新。
基于此网站上的数据创建了一个 API (https://github.com/rafaell-lycan/sabesp-mananciais-api),我们可以跟踪坎塔雷拉水库系统中每个水库的水位变化。
像往常一样,此帖子的源代码可在我的 github 上找到。
API 详细信息
我的朋友 William Bruno (https://github.com/wbruno) 是此 API 的贡献者。
API 地址为 https://sabesp-api.herokuapp.com/。
除了水库的名称外,它还具有当前水位(volume armazenado),当日降雨量(pluviometria do dia),当月累计降雨量(pluviometria acumulada do mês)和当月历史平均值(média histórica do mês)。
API 返回以下 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"
}
]
}
]
上面显示返回的数据是当天的;如果我们要获取过去几天的数据,我们必须在 API 的 URL 上发送所需的日期,即 https://sabesp-api.herokuapp.com/2015-01-01。
创建 iOS 项目
这不是我教您如何在 iOS 中开发的目的,但是您可以在 https://github.com/rpresb/ios-mananciais-sabesp 获取该项目,如果您有任何问题,请在下面留下您的评论。
以下是创建项目时我选择的选项的屏幕截图。
首先,选择项目模板Single View Application,然后单击下一步。
在下一个窗口中,填写字段Product Name、Organization Name、Organization Identifier、Language和Devices。
记住取消选中Use Core Data复选框,然后选择 Swift 语言。
编码
尽管本文的目的不是教您如何在 Swift 中开发,但我将尝试解释我为此应用程序制作的以下代码。
随时在 https://github.com/rpresb/ios-mananciais-sabesp 下载代码。
文件 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
}
}
在此文件中,我们具有将用于操作从 API 获取的数据的结构。
在 Manancial 类的构造函数中,我们收到一个 NSDictionary
,其中包含从 API 返回的 JSON。
对于每个水库(manancial),我们都有一个名为 data 的数组,其中包含 4 个元素。
考虑到元素始终以相同的顺序返回,我们可以使用硬编码的索引来设置数据 volume
,rainDay
,rainMonth
e rainAvg
。
文件 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);
}
}
在函数 viewDidLoad
中,我们调用函数 loadData
,该函数负责请求 API 中的数据。
获取包含数据的 JSON 后,我们将其序列化为 NSArray
对象。
此对象是我们的数据源,用于显示水库信息并为每个水库创建一个页面。
此数组中的每个元素都是一个 NSDictionary
,当用户更改页面时,我们将将其发送到函数 showPage
。
下一步是获取第一页;我们必须将数组的第一个元素发送到函数 showPage
。
运行中的应用程序如下所示
结论
我们使用了另一个有趣的 API。
我选择使用 Swift 的 iOS 来使用此 API,以表明即使使用非常简单的 API,我们也可以进行创造性的使用,从而为用户提供有趣的体验。
尽管我的目标不是教您如何在 Swift 中开发,但这可能是您了解其工作原理并对深入 iOS 开发感到兴奋的起点。
如果您有任何疑问、问题或建议,请在下面留下您的评论,我很乐意回答。