iOS Design Patterns Part3: MVC-N

   demo传送门

   欢迎回来,这一章节你会了解到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 ServicesBusiness Services,我们选第一个(Home Services)。

   点击后会presents出来 Home Products View Controller,这个controller会发起一个网络请求来获取Home products信息。

   如果网络很快你看不到加载过程的话,不要担心,下拉一下你就会在状态栏看到那个可爱的小菊花了(这当然表示正在进行网络通讯)

   我们返回然后选择Business Services同样会presentsBusiness Products View Controller并通过网络加载Business products数据

   让我们打开代码来看看项目现在的情况吧,选择Cleaning Services—> Controllers 组.可以看到Business Products View ControllerHome 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,在这之下还要创建两个组ExtensionsModels

   然后打开你下载的课件的根目录--->Resources目录,你会发现几个相关的网络文件,但他们现在还不适用于MVC-N设计模式,需要我们一会稍作修改。现在直接把这些文件拖进project就好了。

   首先把Int+HTTPStatusCodeUIImageView+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 ControllerHome Products View Controller使用我们新写好的这个方法了。

   打开 Business Products View Controller,添加一个network client作为属性。然后更新 load products()方法

添加一个network client作为属性
更新后的load products()方法

   同理,接下来修改Home Products View Controller,唯一的不同是传入的typebusiness变为product

   最后重新运行程序,没有出现任何问题,完美!

   还有一些其他小问题留在challenge(在课件文件里)里面你自己去实现吧!
   从controller中移除网络请求是解决massive view controller问题一个好的开始,但这样还不能完全解决这个问题,

   关注我们接下来的教程,你会学到其他设计模式来继续解决这个问题。

   拜拜。

   demo传送门

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,383评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,522评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,852评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,621评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,741评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,929评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,076评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,803评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,265评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,582评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,716评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,395评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,039评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,027评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,488评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,612评论 2 350

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,637评论 18 139
  • PLEASE READ THE FOLLOWING APPLE DEVELOPER PROGRAM LICENSE...
    念念不忘的阅读 13,446评论 5 6
  • 虽然现在是秋天了,落叶飘飘,微风习习,丰收硕果,但在我的世界里,依然春暖花开,嘻嘻嘻嘻,心情好,临摹了两幅作品。 ...
    快乐的Alina阅读 462评论 11 22
  • 一直很喜欢听罗胖讲话,一是因为他每次都以朋友的口吻在讲人话,生动易懂,形象且有趣;二来是有料,即无论讲历史还是身边...
    光华同学阅读 518评论 0 50
  • 守着一段光阴,就像守着一个温良如玉的人。怎么看,都是花好月圆的情分。恋着一程风景,就像恋着一段韵律唯美的诗文,怎么...
    杨柳依依y阅读 223评论 1 1