您的位置:首页 > 理论基础 > 计算机网络

(作业)利用网络编程实现多个城市的天气查询

2017-12-06 19:54 435 查看
哎呀,这次作业终于涉及到一些高大上的东西了,废话不多说,先看要求



这次作业需要从网上获取到城市的天气信息,并在第二个界面显示,我们这里需要用到两个第三方库,Alamofire和SwiftyJSON。Alamofire时网络的第三方库,我们使用它来从网络获取天气信息的JSON数据,然后使用SwiftyJSON来解析我们获取的JSON数据。虽然使用Swift自带的URLSession和JSONSerialization也可以办到,但使用这两个第三方库更加简便。

要使用这两个第三方库,我们可以到github上下载并手动导入,但我们也可以使用一个非常方便的工具cocoapods来管理,cocoapods的使用可以看看CSDN小伙伴的博客或者简书小伙伴写的文章

然后从网络获取的天气预报信息可以看看博主转载的文章

我们导入了第三方框架之后,不能再打开以前的蓝色的.xcodeproj工程了,而应该打开白色的.xcworkspace工程,打开该工程后,我们工程的结构会有所改变,目录结构如下:



在Pods工程下的Pods目录下面的就是我们导入的第三方框架,上面的就是我们自己写的工程的目录。

在这些准备工作做完之后,我们就需要开始着手实现需求了。

首先我们这里会用到导航栏控制器,所以在AppDelegate.swift中的func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool方法中增加下面这一行代码

window?.rootViewController = UINavigationController(rootViewController: ViewController())


相信经常看我博客的读者们对这行代码已经不陌生了,这时实现多MVC的基础控制器之一,有不熟悉的读者可以自行查阅相关资料。

然后我们需要创建一个展示天气信息的控制器,仔细看了上面目录结构的读者应该留意到了,博主创建了一个WeatherViewController.swift文件,在这个文件中,我们首先声明两个属性

var weather: String?
var navTitle: String?


第一个字符串是天气信息,第二个字符串是当前页面的标题,博主设置第二个界面的想法是当用户点击第一个界面的表格中的某一行后,改行的城市名字将会作为第二个界面导航栏上的标题显示。

然后我们在viewDidLoad方法中设置一下视图的北京颜色和控制器的标题,再添加一个UILabel控件,用于显示天气信息

self.view.backgroundColor = UIColor.white
self.title = navTitle

let label = UILabel(frame: CGRect(x: 10, y: 100, width: self.view.frame.width - 20, height: self.view.frame.height - 150))
label.text = weather!
label.textAlignment = .center
label.layer.borderWidth = 1
label.textColor = UIColor.black
label.numberOfLines = 0
label.font = UIFont.systemFont(ofSize: 36)
self.view.addSubview(label)


到这里,我们显示天气信息的界面就准备完成了,接下来就是实现我们第一个界面的表格及其功能了。

因为要使用这两个第三方库,所以我们首先需要导入这两个库

import Alamofire
import SwiftyJSON


有时候不能导入,可能是工程还没有构建过,读者可以先构建一下或者运行一下工程,这样等这些第三方库编译之后就可以使用它们了。

然后我们需要表格来展示城市名字,所以我们这里使用UITableView来展示城市名字。我们先要让ViewController遵循UITableView的两个协议,UITableViewDelegate, UITableViewDataSource

然后我们声明tableView,并将城市名称和其对应的编号以字典形式保存在内存当中

var tableView: UITableView!
let citise = ["北京": 101010100, "上海": 101020100, "天津": 101030100, "重庆": 101040100, "哈尔滨": 101050101, "长春": 101060101, "沈阳": 101070101, "呼和浩特": 101080101, "石家庄": 101090101, "太原": 101100101, "西安": 101110101, "济南": 101120101, "乌鲁木齐": 101130101, "拉萨": 101140101, "西宁": 101150101, "兰州": 101160101, "银川": 101170101, "郑州": 101180101, "南京": 101190101, "武汉":
4000
101200101, "杭州": 101210101, "合肥": 101220101, "福州": 101230101, "南昌": 101240101, "长沙": 101250101, "贵阳": 101260101, "成都": 101270101, "广州": 101280101, "昆明": 101290101, "南宁": 101300101, "海口": 101310101, "香港": 101320101, "澳门": 101330101, "台北县": 101340101]


接下来我们就需要将tableView添加到视图当中了

self.view.backgroundColor = UIColor.white
self.title = "cities"

tableView = UITableView(frame: self.view.frame)
tableView.delegate = self
tableView.dataSource = self
self.view.addSubview(tableView)


到这里,系统依旧会提示有错误,那是因为我们还没有实现数据源中的两个必须实现的方法

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return citise.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")

if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
cell?.accessoryType = .disclosureIndicator
}

cell?.textLabel?.text = Array(citise.keys)[indexPath.row]

return cell!
}


记住,使用UITableViewCell时,一定要重用,不然表视图会出现卡顿情况,有时候即使我们重用了cell依然会有卡顿,那就需要使用一些其他技巧来解决卡顿效果了。

到这里,我们基本的准备已经完成了,界面有了,但功能差了一点,那就是从网络获取城市的信息,并跳转到第二个界面展示,所以我们需要用到代理中的方法

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

let city = "\(citise[Array(citise.keys)[indexPath.row]]!)"
let site = "http://www.weather.com.cn/data/sk/" + city + ".html"
let url = URL(string: site)
Alamofire.request(url!).responseJSON { (response) in
if let json = try? JSON(data: response.data!) {
let dict = json["weatherinfo"]
let city = dict["city"].string!
let temp = dict["temp"].string!
let wd = dict["WD"].string!
let ws = dict["WS"].string!
var weather = "温度: \(temp)\n"
weather += "风向: \(wd)\n"
weather += "风力: \(ws)"

let viewController = WeatherViewController()
viewController.navTitle = city
viewController.weather = weather
self.navigationController?.pushViewController(viewController, animated: true)
}
}
}


一看这些代码就蒙了吧?不慌,咱一行一行地解释。

第一行是通过点击的cell来获取该城市相应的城市代码;然后在第二行拼接出相应的网址;第三行使用该网址来生成URL对象;

在第四行我们使用了Almofire中的两个方法,先使用request来发送请求,当参数只有URLConvertible的对象时,request默认使用get方式来发送请求,读者也可以试试其他参数比较多的request方法。然后再使用Almofire的responseJSON方法,读者看到我们连续调用了Almofire的两个方法,会以为它们是不同的对象所有的吧?其实不然,它们都是Almofire的方法,之所以可以连续使用这两个方法,是因为这两个方法最终的返回值都是self,也就是Almofire,这是一个比较舒适的第三方库编程方式,叫做链式编程,这样编程的好处就是可以连续使用其本身的方法而不需要做过多的操作,博主目前还没有完全掌握该方式,只能膜拜大佬。扯多了,我们调用responseJSON方法后,会需要传入一个闭包,闭包有一个DataResponse类型的参数,这个就是从网络获取的返回值了。

在闭包中,我们先使用response的data属性来用获取的JSON二进制数据实例化JSON对象,JSON类是SwiftyJSON的结构体类型,使用SwiftyJSON可以很方便将JSON数据解析。

在if语句当中,我们先将嵌套的JSON数据解析出来,再分别解析自己需要的数据,如果读者不确定返回的JSON数据的格式,可以先打印出来再根据结果解析,或者在浏览器中输入相应网址来获取数据。

我们用JSON数据给weather字符串赋好值之后,就可以弹出第二个界面了,我们先创建WeatherViewController的对象,再给该对象对应的属性赋值,最后用导航栏控制器push出来即可。

到这里,我们就完成了此次作业的要求,来看看最终的效果吧



最后再贴一下所有的代码吧。

ViewController.swift

import UIKit
import Alamofire import SwiftyJSON

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

var tableView: UITableView!
let citise = ["北京": 101010100, "上海": 101020100, "天津": 101030100, "重庆": 101040100, "哈尔滨": 101050101, "长春": 101060101, "沈阳": 101070101, "呼和浩特": 101080101, "石家庄": 101090101, "太原": 101100101, "西安": 101110101, "济南": 101120101, "乌鲁木齐": 101130101, "拉萨": 101140101, "西宁": 101150101, "兰州": 101160101, "银川": 101170101, "郑州": 101180101, "南京": 101190101, "武汉": 101200101, "杭州": 101210101, "合肥": 101220101, "福州": 101230101, "南昌": 101240101, "长沙": 101250101, "贵阳": 101260101, "成都": 101270101, "广州": 101280101, "昆明": 101290101, "南宁": 101300101, "海口": 101310101, "香港": 101320101, "澳门": 101330101, "台北县": 101340101]

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.

self.view.backgroundColor = UIColor.white self.title = "cities" tableView = UITableView(frame: self.view.frame) tableView.delegate = self tableView.dataSource = self self.view.addSubview(tableView)

}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let city = "\(citise[Array(citise.keys)[indexPath.row]]!)" let site = "http://www.weather.com.cn/data/sk/" + city + ".html" let url = URL(string: site) Alamofire.request(url!).responseJSON { (response) in if let json = try? JSON(data: response.data!) { let dict = json["weatherinfo"] let city = dict["city"].string! let temp = dict["temp"].string! let wd = dict["WD"].string! let ws = dict["WS"].string! var weather = "温度: \(temp)\n" weather += "风向: \(wd)\n" weather += "风力: \(ws)" let viewController = WeatherViewController() viewController.navTitle = city viewController.weather = weather self.navigationController?.pushViewController(viewController, animated: true) } } }

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return citise.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { var cell = tableView.dequeueReusableCell(withIdentifier: "Cell") if cell == nil { cell = UITableViewCell(style: .default, reuseIdentifier: "Cell") cell?.accessoryType = .disclosureIndicator } cell?.textLabel?.text = Array(citise.keys)[indexPath.row] return cell! }

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}


WeatherViewController.swift

import UIKit

class WeatherViewController: UIViewController {

var weather: String? var navTitle: String?

override func viewDidLoad() {
super.viewDidLoad()

self.view.backgroundColor = UIColor.white self.title = navTitle let label = UILabel(frame: CGRect(x: 10, y: 100, width: self.view.frame.width - 20, height: self.view.frame.height - 150)) label.text = weather! label.textAlignment = .center label.layer.borderWidth = 1 label.textColor = UIColor.black label.numberOfLines = 0 label.font = UIFont.systemFont(ofSize: 36) self.view.addSubview(label)
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐