Swift实现糗事百科Demo(实战项目)
在这里,你将会学习到解析JSON数据,网络请求功能,动态调整cell内容等功能!!!
最终的结果 是这样的,项目相对简单,很适合入门!下面让我们一起开始教程之旅吧!
1、先看下项目工程结构:
第一步:创建Utitlities文件夹,先完成基础通用的辅助功能
1、网络请求类:HttpRequest.swift
- import Foundation
- ///
- /// @brief 网络请求相关类
- /// @date 2014-10-09
- /// @author huangyibiao
- ///
- class HttpRequest: NSObject {
- override init() {
- super.init()
- }
- ///
- /// @brief 把二进制数据转换成JSON格式的数据
- /// @param data NSDictionary?类型,网络请求返回来的二进制数据
- /// @return 如果解析成功,返回NSDictionary?类型的JSON数据;如果解析失败,会返回nil
- ///
- class func parseJSONData(data: AnyObject?) ->NSDictionary? {
- if let downloadData: NSData = data as? NSData {
- var jsonData: AnyObject? = NSJSONSerialization.JSONObjectWithData(downloadData,
- options: NSJSONReadingOptions.MutableContainers,
- error: nil) as? NSDictionary
- return jsonData as? NSDictionary
- }
- // 当解析失败时,会返回nil
- return nil
- }
- ///
- /// @brief 异步网络请求方法,需要请求地址参数及回调
- /// @param urlString 请求地址
- /// @param completion 请求完成或者请求失败的回调
- /// @return 请求成功时,会返回NSDictionary?的字典格式的数据,如果请求失败,会返回nil
- ///
- class func request(#urlString: String?, completion: (data: NSDictionary?) ->Void) {
- if urlString == nil {
- dispatch_async(dispatch_get_main_queue(), { () -> Void in
- println("urlstring 为空")
- // 请求出现,则返回nil对象表示
- completion(data: nil)
- })
- return
- }
- let url = NSURL.URLWithString(urlString!)
- let request = NSURLRequest(URL: url)
- let queue = NSOperationQueue()
- NSURLConnection.sendAsynchronousRequest(request, queue: queue) {
- (response, data, error) -> Void in
- if error != nil {
- dispatch_async(dispatch_get_main_queue(), { () -> Void in
- println(error)
- // 请求出现,则返回nil对象表示
- completion(data: nil)
- })
- } else { // 请求成功,则返回正确的数据
- let parseData = self.parseJSONData(data)
- dispatch_async(dispatch_get_main_queue(), { () -> Void in
- completion(data: parseData)
- })
- }
- }
- }
- }
2、对String的扩展:
- import Foundation
- import UIKit
- ///
- /// @brief String的通用扩展方法
- /// @date 2014-10-09
- /// @author huangyibiao
- ///
- extension String {
- ///
- /// @brief 获取字符串的高度
- /// @param fontSize 字体大小
- /// @param width 限制一行显示的宽度
- /// @return 返回文本在width宽度的条件下的总高度
- ///
- func height(let fontSize: CGFloat, let width: CGFloat) ->CGFloat {
- let font = UIFont.systemFontOfSize(fontSize)
- let size = CGSizeMake(width, CGFloat.max)
- var style = NSMutableParagraphStyle()
- style.lineBreakMode = NSLineBreakMode.ByCharWrapping
- var attributes = [NSFontAttributeName: font, NSParagraphStyleAttributeName: style.copy()];
- // 强转成NSString
- var text = self as NSString
- var rect = text.boundingRectWithSize(size,
- options: NSStringDrawingOptions.UsesLineFragmentOrigin,
- attributes: attributes,
- context: nil)
- return rect.size.height
- }
- ///
- /// @brief 把时间戳转换成“2014年12月12日 8:20:20”格式的日期字符串
- /// @param timeStamp 时间戳
- /// @return “2014年12月12日 8:20:20”格式的日期字符串
- ///
- func dateStringFromTimeStamp(let timeStamp: NSString) ->String {
- var formatter = NSDateFormatter()
- formatter.dateFormat = "yyyy年MM月dd日 HH:MM:ss"
- let date = NSDate(timeIntervalSince1970: timeStamp.doubleValue)
- return formatter.stringFromDate(date)
- }
- }
3、UIView扩展:
- import Foundation
- import UIKit
- ///
- /// @brief UIView的扩展方法,方便工程全局使用扩展方法来创建或者使用所有继承于UIView的控件
- /// @date 2014-10-09
- /// @author huangyibiao
- ///
- extension UIView {
- ///
- /// 获取或设置origin.x
- ///
- func originX() ->CGFloat {
- return self.frame.origin.x
- }
- func originX(let originX: CGFloat) {
- var rect = self.frame
- rect.origin.x = originX
- self.frame = rect
- }
- ///
- /// 获取或设置origin.y
- ///
- func originY() ->CGFloat {
- return self.frame.origin.y
- }
- func originY(let originY: CGFloat) {
- var rect = self.frame
- rect.origin.y = originY
- self.frame = rect
- }
- ///
- /// 获取或设置origin
- ///
- func origin() ->CGPoint {
- return self.frame.origin
- }
- func origin(let origin: CGPoint) {
- var rect = self.frame
- rect.origin = origin
- self.frame = rect
- }
- ///
- /// 获取或设置width
- ///
- func width() ->CGFloat {
- return self.frame.size.width
- }
- func width(let width: CGFloat) {
- var rect = self.frame
- rect.size.width = width
- self.frame = rect
- }
- ///
- /// 获取或设置height
- ///
- func height() ->CGFloat {
- return self.frame.size.height
- }
- func height(let height: CGFloat) {
- var rect = self.frame
- rect.size.height = height
- self.frame = rect
- }
- ///
- /// 获取rightX
- ///
- func rightX() ->CGFloat {
- return originX() + width()
- }
- ///
- /// 获取或设置bottomY
- ///
- func bottomY() ->CGFloat {
- return originY() + height()
- }
- func bottomY(let bottomY: CGFloat) {
- var rect = self.frame
- rect.origin.y = bottomY - height()
- self.frame = rect
- }
- }
第二步:分析好项目的特性,这几个显示的内容格式很像,因此这里使用了同一个基类,这也需要我们先封装一个基类:
BaseRefreshController
- ///
- /// @brief 由HotController、LatestController、TruthController继承,用于
- /// 统一管理数据显示
- /// @data 2014-10-09
- /// @author huangyibiao
- class BaseRefreshController: UIViewController,
- UITableViewDataSource,
- UITableViewDelegate,
- RefreshViewDelegate,
- JokerCellDelegate {
- var refreshView: RefreshView?
- var dataSource = NSMutableArray()
- var tableView: UITableView?
- var currentPage: Int = 1
- var cellIdentifier = "JokerCellIdentifier"
- override func viewDidLoad() {
- super.viewDidLoad()
- self.automaticallyAdjustsScrollViewInsets = false;
- self.view.backgroundColor = UIColor.whiteColor()
- // table view
- self.tableView = UITableView(frame: CGRectMake(0, 64, self.view.width(), kScreenHeight - 49 - 64))
- self.tableView?.dataSource = self
- self.tableView?.delegate = self
- self.tableView?.separatorStyle = UITableViewCellSeparatorStyle.None
- self.view.addSubview(self.tableView!)
- var nib = UINib(nibName: "JokerCell", bundle: nil)
- self.tableView!.registerNib(nib, forCellReuseIdentifier: cellIdentifier)
- // refresh view
- var array = NSBundle.mainBundle().loadNibNamed("RefreshView", owner: self, options: nil) as Array
- self.refreshView = array[0] as? RefreshView
- self.tableView!.tableFooterView = self.refreshView
- self.refreshView!.delegate = self
- }
- ///
- /// @brief 加载更多数据,此方法由子类调用
- /// @param urlString 请求地址,其中不指定page值
- func downloadData(#urlString: String) {
- let url = "\(urlString)\(self.currentPage)"
- self.refreshView!.startLoadingMore()
- HttpRequest.request(urlString: url) { (data) -> Void in
- if data == nil {
- UIAlertView.show(title: "温馨提示", message: "加载失败!")
- } else {
- var itemArray = data?["items"] as NSArray
- for item: AnyObject in itemArray {
- self.dataSource.addObject(item)
- }
- self.tableView!.reloadData()
- self.refreshView!.stopLoadingMore()
- self.currentPage++
- }
- }
- }
- ///
- /// UITableViewDataSource
- ///
- func numberOfSectionsInTableView(tableView: UITableView) -> Int {
- return 1
- }
- func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- return self.dataSource.count
- }
- func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
- var cell = tableView.dequeueReusableCellWithIdentifier(self.cellIdentifier, forIndexPath: indexPath) as? JokerCell
- cell?.delegate = self
- if indexPath.row < self.dataSource.count {
- var dataDict = self.dataSource[indexPath.row] as NSDictionary
- cell?.data = dataDict
- }
- return cell!
- }
- ///
- /// UITableViewDelegate
- ///
- func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat {
- var index = indexPath.row
- var data = self.dataSource[index] as NSDictionary
- return JokerCell.cellHeight(data)
- }
- func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
- var index = indexPath.row
- var data = self.dataSource[index] as NSDictionary
- let comment = CommentController()
- comment.jokeId = data["id"] as? String
- self.navigationController?.pushViewController(comment, animated: true)
- }
- ///
- /// JokerCellDelegate 代理方法实现
- ///
- func jokerCell(cell: JokerCell, didClickPicture picutre: String) {
- let browser = PhotoBrowserController()
- browser.bigImageUrlString = picutre
- self.navigationController?.pushViewController(browser, animated: true)
- }
- }
如果使用的cell不一样,那么子类需要重写对应的代理方法,像查看评论这个就需要重写:
CommentController:
- import UIKit
- ///
- /// @brief 查看评价信息
- /// @data 2014-10-09
- /// @author huangyibiao
- class CommentController: BaseRefreshController {
- // 不可空
- var jokeId: String?
- override func viewDidLoad() {
- super.viewDidLoad()
- self.title = "评论"
- var nib = UINib(nibName: "CommentCell", bundle: nil)
- self.tableView!.registerNib(nib, forCellReuseIdentifier: "CommentCellIdentifier")
- self.tableView!.height(kScreenHeight - 64)
- }
- override func viewWillAppear(animated: Bool) {
- super.viewWillAppear(animated)
- if let root = self.tabBarController as? RootTabBarController {
- root.tabBarView?.hidden = true
- }
- if self.jokeId != nil {
- downloadData(urlString: "http://m2.qiushibaike.com/article/\(self.jokeId!)/comments?count=20&page=")
- }
- }
- override func viewWillDisappear(animated: Bool) {
- super.viewWillDisappear(animated)
- if let root = self.tabBarController as? RootTabBarController {
- root.tabBarView?.hidden = false
- }
- }
- ///
- /// RefreshViewDelegate
- func refresh(refreshView: RefreshView, didClickButton button: UIButton) {
- if self.jokeId != nil {
- downloadData(urlString: "http://m2.qiushibaike.com/article/\(self.jokeId!)/comments?count=20&page=")
- }
- }
- ///
- /// UITableViewDataSource
- ///
- override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
- var cell = tableView.dequeueReusableCellWithIdentifier("CommentCellIdentifier", forIndexPath: indexPath) as? CommentCell
- if indexPath.row < self.dataSource.count {
- var dataDict = self.dataSource[indexPath.row] as NSDictionary
- cell?.data = dataDict
- }
- return cell!
- }
- ///
- /// UITableViewDelegate
- ///
- override func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat {
- var index = indexPath.row
- var data = self.dataSource[index] as NSDictionary
- return CommentCell.cellHeight(data)
- }
- override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
- // 重写而已,以防调用父类的方法
- }
- }
这样封装好以后,下面的最新、热门、真相这三个模块就很简化了:
- import Foundation
- import UIKit
- ///
- /// @brief 热门 模块视图控制器
- /// @author huangyibiao
- class HotController: BaseRefreshController {
- ///
- /// @brief 生命周期函数
- ///
- override func viewDidLoad() {
- super.viewDidLoad()
- self.title = "热门";
- downloadData(urlString: "http://m2.qiushibaike.com/article/list/suggest?count=20&page=")
- }
- ///
- /// RefreshViewDelegate
- func refresh(refreshView: RefreshView, didClickButton button: UIButton) {
- downloadData(urlString: "http://m2.qiushibaike.com/article/list/suggest?count=20&page=")
- }
- }
- import Foundation
- import UIKit
- ///
- /// @brief 最新 模块视图控制器
- /// @author huangyibiao
- class LatestController: BaseRefreshController {
- ///
- /// @brief 生命周期函数
- ///
- override func viewDidLoad() {
- super.viewDidLoad()
- self.title = "最新";
- downloadData(urlString: "http://m2.qiushibaike.com/article/list/latest?count=20&page=")
- }
- ///
- /// RefreshViewDelegate
- func refresh(refreshView: RefreshView, didClickButton button: UIButton) {
- downloadData(urlString: "http://m2.qiushibaike.com/article/list/latest?count=20&page=")
- }
- }
- import Foundation
- import UIKit
- ///
- /// @brief 真相 模块视图控制器
- /// @author huangyibiao
- class TruthController: BaseRefreshController {
- ///
- /// @brief 生命周期函数
- ///
- override func viewDidLoad() {
- super.viewDidLoad()
- self.title = "真相";
- downloadData(urlString: "http://m2.qiushibaike.com/article/list/imgrank?count=20&page=")
- }
- ///
- /// RefreshViewDelegate
- func refresh(refreshView: RefreshView, didClickButton button: UIButton) {
- downloadData(urlString: "http://m2.qiushibaike.com/article/list/imgrank?count=20&page=")
- }
- }
那么剩下定制cell及动态调整内容就让大家自己去查看源码了!!!!!
想要源码吗?猛击这里
版权声明:本文为博主原创文章,未经博主允许不得转载。
- 上一篇处理文本中的超链接
- 下一篇iOS中用到的3DES密码算法
Swift实现糗事百科Demo(实战项目)的更多相关文章
- 8.Python爬虫实战一之爬取糗事百科段子
大家好,前面入门已经说了那么多基础知识了,下面我们做几个实战项目来挑战一下吧.那么这次为大家带来,Python爬取糗事百科的小段子的例子. 首先,糗事百科大家都听说过吧?糗友们发的搞笑的段子一抓一大把 ...
- Python爬虫实战一之爬取糗事百科段子
大家好,前面入门已经说了那么多基础知识了,下面我们做几个实战项目来挑战一下吧.那么这次为大家带来,Python爬取糗事百科的小段子的例子. 首先,糗事百科大家都听说过吧?糗友们发的搞笑的段子一抓一大把 ...
- Python爬虫实战之爬取糗事百科段子
首先,糗事百科大家都听说过吧?糗友们发的搞笑的段子一抓一大把,这次我们尝试一下用爬虫把他们抓取下来. 友情提示 糗事百科在前一段时间进行了改版,导致之前的代码没法用了,会导致无法输出和CPU占用过高的 ...
- Python爬虫实战之爬取糗事百科段子【华为云技术分享】
首先,糗事百科大家都听说过吧?糗友们发的搞笑的段子一抓一大把,这次我们尝试一下用爬虫把他们抓取下来. 友情提示 糗事百科在前一段时间进行了改版,导致之前的代码没法用了,会导致无法输出和CPU占用过高的 ...
- python scrapy实战糗事百科保存到json文件里
编写qsbk_spider.py爬虫文件 # -*- coding: utf-8 -*- import scrapy from qsbk.items import QsbkItem from scra ...
- 转 Python爬虫实战一之爬取糗事百科段子
静觅 » Python爬虫实战一之爬取糗事百科段子 首先,糗事百科大家都听说过吧?糗友们发的搞笑的段子一抓一大把,这次我们尝试一下用爬虫把他们抓取下来. 友情提示 糗事百科在前一段时间进行了改版,导致 ...
- 芝麻HTTP:Python爬虫实战之爬取糗事百科段子
首先,糗事百科大家都听说过吧?糗友们发的搞笑的段子一抓一大把,这次我们尝试一下用爬虫把他们抓取下来. 友情提示 糗事百科在前一段时间进行了改版,导致之前的代码没法用了,会导致无法输出和CPU占用过高的 ...
- 【Python爬虫实战】多线程爬虫---糗事百科段子爬取
多线程爬虫:即程序中的某些程序段并行执行,合理地设置多线程,可以让爬虫效率更高糗事百科段子普通爬虫和多线程爬虫分析该网址链接得出:https://www.qiushibaike.com/8hr/pag ...
- Python爬虫实战(一):爬糗事百科段子
代码: # _*_ coding:utf-8 _*_ import urllib2 import re from datetime import datetime class QSBK: def __ ...
随机推荐
- Python之路:迭代器和yield生成器
一.迭代器 对于Python 列表的 for 循环,他的内部原理:查看下一个元素是否存在,如果存在,则取出,如果不存在,则报异常 StopIteration.(python内部对异常已处理) 使用迭代 ...
- poj 2096
/** 程序员调bug思路: 一共有四种情况,1. 1个原有的bug 在原有的分类中2. 1个原有的bug 在新的分类中3. 1个新的bug 在原有的分类中4. 1个新bug 在新的分类中 **/ # ...
- poj 3252
http://poj.org/problem?id=3252//自己搞了很长时间...现在刚刚有点明白.. 1 #include <iostream> using namespace st ...
- 蝕刻技術(Etching Technology)
1. 前言 蚀刻是将材料使用化学反应或物理撞击作用而移除的技术. 蚀刻技术可以分为『湿蚀刻』(wet etching)及『干蚀刻』(dry etching)两类.在湿蚀刻中是使用化学溶液,经由化学反应 ...
- html = data.decode('gbk').encode('utf-8')
html = data.decode('gbk').encode('utf-8')此处encode编码要与html文件内charset=utf-8的格式一致,如果不一致,浏览器打开乱码,文本编辑器正常 ...
- ios8 swift开发:显示变量的类名称
var ivar = [:] ivar.className // __NSDictionaryI var i = 1 i.className // error: 'Int' does not have ...
- H面试程序(16): 简单选择排序
#include<stdio.h> #include<assert.h> void display(int * a, int n) { assert(a); for(int i ...
- 新安装的linux(linux mint 或则ubuntu)系统中安装postgresql-xc安装的包
一:./configure的时候1,gcc的处理:sudo apt-get install clang && rvm install 1.9.3 --with-gcc=clang2,缺 ...
- [POJ 1521]--Entropy(哈夫曼树)
题目链接:http://poj.org/problem?id=1521 Entropy Time Limit: 1000MS Memory Limit: 10000K Description A ...
- (Problem 15)Lattice paths
Starting in the top left corner of a 22 grid, and only being able to move to the right and down, the ...