iOS网络请求(Networking)及处理 Json
我们知道,空格不是 URL 中的有效字符, 除此,还有许多其它特殊字符也不是,例如 < 或 > 符号。因此对特殊字符必须进行转义,即 URL 编码。
例如,我们可以将空格编码为 + 号或字符序列 %20。
幸运的是,String 类现在已经可以进行这种编码了。 因此,我们只需添加一些代码就可以完成 URL 转码:
func iTunesURL(searchText: String) -> URL {
let encodedText = searchText.addingPercentEncoding(
withAllowedCharacters: CharacterSet.urlQueryAllowed)! // Add this
let urlString = String(
format: "https://itunes.apple.com/search?term=%@",
encodedText) // Change this
let url = URL(string: urlString)
return url!
}
以上代码调用 addingPercentEncoding(withAllowedCharacters:) 方法,创建一个新字符串,其中的所有的特殊字符被转码。我们使用这个新字符串进行网络请求。
URL: 'https://itunes.apple.com/search?term=pokemon%20go'
空格被转码为 %20。% 表示转义字符,20 是空格的 UTF-8 值。这里我们还可以尝试转码带有其它特殊字符(例如 # 和 * 甚至 Emoji)的 url,看看会发生什么。
解析 JSON 准备工作
从 Swift 4 开始,Codable 可以解析 JSON 了。
还记得如何使用 PropertyListDecoder 解码支持 Codable 协议的 plist 数据,以读取和保存清单中的数据吗? 好吧,属性列表并不是 Codable 支持的唯一开箱即用格式——它也支持 JSON!
为了让我们的 app 能够将 JSON 数据直接读入相关数据结构,我们需要将它设置为遵守 Codable 协议。
比如 SearchResult.swift:
class ResultArray: Codable {
var resultCount = 0
var results = [SearchResult]()
}
class SearchResult: Codable {
var artistName: String? = ""
var trackName: String? = ""
var name: String {
return trackName ?? ""
}
}
解析 JSON
SearchViewController.swift:
func performStoreRequest(with url: URL) -> Data? { // Change to Data?
do {
return try Data(contentsOf:url) // Change this line
} catch {
. . .
}
}
func parse(data: Data) -> [SearchResult] {
do {
let decoder = JSONDecoder()
let result = try decoder.decode(
ResultArray.self, from: data)
return result.results
} catch {
print("JSON Error: \(error)")
return []
}
}
我们使用 JSONDecoder 对象将来自服务器的响应数据转换为临时 ResultArray 对象,我们可以从中提取 results 属性。
处理 Json,优化如下:
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
if !searchBar.text!.isEmpty {
. . .
print("URL: '\(url)'")
if let data = performStoreRequest(with: url) { // Modified
let results = parse(data: data) // New line
print("Got results: \(results)") // New line
}
tableView.reloadData()
}
}
以上打印出的只是对象,没有显示对象内容。接下来我们继续优化,打印更多详细信息。
打印对象内容信息
修改 SearchResult.swift,令其遵守 CustomStringConvertible 协议:
class SearchResult: Codable, CustomStringConvertible {
CustomStringConvertible 协议允许对象具有自定义字符串表示形式。即,该协议允许对象具有描述对象及其属性的自定义字符串。
修改 SearchResult 类:
var description: String {
return "\nResult - Name: \(name), Artist Name: \(artistName ?? "None")"
}
注意上面代码中 ?? 运算符,它被称为空合( nil-coalescing)运算符。意思是,如果变量有值,则返回该变量,如果没有,则返回 ?? 运算符右侧的值作为默认值。
比如:
let username = loginName ?? "Guest"
loginName 表示为可选性,如果loginName 为空,则使用默认名称 Guest
再次打印,详细信息出来了:
URL: 'https://itunes.apple.com/search?term=Metallica'
Got results: [
Result - Name: Enter Sandman, Artist Name: Metallica,
Result - Name: Nothing Else Matters, Artist Name: Metallica,
Result - Name: The Unforgiven, Artist Name: Metallica,
. . .