65.9K
CodeProject 正在变化。 阅读更多。
Home

Swift:获取圣保罗的水位

2015年5月6日

CPOL

3分钟阅读

viewsIcon

11140

创建一个使用 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 NameOrganization NameOrganization IdentifierLanguageDevices

记住取消选中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 个元素。

考虑到元素始终以相同的顺序返回,我们可以使用硬编码的索引来设置数据 volumerainDayrainMonth 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 开发感到兴奋的起点。

如果您有任何疑问、问题或建议,请在下面留下您的评论,我很乐意回答。

© . All rights reserved.