本课主要开发一个天气App,运用58和60课的知识点:从网上下载数据和处理字符串。
课程笔记文集地址:Udemy课程:The Complete iOS 9 Developer Course - Build 18 Apps
1. 找到数据来源,也就是选好网址
网址为:http://www.weather-forecast.com/locations/Paris/forecasts/latest
所以需要去.plist文件里输入:
NSAppTransportSecurity Dictionary (1 item) 这一个item就是-> NSAllowsArbitraryLoads Boolean YES
2.布局storyboard
放置控件,设置好各种Auto Layout的约束,最终效果见下图:
建立 Outlet 和 Action 连接:
@IBOutlet var cityTextField: UITextField!
@IBOutlet var resultLabel: UILabel!
@IBOutlet var findWeather(sender: AnyObject) {
//这是Button的Action连接
}
3.获取网络数据
首先是Lecture 58中学到的代码,几乎没有什么太大的变化,如下:
let url = NSURL(string:"http://www.weather-forecast.com/locations/Paris/forecasts/latest")
let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) -> Void in
//这里的代码都是task完成之后再执行,如果没有完成,则不执行,如果无法执行,也不执行之后的代码
if let urlContent = data {
let webContent = NSString(data: urlContent, encoding: NSUTF8StringEncoding)
print (webContent)
} else {
// 这里可以写出错的提示神马的
}
}
task?.resume()
从打印出来代码可以看出来,我们需要的数据只是其中一行,那么接下来需要做的事情就是把这一行从数据中提取出来。鼠标右键查看源码(谷歌浏览器),比起print(webContent)
更容易阅读。
下图是我们需要的信息:
查看源码之后找到对应的部分:
所有的源码实际上就是webContent
,现在我们只需要这一小部分,那么怎么截取出来呢?
首先用上一节课学到的知识把webContent
分成字符串类型的数组,这样就方便取出需要的字段了。
newTypeString.componentsSeparatedByString("某某字符串")
那我们用哪个字符串来分割webContent
呢?
就是:
3 Day Weather Forecast Summary:
这段放到代码中时要注意双引号的问题,在Swift中,两个双引号之间表示是一个字符串,所以直接复制到代码中后,还需要对代码进行小小的修改,在双引号前面加上 \ 表示这是一个标点符号不是表示字符串:
let websiteArray = webContent?.componentsSeparatedByString("3 Day Weather Forecast Summary: ")
这里最好确保websiteArray
这个数组里真正有内容,如果网页的布局变了,或者网站停止服务了,挂掉了之类的,数组里就不会有值,这样空值出现,会造成应用崩溃,用if确保有值之后再去继续往下走:
if websiteArray!.count > 1 {
print(websiteArray![1])
}
然后继续websiteArray[1]
中的内容,最后得到我们想要的信息:
if websiteArray!.count > 1 {
let weatherArray = websiteArray![1].componentsSeparatedByString("
还是老样子,要确保 weatherArray
这个数组里真的有内容:
if weatherArray!.count > 1 {
let weatherSummary = weatherArray[0]
将weatherSummary赋值给对应的Label控件
}
将weatherSummary赋值给对应的Label控件,这个步骤可以用多线程的方法放到主线程来做:
if weatherArray!.count > 1 {
let weatherSummary = weatherArray[0]
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.resultLabel.text = weatherSummary
})
}
运行之后发现,weatherSummary
里的摄氏度没有显示出来,所以我们用上一节的知识替换出正确的符号:
let weatherSummary = weatherArray[0].stringByReplacingOccurrencesOfString("°", withString:"��¸")
摄氏度的快捷键:Option+Alt+Z
4.更换城市
我们现在使用的是巴黎的天气情况,如果是其他城市的情况怎么办呢?
根据网站上的信息,我们发现,只需要替换网址中的Paris即可。
let url = NSURL(string:"http://www.weather-forecast.com/locations/" +cityTextField.text! +"/forecasts/latest")!
不过输入带有空格的城市如 San Francisco,会造成程序崩溃,解决方法:
let url = NSURL(string:"http://www.weather-forecast.com/locations/" + cityTextField.stringByReplacingOccurrencesOfString(" ", withString:"��-") + "/forecasts/latest")!
输入乱七八糟的字符也会造成崩溃,解决方法:
let attemptedUrl = NSURL(string:"http://www.weather-forecast.com/locations/" + cityTextField.stringByReplacingOccurrencesOfString(" ", withString:"��-") + "/forecasts/latest")!
if let url = attemptedUrl {
//这里继续往下的所有操作
}
5.错误提示
如果用户输入了错误的信息,需要提示一下,我们没有获取到城市信息,不然用户看到程序界面没有变化,以为死掉了呢。
声明一个 wasSuccessful 的布尔值,当为false时,更新Label的内容。
6.完整代码
到这里,代码就已经全部写完了。
全部代码如下:
import UIKit
class ViewController: UIViewController {
@IBOutlet var cityTextField: UITextField!
@IBOutlet var resultLabel: UILabel!
@IBAction func findWeather(sender: AnyObject) {
var wasSuccessful = false
let attemptedUrl = NSURL(string: "http://www.weather-forecast.com/locations/" + cityTextField.text!.stringByReplacingOccurrencesOfString(" ", withString: "-") + "/forecasts/latest")
if let url = attemptedUrl {
let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) -> Void in
if let urlContent = data {
let webContent = NSString(data: urlContent, encoding: NSUTF8StringEncoding)
let websiteArray = webContent!.componentsSeparatedByString("3 Day Weather Forecast Summary: ")
if websiteArray.count > 1 {
let weatherArray = websiteArray[1].componentsSeparatedByString("")
if weatherArray.count > 1 {
wasSuccessful = true
let weatherSummary = weatherArray[0].stringByReplacingOccurrencesOfString("°", withString: "º")
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.resultLabel.text = weatherSummary
})
}
}
}
if wasSuccessful == false {
self.resultLabel.text = "Couldn't find the weather for that city - please try again."
}
}
task.resume()
} else {
self.resultLabel.text = "Couldn't find the weather for that city - please try again."
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}