请求推荐数据
请求方式: AFNetworking&Alamofire?
- 目前在iOS开发中, 请求网络数据, 我们经常会使用第三方框架. 而比较出名的莫过于AFNetworking
- 不过AFNetworking是使用OC开发的框架,作者又专门针对Swift开发了另外一个框架就是:Alamofire。
- 因为我们该项目是Swift版本,所有直接采用Alamofire
- 注:其实Alamofire非常强大,不过我们这里只是发送请求,使用起来是非常方便的。
集成Alamofire
- 在iOS开发中,如果我们集成一个第三方框架,通常会使用Cocoapods
- 因此,我们这里通过Cocoapods进行集成
- 找到项目所在目录:
- 打开终端:
- 进入项目目录,执行:
pod init
操作
- 之后会生成Profile文件,打开Profile文件(记事本、Xcode打开即可,推荐Xcode打开)
- 将下面代码粘贴过去
- 回到终端,执行
pod install --no-repo-update
命令
- 关闭程序,通过
工作空间
打开项目
platform :ios, '8.0'
use_frameworks!
target 'DYZB' do
pod 'Alamofire'
end
工具类的封装
- 在实际开发中,为了不过于依赖某一个第三方框架,我们经常会在使用的方式封装到某一个工具类中,以便于某天该框架不更新时不至于很多地方都需要修改。
- 比如之前的ASIHTTPRequest就出现了不更新的情况
- 因此,我们在使用之前先封装一个简单的工具类。之后在其它任何地方发送网络请求,都依赖于自己的工具类。如果某一天该框架不再更新,我们希望更换框架,只修改工具类中代码即可。
- 创建工具类:NetworkTools
- 为工具类提供类方法,方便调用
- 请求时,需要传入请求方式、地址(URL)、参数(parameters)、回调闭包
- 在请求方法中,使用Alamofire发送网络请求
import UIKit
import Alamofire
enum MethodType {
case GET
case POST
}
class NetworkTools {
}
extension NetworkTools {
// 封装请求方法
class func requestData(type : MethodType, urlString : String, parameters : [String : AnyObject], finishedCallback : (result : AnyObject) -> ()) {
// 判断请求范式
let method = type == .GET ? Alamofire.Method.GET : Alamofire.Method.POST
// 发送请求,并且将请求到的数据回调
Alamofire.request(method, urlString, parameters: parameters).responseJSON { (respose) in
guard let result = respose.result.value else {
print(respose.result.error)
return
}
finishedCallback(result: result)
}
}
}
MVVM介绍
- 前面环境配置完成后,我们要请求首页数据。
- 数据请求在哪里发送了?
MVC模式
- Model-View-Controller是一个Apple官方推荐的权威范式。
- 苹果使用的MVC的定义是这么说的:所有的对象都可以被归类为一个model,一个view,或是一个controller。
- 那么把网络代码放哪里?
- 我们知道,因为控制器是一个大管家,那么不知道如何安放的代码就放置在控制器中
- 是的,传统的MVC方式我们经常这么做。
- 该做法的弊端在哪里?
- 由于大量的代码被放进view controller,导致控制器变的相当臃肿。
- 在iOS开发中有的view controller里绵延成千上万行代码的事并不是前所未见的
- 厚重的View Controller很难维护(由于其庞大的规模);包含几十个属性,使他们的状态难以管理;遵循许多协议(protocol),导致协议的响应代码和controller的逻辑代码混淆在一起。
- 那么究竟应该放在哪里?
- 显然MVC的3大组件根本没有适合放这些代码的地方。
MVVM模式
- MVVM来自微软。和MVC很像,并且引入新的组件ViewModel
- view model是一个放置用户输入验证逻辑,视图显示逻辑,发起网络请求和其他各种各样的代码的极好的地方。
- 由于展示逻辑放在了view model中(比如网络请求、请求后的数据解析等等),视图控制器本身就会不再臃肿。
- 因此,该项目中的请求数据,统一交给ViewModel管理。每一个控制器对应一个属于自己的ViewModel。
发送网络请求
接口解析
- 在推荐的数据展示中,有三个请求
- 因此我们需要分别发送三个请求,并且当所有的请求数据拿到之后,对数据进行整理分组排序。(因为界面中有用到分组)
- 因此请求分成五步曲
- 请求游戏数据,并且转成模型对象
- 请求颜值数据,并且转成模型对象
- 请求热门数据,并且转成模型对象
- 对数据进行整理,并且放入大的数组中
- 将数据传递给外面控制器,展示数据
接口描述
参数名称 | 参数说明 |
---|
time | 获取当前时间的字符串 |
limit | 获取数据的个数 |
offset | 偏移的数据量 |
参数名称 | 参数说明 |
---|
time | 获取当前时间的字符串 |
limit | 获取数据的个数 |
offset | 偏移的数据量 |
参数名称 | 参数说明 |
---|
time | 获取当前时间的字符串 |
class RecommendViewModel: NSObject {
lazy var anchorGroups = [AnchorGroup]()
private lazy var hotAnchorGroup = AnchorGroup()
private lazy var prettyAnchorGroup = AnchorGroup()
}
extension RecommendViewModel {
func requestRecommendData(RecommendDataCallback : () -> ()) {
// 0.定义处理闭包
func parserData(result : AnyObject) -> [[String : NSObject]]? {
// 1.将结果转成字典
guard let resultDict = result as? [String : NSObject] else { return nil }
// 2.通过data的key取出对应的数组
return resultDict["data"] as? [[String : NSObject]]
}
// 1.请求热门数据
let group = dispatch_group_create()
dispatch_group_enter(group)
NetworkTools.requestData(.GET, urlString: "http://capi.douyucdn.cn/api/v1/getbigDataRoom", parameters: ["time" : NSDate.getNowTimeString()]) { (result) in
// 1.获取解析的字典数据
guard let dictArray = parserData(result) else { return }
// 2.创建对象
self.hotAnchorGroup.tag_name = "热门"
self.hotAnchorGroup.icon_name = "home_header_hot"
var tempArray = [AnchorModel]()
for dict in dictArray {
tempArray.append(AnchorModel(dict: dict))
}
self.hotAnchorGroup.anchors = tempArray
dispatch_group_leave(group)
}
// 2.请求颜值数据
dispatch_group_enter(group)
NetworkTools.requestData(.GET, urlString: "http://capi.douyucdn.cn/api/v1/getVerticalRoom", parameters: ["limit":"4", "offset" : "0", "time" : NSDate.getNowTimeString()]) { (result) in
// 1.获取解析的字典数据
guard let dictArray = parserData(result) else { return }
// 2.创建对象
self.prettyAnchorGroup.tag_name = "颜值"
self.prettyAnchorGroup.icon_name = "home_header_phone"
var tempArray = [AnchorModel]()
for dict in dictArray {
tempArray.append(AnchorModel(dict: dict))
}
self.prettyAnchorGroup.anchors = tempArray
dispatch_group_leave(group)
}
// 3.请求游戏数据
dispatch_group_enter(group)
NetworkTools.requestData(.GET, urlString: "http://capi.douyucdn.cn/api/v1/getHotCate", parameters: ["limit":"4", "offset" : "0", "time" : NSDate.getNowTimeString()]) { (result) in
// 1.获取解析的字典数据
guard let dictArray = parserData(result) else { return }
// 2.解析数据
for dict in dictArray {
self.anchorGroups.append(AnchorGroup(dict: dict))
}
dispatch_group_leave(group)
}
// 4.所有数据加载完成
dispatch_group_notify(group, dispatch_get_main_queue()) {
self.anchorGroups.insert(self.prettyAnchorGroup, atIndex: 0)
self.anchorGroups.insert(self.hotAnchorGroup, atIndex: 0)
RecommendDataCallback()
}
}
}
展示数据
普通数据展示(文本数据)
- 将数据回调给控制器后,控制器拿到数据展示数据即可
- 在控制器中拿到模型,并且将模型传入给Cell进行展示
图片数据展示
- 在设置网络图片时,OC中经常使用SDWebImage框架。
- 相同的原因,我们使用的Swift项目,因此这里我使用
onevcat
, 也就是喵神
写的Kingfisher
- 在Profile中加入框架, 并且执行安装命令
- pod install —no-repo-update
platform :ios, '8.0'
use_frameworks!
target 'DYZB' do
pod 'Alamofire'
pod 'Kingfisher'
end
srcImageView.kf_setImageWithURL(NSURL(string: anchor?.vertical_src ?? "")!)