目前有大量 App 都需要进行网络请求,这里讨论一下如何优化网络请求。
我们用 Github 作为服务器,然后用 Alamofire 作为网络请求框架。
对 Github 发起请求,然后取得 Repository (代码库)。
先看一下我们的 Model :
struct Repository {
var name: String! // 库的名称
var language: String! // 汇编语言
var description: String! // 描述
var url: String! // 链接地址
}
然后看一下我们的 ViewController :
class RepositoryTableViewController: UITableViewController {
var user = "beeth0ven", name = "Timer"
private var repository: Repository! {
didSet { updateUI() }
}
@IBOutlet private weak var nameLabel: UILabel!
@IBOutlet private weak var languageLabel: UILabel!
@IBOutlet private weak var descriptionLabel: UILabel!
@IBOutlet private weak var urlLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
repository = Github.getRepository(user: user, name: name)
}
func updateUI() {
nameLabel.text = repository.name
languageLabel.text = repository.language
descriptionLabel.text = repository.description
urlLabel.text = repository.url
}
}
这里先假设服务器在本地,可以直接取得 Repository :
struct Github {
static func getRepository(user user: String, name: String) -> Repository {
var repo = Repository()
repo.name = "Timer"
repo.language = "Swift"
repo.description = "Closure based timer"
repo.url = "https://github.com/beeth0ven/Timer"
return repo
}
}
这里的流程是这样的:
(user, name) -> Repository -> updateUI
在 RepositoryTableViewController 的 viewDidLoad() 方法里,
通过 Github 用户名和 repo 名,取得 Repository,
override func viewDidLoad() {
super.viewDidLoad()
repository = Github.getRepository(user: user, name: name)
}
当得到 Repository 后, 刷新界面.
private var repository: Repository! {
didSet { updateUI() }
}
如果是从服务器取得 Repository 那流程会是这样:
(user, name) -> JSON -> Repository -> updateUI
我们多比较一下本地取值和服务器取值,可以发现,
实际上服务器请求取值比本地多了两个特征:
- 异步
- 可能失败
本地取值立即就可以返回,而服务器则需要花更多时间。
另外如果无法连接互联网,那么服务器就不能返回结果,
这样请求就会失败.
不过要处理这两个特征其实并不难:
struct Github {
static func getRepository(user user: String, name: String) -> Repository {
...
}
}
改为:
struct Github {
static func getRepository(user user: String, name: String,
didGet: (Repository) -> Void,
didFail: (ErrorType) -> Void) {
...
}
}
异步,只需要声明一个 didGet: (Repository) -> Void 的 closure.
失败,只需要声明一个 didFail: (ErrorType) -> Void 的 closure.
那么该方法的详细执行内容是什么:
struct Github {
static func getRepository(user
user: String, name: String,
didGet: (Repository) -> Void,
didFail: (ErrorType) -> Void) {
let baseURLString = "https://api.github.com"
let path = "/repos/\(user)/\(name)"
let url = NSURL(string: baseURLString + path)!
Alamofire
.request(.GET, url)
.responseJSON { response in
switch response.result {
case .Success(let json):
let repository = Repository(json: json)
dispatch_async(dispatch_get_main_queue(), {
didGet(repository)
})
case .Failure(let error):
dispatch_async(dispatch_get_main_queue(), {
didFail(error)
})
}
}
}
}
extension Repository {
init(json: AnyObject) {
if let dictionary = json as? [String: AnyObject] {
self.name = dictionary["name"] as? String
self.language = dictionary["language"] as? String
self.description = dictionary["description"] as? String
self.url = dictionary["html_url"] as? String
}
}
}
使用时,也需要进行微调。
在 RepositoryTableViewController 的 viewDidLoad() 方法需要进行修改:
...
repository = Github.getRepository(user: user, name: name)
...
改为:
...
Github.getRepository(user: user, name: name,
didGet: { repo in self.repository = repo },
didFail: { error in print(error) }
...
结尾
这就是网络请求最基本的形态,其实他和本地取值区别并不大。
此时的代码可以在,分支 Part-1-End 找到。
Part 2,将介绍如何使用 RxSwift 来实现网络请求,
将响应式编程融入到网络请求中!