在这篇文章中会使用到四个第三方库,第一个是OC的第三方库Reachability,用来检测当前网络状态。第二个是OC的第三方库MJRefresh,在使用app时,我们经常会遇到上拉刷新或者是下拉加载更多,这个类的作用就是添加下拉刷新的header或者上拉加载更多的footer.第三个是swift的第三方库Kingfisher,作用是用来异步加载图片,第四个是swift的第三方库Alamofire,用于做网络请求。
相关链接
Alamofire做网络请求:
http://www.jianshu.com/p/4723da7eab66
如何使用第三方库:
http://www.jianshu.com/p/734f7b1280f3
Reachability—网络状态的检测
所谓的检测网络状态就是判断是否有网络,网络是否改变,如果有网络,是wifi网络还是3G/4G网络。
- AppDelegate.swift
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var host:Reachability? = nil
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
//添加观察者观察网络状态的改变
NSNotificationCenter.defaultCenter().addObserver(self, selector: "netWorkChangeStatus", name: kReachabilityChangedNotification, object: nil)
//创建一个连接去不断地尝试做网络连接来确定网络的状态是否发生改变(不会联网)
self.host = Reachability(hostName: "www.baidu.com")
self.host?.startNotifier()
return true
}
//网络发生改变的时刻
func netWorkChangeStatus(){
print("当前网络状态:")
//1.拿到当前网络连接状态
let status = Reachability.reachabilityForInternetConnection().currentReachabilityStatus()
//2.判断当前的网络状态
switch status{
case NotReachable:print("没有网络")
case ReachableViaWiFi:print("wifi")
case ReachableViaWWAN:print("3G/4G网络")
default:break
}
}
}
- ViewController
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.test1()
}
//检测当前网络状态
func test1(){
//1.拿到当前网络连接状态
let status = Reachability.reachabilityForInternetConnection().currentReachabilityStatus()
//2.判断当前的网络状态
switch status{
case NotReachable:print("没有网络")
case ReachableViaWiFi:print("wifi")
case ReachableViaWWAN:print("3G/4G网络")
default:break
}
}
}
MJRefresh—上拉刷新,下拉加载更多
在这个第三方库中提供了很多种样式可以选择,详细可以参考这个库里面的README.md文件:
下面的例子使用的是动画效果的header和footer
GET
在使用README.md的时候找到需要使用的效果,然后comand+f搜索跳转到相应的OC代码例子再翻译成swift语言就可以正确使用相应方法了
import UIKit
class ViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
//1.添加下拉刷新
//self.test1()
self.test2()
//2.上拉加载更多
//self.test3()
self.test4()
}
//MARK: - 添加普通下拉刷新控件
func test1(){
//创建普通下拉刷新控件
//会自动在tableView的顶部添加一个刷新控件,当用手拖拽顶部的时候,会自动开始刷新数据
self.tableView.mj_header = MJRefreshNormalHeader(refreshingBlock: { () in
//在这里重新获取最新的数据
print("开始刷新")
//数据获取完成后需要手动停止刷新
//self.tableView.mj_header.endRefreshing()
})
}
//MARK: - 添加帧动画下拉刷新控件
func test2(){
//1.创建header对象
let header = MJRefreshGifHeader(refreshingBlock: { () in
//在这里刷新数据
print("刷新数据")
})
//2.给指定的状态设置帧动画数组
var imagesArray = [UIImage]()
for item in 1...3{
let image = UIImage(named: "ref\(item).png")
imagesArray.append(image!)
}
//参数1:图片数组
//参数2:播放一组动画所需要的时间
//参数3:刷新状态(开始刷新,正在刷新,停止刷新等)
header.setImages(imagesArray, duration: 1, forState: MJRefreshState.Refreshing)
//3.设置heder
self.tableView.mj_header = header
}
//MARK: - 普通上拉加载更多
func test3(){
//在tableView的底部添加一个刷新控件,当cell华到底部的时候,控件会自动显示和刷新
self.tableView.mj_footer = MJRefreshAutoNormalFooter(refreshingBlock: { () in
//在这里一般去请求更多数据
print("开始请求数据")
//请求完成后手动停止
//self.tableView.mj_footer.endRefreshing()
})
}
//MARK: - 添加帧动画上拉加载更多控件
func test4(){
//1.创建footer对象
let footer = MJRefreshAutoGifFooter(refreshingBlock: { () in
//在这里刷新数据
print("刷新数据")
})
//2.给指定的状态设置帧动画数组
var imagesArray = [UIImage]()
for item in 1...3{
let image = UIImage(named: "ref\(item).png")
imagesArray.append(image!)
}
//参数1:图片数组
//参数2:播放一组动画所需要的时间
//参数3:刷新状态(开始刷新,正在刷新,停止刷新等)
footer.setImages(imagesArray, duration: 1, forState: MJRefreshState.Refreshing)
//3.设置heder
self.tableView.mj_footer = footer
}
}
extension ViewController{
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 30
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("cell")
if cell == nil{
cell = UITableViewCell(style: .Subtitle, reuseIdentifier: "cell")
cell?.selectionStyle = .None
}
return cell!
}
}
网络数据展示
需要展示网络数据,首先得有网络数据来源,有服务器接口的可以直接使用接口,也可以使用辅助工具为我们获得数据,利用HTTPScoop可以抓包并获取网页的相关数据,用VisualJSON可以先进行数据解析看是否是我们需要的数据,也可以看数据的类型等信息。
下面的例子用swift的第三方库Alamofire来作数据请求,用swift的第三方库Kingfisher异步加载图片,用OC的第三方库MJRefresh给tableView添加了header和footer,其中mainStoryBoard的视图控制器改成了Navigation Controller,根视图控制器关联成了继承自UITableViewController的MainController,使用的cell是通过Xib创建的。
- MainController
这个页面是首页,主要用于Alamofire网络请求,创建cell及MJRefresh创建header,footer
import UIKit
import Alamofire
class MainController: UITableViewController {
//MARK: - 属性
//1.当前页面
let requestUrl = "http://0.0.0.0:[email protected]/api/articles/hot.json"
//数据源数组
lazy var dataArray:[ArticleModel] = {
return [ArticleModel]()
}()
override func viewDidLoad() {
super.viewDidLoad()
self.title = "首页"
//添加刷新控件(要放到下载数据前面,因为后面要先判断控件再请求数据)
self.addRefView()
//下载数据
self.getData()
//注册cell
self.tableView.registerNib(UINib(nibName: "ArticleCell", bundle: nil), forCellReuseIdentifier: "cell")
self.tableView.rowHeight = 120
}
}
//MARK: - 获取网络数据(异步)
extension MainController{
func getData(){
//判断是否是因为下拉刷新而产生的请求
//是就清空数据源数组,这样self.dataArray.count / 20就等于0,又从最开始的数据开始请求
if self.tableView.mj_header.isRefreshing(){
self.dataArray.removeAll()
}
Alamofire.request(.GET, self.requestUrl, parameters: ["pn":self.dataArray.count / 20,"size":20], encoding: .URL, headers: nil).responseJSON(options: .MutableContainers) { (data) in
print("获取到数据")//测试1
//print(data)
//获取最外层的字典
let json = data.result.value
//获取键对应的值(利用json解析工具看key)
if let tarry = json?.objectForKey("articles"){
let array = tarry as! [NSDictionary]
//print(array)
//遍历数组,拿到字典
for dict in array{
//根据字典创建数据模型
let model = ArticleModel(dict: dict)
//将模型存到数据源数组中
self.dataArray.append(model)
}
//让刷新控件停止刷新 !!!
//如果不停止刷新,就不能进行下一次调用刷新
self.tableView.mj_footer.endRefreshing()
self.tableView.mj_header.endRefreshing()
//刷新tableView !!!
self.tableView.reloadData()
}
}
}
}
//MARK: - tableView协议方法
extension MainController{
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//cell个数不为0才会执行cell的创建与刷新
print(self.dataArray.count)//测试2组合1判断数据
return self.dataArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! ArticleCell
cell.selectionStyle = .None
//刷新数据
//改变model的值会执行cell的didSet异步下载图片
cell.model = self.dataArray[indexPath.row]
return cell
}
//点击cell跳详情页
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let detailC = DetailViewController()
//传值(需要id)
detailC.id = self.dataArray[indexPath.row].id
self.navigationController?.pushViewController(detailC, animated: true)
}
}
//MARK: - 添加刷新控件
extension MainController{
func addRefView(){
//1.添加下拉刷新
self.tableView.mj_header = MJRefreshNormalHeader(refreshingBlock: { () in
//重新请求数据
print("刷新数据")//测试
self.getData()
})
//2.添加上拉加载
self.tableView.mj_footer = MJRefreshAutoNormalFooter(refreshingBlock: { () in
//请求更多数据
print("加载更多")//测试
self.getData()
})
}
}
- DetailViewController
这个页面是详情页,主要用于Alamofire网络请求网页,点击cell的时候会跳转到本页面并显示请求到的对应的网页。
import UIKit
import Alamofire
class DetailViewController: UIViewController {
//MARK: - 属性
var id:String? = nil
//创建webView
let webView = UIWebView()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.whiteColor()
//设置webView的Frame
self.webView.frame = self.view.frame
self.view.addSubview(webView)
self.getData()
}
}
extension DetailViewController{
func getData(){
//1.拼接请求地址
let urlStr = "http://0.0.0.0:[email protected]/api/articles/\(self.id!).json?is_pad=1&need_image_meta=1"
//print(urlStr)//测试
//2.异步请求
Alamofire.request(.GET, urlStr).responseJSON(options: .MutableContainers) { (data) in
//print(data)
//拿到请求结果的值
let json = data.result.value
if let tdict = json?.objectForKey("article"){
//转换成字典
let dict = tdict as! NSDictionary
//a.获取到html代码对应的字符串
let content = dict["content"] as! String
//b.获取网页地址
let urlstr2 = dict["url"] as! String
let url = NSURL(string: urlstr2)
//将网页加载到webView上
//方式1:加载代码字符串(更好)
//参数1:html
//参数2:如果不放心,可以加载网页地址,不需要就nil
//self.webView.loadHTMLString(content, baseURL: url)
//方式2:加载网页
self.webView.loadRequest(NSURLRequest(URL: url!))
}
}
}
}
- ArticleCell
cell中用了一个计算属性,当首页中给cell的model赋值,就会执行didSet里面的代码,改变cell上显示的内容
import UIKit
import Kingfisher
class ArticleCell: UITableViewCell {
//MARK: - 属性
@IBOutlet weak var coverImageView: UIImageView!
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var subTitleLabel: UILabel!
//MARK: - 模型属性
var model:ArticleModel? = nil{
didSet{
//1.通过Kingfisher异步加载网络图片
if let imageurl = model?.img{
//参数1:网络地址
//参数2:默认图片
self.coverImageView.kf_setImageWithURL(NSURL(string: imageurl)!, placeholderImage: nil)
}
//2.其他信息
titleLabel.text = model?.title
subTitleLabel.text = (model?.feed_title)! + " " + (model?.time)!
}
}
}
- ArticleModel—数据模型
import UIKit
class ArticleModel: NSObject {
var id = ""
var feed_title = ""
var img:String? = nil
var time = ""
var title = ""
init(dict:NSDictionary) {
self.id = dict["id"] as! String
self.feed_title = dict["feed_title"] as! String
self.img = dict["img"] as? String
self.time = dict["time"] as! String
self.title = dict["title"] as! String
}
}