Swift 中使用 SwiftyJSON 制作一个比特币价格 APP
来源:互联网 发布:猎天使魔女 知乎 编辑:程序博客网 时间:2024/04/30 05:06
Swift 中处理 JSON 数据有很多种方式,可以使用原生的 NSJSONSerialization,也可以使用很多第三方库。原生的 NSJSONSerialization 方式这篇文章中介绍过。这次我们介绍一个第三方库 SwiftyJSON
并且用它来制作一个有趣的 APP.
关于 SwiftyJSON
首先,我们来了解一下什么是 SwiftyJSON
, 并且我们为什么要用这个库。比如我们要解析这个比特币实时价格的接口:
http://api.coindesk.com/v1/bpi/currentprice/CNY.json
这个接口的数据格式如下:
{ "time": { "updated": "Jul 20, 2015 13:14:00 UTC", "updatedISO": "2015-07-20T13:14:00+00:00", "updateduk": "Jul 20, 2015 at 14:14 BST" }, "disclaimer": "This data was produced from the CoinDesk Bitcoin Price Index (USD & CNY respectively).", "bpi": { "USD": { "code": "USD", "rate": "278.3400", "description": "United States Dollar", "rate_float": 278.34 }, "CNY": { "code": "CNY", "rate": "1,717.4683", "description": "Chinese Yuan", "rate_float": 1717.4683 } }}
如果我们使用原生的 NSJSONSerialization
方式,得到比特币的人民币价格的话,我们写出的代码大概就是这样的:
var url = "http://api.coindesk.com/v1/bpi/currentprice/CNY.json"if let jsonData = NSData(contentsOfURL: NSURL(string: url)!) { if let jsonObj: NSDictionary = NSJSONSerialization.JSONObjectWithData(jsonData, options: .MutableLeaves, error: nil) as? NSDictionary { if let bpi:NSDictionary = jsonObj["bpi"] as? NSDictionary { if let cny:NSDictionary = bpi["CNY"] as? NSDictionary { print(cny["rate"]!) } } }}
那么我们再来看一下,我们用 SwiftyJSON 来达到同样的目的要写的代码:
let url = "http://api.coindesk.com/v1/bpi/currentprice/CNY.json"if let jsonData = NSData(contentsOfURL: NSURL(string: url)!) { let json = JSON(data: jsonData) print(json["bpi"]["CNY"]["rate"])}
是不是感觉精简了很多呢,对,就是这个效果。SwiftyJSON
的以大好处就是,不用你来处理 Swift 中的类型转换,它会自动帮你处理类型等开发语言相关的问题,让你专注于 JSON 数据的处理中。怎么样,挺好用的把。
关于 SwifyJSON 的更多介绍,大家还可以参看它的 Github 主页:
https://github.com/SwiftyJSON/SwiftyJSON
下面我们就以一个例子来继续了解 SwiftyJSON。
比特币查询应用
我们今天要做的是一个比特币实时价格的 APP,这里我们会用到 SwiftyJSON 来解析服务端的数据。
首先我们创建一个项目, Single View Application
类型:
然后设置好项目的基本信息:
然后就是要引入 SwiftyJSON
库,
另外还可以下载我们预配置好的项目来进行开发:bitprice-start.zip
现在我们就进入主题吧,首先我们开始构建 UI 界面,打开 Main.storyboard
进行编辑。
- 首先,我们在
storyboard
中拖入三个UILabel
http://www.swiftcafe.io/images/swifty-json/3.png” alt=”构建 storyboard 界面” title=”” />
其中第一个 Label 的 text
属性设置为 “当前价格”, 后两个 Label 的 text
设置为空,用作显示比特币的价格。
- 然后,我们将两个用于显示价格的
UILabel
链接到主控制器的Outlet
中,在打开 storyboard 视图的同时,按住Option
并点击ViewController.swift
。这样编辑界面上同时显示了storyboard
和控制器的代码,然后我们在storyboard
中选中 Label,然后按住control
拖动到控制器的代码中:
http://www.swiftcafe.io/images/swifty-json/4.jpg” alt=”建立链接” title=”” />
随后会弹出一个变量名称提示框,我们将第一个 UILabel 命名为 priceLabel
,将第二个 UILabel 命名为 differLabel
。
http://www.swiftcafe.io/images/swifty-json/5.jpg” alt=”变量命名” title=”” />
最后,我们在给 ViewController
建立一个新的属性 lastPrice
, 存储上次更新的价格,用于计算当前价格相对于上次的涨跌幅。
这样我们的 ViewController
的属性定义如下:
class ViewController: UIViewController { @IBOutlet var priceLabel: UILabel! @IBOutlet var differLabel: UILabel! var lastPrice:Double = 0.0}
两个 IBOutlet
链接的 UILabel
, 还有一个 Double
变量用于存放上次的价格。
基础结构设置好后,我们就可以开始构建应用的逻辑了,我们首先定义一个方法 getLatestPrice()
,用于获取比特币最新的价格:
func getLatestPrice() -> String?{ let url = "http://api.coindesk.com/v1/bpi/currentprice/CNY.json" if let jsonData = NSData(contentsOfURL: NSURL(string: url)!) { let json = JSON(data: jsonData) return json["bpi"]["CNY"]["rate"].stringValue }else { return nil }}
这里面我们首先通过 NSData
的构造方法从指定的 URL 地址读取了比特币价格数据,然后用到了 SwiftyJSON
来读取和解析返回的 JSON
数据
let json = JSON(data: jsonData)return json["bpi"]["CNY"]["rate"].stringValue
只有两行代码,就完成了数据的提取,很方便吧。
数据读取方法写好了,那么我们需要另外一个方法来调度这个,因为我们这个 getLatestPrice
的网络操作时同步的,所以我们的调度方法需要把它放到另外的线程中,我们使用 GCD
进行这个处理:
func reloadPrice() { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in let price = self.getLatestPrice() dispatch_async(dispatch_get_main_queue(), { () -> Void in NSTimer.scheduledTimerWithTimeInterval(3, target: self, selector: Selector("reloadPrice"), userInfo: nil, repeats: false) if let p = price { var nsPrice = p as NSString nsPrice = nsPrice.stringByReplacingOccurrencesOfString(",", withString: "") let doublePrice = nsPrice.doubleValue let differPrice = doublePrice - self.lastPrice self.lastPrice = doublePrice; self.priceLabel.text = NSString(format: "¥ %.2f", doublePrice) as? String if differPrice > 0 { self.differLabel.textColor = UIColor.redColor() self.priceLabel.textColor = UIColor.redColor() self.differLabel.text = NSString(format: "+%.2f", differPrice) as? String }else{ self.differLabel.text = NSString(format: "%.2f", differPrice) as? String self.differLabel.textColor = UIColor.greenColor() self.priceLabel.textColor = UIColor.greenColor() } } }) });}
我们这里首先使用 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),...)
来调度异步线程,在这个线程中,我们调用了 getLatestPrice()
方法来获取当前的比特币价格,读取成功后,我们要用这个数据来更新 UI 显示了。而 UI 的操作时不能在异步线程中进行的。所以我们随后又调用了 dispatch_async(dispatch_get_main_queue(),...)
方法将处理调度到主线程中。
由于服务端返回的数据格式是字符串类型的诸如这样的价格数据
1,273.203
所以我们还需要对这个数据进行一下转换:
var nsPrice = p as NSStringnsPrice = nsPrice.stringByReplacingOccurrencesOfString(",", withString: "")let doublePrice = nsPrice.doubleValue
首先我们将字符串中的 ,
字符清除掉,然后使用 NSString 的 doubleValue
将字符串转换成 Double 类型。
接下来,我们用当前的价格减去上次读取的价格,计算出差价,就可以显示出相对于上次读取数据的涨跌幅度了。计算完成后,我们就重新将当前的价格存入 self.lastPrice
中,以便于下次的计算。
let differPrice = doublePrice - self.lastPriceself.lastPrice = doublePrice;
最后,我们计算出了这些数据,再将他们显示的 UILabel 上面。
self.priceLabel.text = NSString(format: "¥ %.2f", doublePrice) as? Stringif differPrice > 0 { self.differLabel.textColor = UIColor.redColor() self.priceLabel.textColor = UIColor.redColor() self.differLabel.text = NSString(format: "+%.2f", differPrice) as? String}else{ self.differLabel.text = NSString(format: "%.2f", differPrice) as? String self.differLabel.textColor = UIColor.greenColor() self.priceLabel.textColor = UIColor.greenColor()}
我们首先将当前价格设置到 self.priceLabel
, 然后根据涨跌幅度是正数还是负数设置 self.differLabel
的文字,如果是正数要在前面放一个 +
号。同时我们根据涨跌幅设置文本的颜色,如果是涨就设置为红色,如果是跌就设置为绿色。
最后还有一行代码我们要注意:
NSTimer.scheduledTimerWithTimeInterval(3, target: self, selector: Selector("reloadPrice"), userInfo: nil, repeats: false)
我们用 NSTimer
又调度了一下这个方法,在 3 秒钟之后,重新请求最新价格。这样我们的价格就能每隔 3 秒刷新一次。
数据读取方法弄好之后,我们就可以在 viewDidLoad()
里面调用它了
override func viewDidLoad() { super.viewDidLoad() reloadPrice()}
接下来可以运行一下项目,我们就会看到报价比特币的最新价格显示在界面上了。然后还可以不停的刷新。
显示历史报价
最新报价的现实逻辑我们实现完了,我们还可以做更多的事情,仔细研究 coindesk
的数据,我们发现还有一个接口可以实现查询比特币的报价历史:
http://api.coindesk.com/v1/bpi/historical/close.json?start=2015-07-15&end=2015-07-24¤cy=CNY
访问这个接口我们就可以看到诸如这样的数据返回:
{ "bpi": { "2015-07-15": 1756.5732, "2015-07-16": 1719.6188, "2015-07-17": 1723.7974, "2015-07-18": 1698.9991, "2015-07-19": 1686.3934, "2015-07-20": 1723.3102, "2015-07-21": 1702.5693, "2015-07-22": 1710.3503 }, "disclaimer": "This data was produced from the CoinDesk Bitcoin Price Index. BPI value data returned as CNY.", "time": { "updated": "Jul 23, 2015 09:53:17 UTC", "updatedISO": "2015-07-23T09:53:17+00:00" }}
我们看到,这个接口返回了从起始日期到结束日期的比特币价格信息,我们可以使用这个数据来显示历史数据,比如从当天往前 5 天之内的历史数据。
那么我们先写一个网络读取和解析数据的方法:
func getLastFiveDayPrice() -> Array<(String,String)> { var curDate = NSDate() var calendar = NSCalendar.currentCalendar() let startDate = calendar.dateByAddingUnit(NSCalendarUnit.CalendarUnitDay, value: -6, toDate: curDate, options: nil) let endDate = calendar.dateByAddingUnit(NSCalendarUnit.CalendarUnitDay, value: -1, toDate: curDate, options: nil) let formatter = NSDateFormatter() formatter.dateFormat = "yyyy-MM-dd" let url = "http://api.coindesk.com/v1/bpi/historical/close.json?start=\(formatter.stringFromDate(startDate!))&end=\(formatter.stringFromDate(endDate!))¤cy=CNY" var result = Array<(String,String)>() if let jsonData = NSData(contentsOfURL: NSURL(string: url)!) { let json = JSON(data: jsonData) let bpiDict:JSON = json["bpi"] for (key,val) in bpiDict { result.append((key,val.stringValue)) } } return result}
这个方法会返回一个数组,我们仔细看一下这个数组的定义 Array<(String,String)>
,数组中的类型是 (String,String)
, 这种类型定义叫做 元组(Tuple) 是 Swift中的一个语言特性,关于元组,简而言之就是一个包含了多个元素的类型,比如我们这里的元组包含了两个 String
类型的值。
下面展示了元组类型的简单用法:
let tuple = ("2012-2-21","1,232.23")//可以通过索引来引用元组的元素print("\(tuple.0) price is \(tuple.1)")//还可以为元组的项制定名称let (date,price) = tupleprint("\(date) price is \(price)")
我们看到,我们可以通过索引的方式,也可以通过为元组项指定名称的方式来引用元组中的值。这里简单介绍一下元组的概念,更详细的内容大家可以参考相关资料。
接下来,我们看一下这个方法的内容,首先我们通过格式化 NSDate
输出的方式拼接出 URL,这里我们用到了 NSCalendar
,这个类可以通过 dateByAddingUnit
方法操作 NSDate
的各个日期属性,比如将当前的日期减去多少天,我们用这个方法得到当前日期往前 5 天和 1 天的日期值,用于得到这个期间的比特币价格。
我们还用到了 NSDateFormatter
,这个类可以将 NSDate
的值进行格式化输出,得到我们需要的日期输出格式。我们这里需要类似 2012-03-12
的这种日期格式,所以我们将日期格式定义为 yyyy-MM-dd
。
最后通过 NSDateFormatter
的 stringFromDate
方法输出格式化后的日期值:
var curDate = NSDate()var calendar = NSCalendar.currentCalendar()let startDate = calendar.dateByAddingUnit(NSCalendarUnit.CalendarUnitDay, value: -6, toDate: curDate, options: nil)let endDate = calendar.dateByAddingUnit(NSCalendarUnit.CalendarUnitDay, value: -1, toDate: curDate, options: nil)let formatter = NSDateFormatter()formatter.dateFormat = "yyyy-MM-dd"let url = "http://api.coindesk.com/v1/bpi/historical/close.json?start=\(formatter.stringFromDate(startDate!))&end=\(formatter.stringFromDate(endDate!))¤cy=CNY"
拼接好 URL 之后,我们就可以开始请求数据了,看一看下面的代码:
var result = Array<(String,String)>()if let jsonData = NSData(contentsOfURL: NSURL(string: url)!) { let json = JSON(data: jsonData) let bpiDict:JSON = json["bpi"] for (key,val) in bpiDict { result.append((key,val.stringValue)) }}
首先我们定义了一个 result
数组,用于返回我们的价格列表。然后我们使用 NSData
的构造方法来请求接口的数据。请求到数据后,我们使用 SwiftyJSON
的 JSON
类进行解析,随后的 for
循环中,我们遍历了 bpi
节点中的所有的键值,将这些键值通过元组的方式添加到 result
列表中。
result.append((key,val.stringValue))
注意条语句,我们构造元组的方式 (key,val.stringValue)
, 因为我们的元组定义为 (String,String)
类型,在 for
循环中,我们的 key
变量是 String
类型的,所以我们可以直接用这个值来构建元组的第一项,而 val
不是 String
类型的。我们必须使用 SwiftyJSON
中的 stringValue
方法取得这个节点的 String
类型的值来构建元组的第二项。
到此为止我们的历史数据读取方法也完成了。
构造历史价格界面
数据读取方法构造完成后,我们就可以开始处理 UI 界面了,我们创建了 buildHistoryLabels
方法:
func buildHistoryLabels(priceList: Array<(String,String)>) { var count = 0.0 var labelTitle = UILabel(frame: CGRectMake(CGFloat(30.0), CGFloat(220.0), CGFloat(200.0), CGFloat(30.0))) labelTitle.text = "历史价格" self.view.addSubview(labelTitle) for (date, price) in priceList { var labelHistory = UILabel(frame: CGRectMake(CGFloat(30.0), CGFloat(250 + count * 40.0), CGFloat(200.0), CGFloat(30.0))) labelHistory.text = "\(date) \(price)" self.view.addSubview(labelHistory) count++ }}
这个方法接受一个数组作为参数,这个数组的内容就是我们的价格列表。首先我们这里构建了这组 UILabel 的标题:
var labelTitle = UILabel(frame: CGRectMake(CGFloat(30.0), CGFloat(220.0), CGFloat(200.0), CGFloat(30.0)))labelTitle.text = "历史价格"self.view.addSubview(labelTitle)
然后我们通过一个 for
循环来遍历价格列表,取出元组的两项内容,分别以 date
和 price
来命名,并用这些数据构建出 UILabel
并添加到 UI 视图中:
for (date, price) in priceList { var labelHistory = UILabel(frame: CGRectMake(CGFloat(30.0), CGFloat(250 + count * 40.0), CGFloat(200.0), CGFloat(30.0))) labelHistory.text = "\(date) \(price)" self.view.addSubview(labelHistory) count++}
现在我们可以运行 APP 了,我们看到当前的价格,以及近期的价格都展示在了界面中:
http://www.swiftcafe.io/images/swifty-json/7.png” alt=”价格列表” title=”” />
到此为止,我们利用 SwiftyJSON
完成的读取了 JSON 数据。我们的比特币查询 APP 也基本完成了。当然这个示例 APP 还有很多不完善的地方,如果大家有兴趣,让他变的更加完善。
- Swift 中使用 SwiftyJSON 制作一个比特币价格 APP
- Swift开发:使用SwiftyJSON解析JSON数据
- 比特币今日价格
- 比特币价格
- 比特币价格走势
- 比特币价格今日的价格
- 为什么比特币价格摇摇欲坠?
- swift:使用第三方开源库SwiftyJSON解析本地json数据文件
- 如何用Swift制作一个简单的画板APP
- Swift 第三方库 - SwiftyJSON
- 2016比特币价格:跌还是涨
- 比特币量化价格浮标-CCI策略
- 西班牙世界遗产以比特币价格出售
- 用Python预测比特币价格
- 比特币怎么制作
- 比特币如何制作
- 制作比特币
- 怎么制作比特币
- windows7系统windows XP系统ps2针孔老式键盘开机不能使用驱动出现感叹号--亲自测试可以解决问题
- 重载,覆盖,隐藏
- C语言课程设计-学生信息管理系统
- Big Number
- c++ 模板详解(一)
- Swift 中使用 SwiftyJSON 制作一个比特币价格 APP
- 关于DMA传输外设地址的说明
- hdu1045 Fire Net(二分图最大匹配)
- Project Euler:Problem 90 Cube digit pairs
- zoj1745 Are We There Yet?
- HDU 3681 Prison Break(状压DP + 二分)
- H.264 基础及 RTP 封包详解
- oracle数据库---sqlplus介绍
- 1027