本项目借用了某兄弟上传到code4app上的JokerClient源码中的接口,在此先谢谢这位兄弟!
在这里,你将会学习到解析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) }) } } } }
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) } }
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) } }
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=") } }
想要源码吗?猛击这里