欢迎回来,这一章节你会了解到MVC-N设计模式。让我们快速回顾一下MVC设计模式,MVC把文件按照models、views 、controllers.分类
但事实不会这么简单,比如:谁来处理点击事件、谁来处理数据加载、谁来负责把数据展示在View上?
啊哈!这三种类型实际上是重叠的。那么,重叠代码实际上在哪里呢?处理点击事件看起来是controller的任务,所以在controller处理它;数据加载谁来负责呢,好像还是控制器,把model的数据给View赋值呢?好吧,这些工作controller好像都能做,对么?
在你意识到控制器已经很大的时候,控制器已经有几千行代码了,这就是所谓的 massive view controller problem
massive view controller problem 幸好,我们还有办法解决它,当当当当!~~
MVC-N闪亮登场!
MVC-N看起来比MVC更好,毕竟他按类型分成了四部分,四比三多,所以四个比三个更好,对吧,哈哈。
相对于现在demo中使用的复制网络请求代码(这当然是不太好的),MVC—N创建了一个 network client来处理网络请求
Network clients要做的事情用开发术语来说就是:发起网络请求,把相应数据的json数据处理成model模型,然后通过闭包(block)回调传回view controller
在接下来你要对demo开动了,要完成上述内容:创建一个network client,然后把现有的网络请求逻辑放到network client里,最后重构现有的controller来使用我们的network client。
打开demoStart,模拟器运行,点击Get Started,然后你会看到一个Cleaning Services table view controller。
这里有两个选项Home Services和Business Services,我们选第一个(Home Services)。
点击后会presents出来 Home Products View Controller,这个controller会发起一个网络请求来获取Home products信息。
如果网络很快你看不到加载过程的话,不要担心,下拉一下你就会在状态栏看到那个可爱的小菊花了(这当然表示正在进行网络通讯)
我们返回然后选择Business Services同样会presents出Business Products View Controller并通过网络加载Business products数据
让我们打开代码来看看项目现在的情况吧,选择Cleaning Services—> Controllers 组.可以看到Business Products View Controller和Home Products View Controller
这两个类都有load products方法且内容基本一致,唯一的不同就是请求URL的末端不同:Home Products View Controller末端是home Business Products View Controller末端是Business。
错误处理逻辑和json解析逻辑也近乎一摸一样,这样看来重复代码太多太多了。所以我们要使用Model-View-Controller Networking设计模式,并创建一个network client来处理网络请求,使用network client来消除这两个控制器的重复代码。
首先我们要创建一个新的组叫networking,在这之下还要创建两个组Extensions和 Models。
然后打开你下载的课件的根目录--->Resources目录,你会发现几个相关的网络文件,但他们现在还不适用于MVC-N设计模式,需要我们一会稍作修改。现在直接把这些文件拖进project就好了。
首先把Int+HTTPStatusCode和UIImageView+URL拖进Extensions组中不要忘记勾选Copy Items if needed。
然后把NetworkError放到Models中,最后把NetworkClient直接拖进Networking组,搞定!
让我们快速把这几个文件过一眼,Int+HTTPStatusCode提供了一个简单的判断HTTP状态码是否在200-300之间。(即服务器返回请求成功状态)
UIImageView+URL提供了一个通过URL快速设置imgView图片的方法(类似于大家常用的SDImage)如果你看不懂这些代码,don’t panic,这一点也不耽误你学习MVC-N。
注释:discardableResult :在Swift3中,如果没有使用方法的返回值,会报出警告,使用@discardableResult关键字取消警告
Network Error是一个枚举,作用是把 HTTP Status Code error处理成一个简单的模型,方便我们后续使用。
extension NetworkError: Equatable {
public static func ==(lhs: NetworkError, rhs: NetworkError) -> Bool {
return lhs.statusCode == rhs.statusCode
}
}
注释:基本的枚举类型无需实现==就可以就行比较,但是对于非基本enum的 需要重写==运算符。
当然我们最感兴趣的还是network client,因为我们要把现有的网络请求逻辑放在这里
现在这个类只有一个初始化方法shared(),这里通过读取server environments plist获取root url。如果这个地址要经常改变的话,这样比直接写死要好一些,当然这只是个人喜好。实际上你怎么处理都无所谓。
shared()是一个singletons方法,这里不去讨论程序员们对singletons的看法,或好或坏,至少singletons用在这里是没错的。
下一步我们要把重复的网络请求移动到network client里来,首先我们创建一个新的方法
public func getProducts(forType type: Product.ProductType,
success _success: @escaping ([Product]) -> Void,
failure _failure: @escaping (NetworkError) -> Void) {
let success: ([Product]) -> Void = { products in
DispatchQueue.main.async { _success(products) }
}
let failure: (NetworkError) -> Void = { error in
DispatchQueue.main.async { _failure(error) }
}
let url = baseURL.appendingPathComponent("products/\(type.rawValue)")
let task = session.dataTask(with: url, completionHandler: { (data, response, error) in
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode.isSuccessHTTPCode,
let data = data,
let jsonObject = try? JSONSerialization.jsonObject(with: data),
let json = jsonObject as? [[String: Any]] else {
if let error = error {
failure(NetworkError(error: error))
} else {
failure(NetworkError(response: response))
}
return
}
let products = Product.array(jsonArray: json)
success(products)
})
task.resume()
}
需要传入一个product的枚举类型,用来表明我们需要请求哪种数据,是Business还是Home。然后把成功或失败的结果通过闭包(block)在主线程返回。
network client不会关心请求的结果是什么,只是单纯的把数据通过成功或失败的闭包传递出去
让我们快速的过一下这个方法,事实上,我们首先要确保HTTPURLResponse存在,然后验证httpResponse返回了成功的状态码,最后要确保返回的json数组格式正确,如果有任何一项不成立,我们认为网络请求失败,返回请求错误。
最后task.resume()启动任务
OK,到现在我们最后需要做的就是去Business Products View Controller和Home Products View Controller使用我们新写好的这个方法了。
打开 Business Products View Controller,添加一个network client作为属性。然后更新 load products()方法
添加一个network client作为属性 更新后的load products()方法同理,接下来修改Home Products View Controller,唯一的不同是传入的type由business变为product
最后重新运行程序,没有出现任何问题,完美!
还有一些其他小问题留在challenge(在课件文件里)里面你自己去实现吧!
从controller中移除网络请求是解决massive view controller问题一个好的开始,但这样还不能完全解决这个问题,
关注我们接下来的教程,你会学到其他设计模式来继续解决这个问题。
拜拜。
网友评论