zoukankan      html  css  js  c++  java
  • Swift实现糗事百科Demo(实战项目)

    在这里,你将会学习到解析JSON数据,网络请求功能,动态调整cell内容等功能!!!

    最终的结果 是这样的,项目相对简单,很适合入门!下面让我们一起开始教程之旅吧!

    1、先看下项目工程结构:

    第一步:创建Utitlities文件夹,先完成基础通用的辅助功能

    1、网络请求类:HttpRequest.swift

    1. import Foundation  
    2.   
    3. ///  
    4. /// @brief 网络请求相关类  
    5. /// @date  2014-10-09  
    6. /// @author huangyibiao  
    7. ///  
    8. class HttpRequest: NSObject {  
    9.     override init() {  
    10.         super.init()  
    11.     }  
    12.       
    13.     ///  
    14.     /// @brief 把二进制数据转换成JSON格式的数据  
    15.     /// @param data NSDictionary?类型,网络请求返回来的二进制数据  
    16.     /// @return 如果解析成功,返回NSDictionary?类型的JSON数据;如果解析失败,会返回nil  
    17.     ///  
    18.     class func parseJSONData(data: AnyObject?) ->NSDictionary? {  
    19.         if let downloadData: NSData = data as? NSData {  
    20.             var jsonData: AnyObject? = NSJSONSerialization.JSONObjectWithData(downloadData,  
    21.                 options: NSJSONReadingOptions.MutableContainers,  
    22.                 error: nil) as? NSDictionary  
    23.               
    24.             return jsonData as? NSDictionary  
    25.         }  
    26.           
    27.         // 当解析失败时,会返回nil  
    28.         return nil  
    29.     }  
    30.       
    31.     ///  
    32.     /// @brief 异步网络请求方法,需要请求地址参数及回调  
    33.     /// @param urlString 请求地址  
    34.     /// @param completion 请求完成或者请求失败的回调  
    35.     /// @return 请求成功时,会返回NSDictionary?的字典格式的数据,如果请求失败,会返回nil  
    36.     ///  
    37.     class func request(#urlString: String?, completion: (data: NSDictionary?) ->Void) {  
    38.         if urlString == nil {  
    39.             dispatch_async(dispatch_get_main_queue(), { () -> Void in  
    40.                 println("urlstring 为空")  
    41.                 // 请求出现,则返回nil对象表示  
    42.                 completion(data: nil)  
    43.             })  
    44.             return  
    45.         }  
    46.           
    47.         let url = NSURL.URLWithString(urlString!)  
    48.         let request = NSURLRequest(URL: url)  
    49.           
    50.         let queue = NSOperationQueue()  
    51.         NSURLConnection.sendAsynchronousRequest(request, queue: queue) {  
    52.             (response, data, error) -> Void in  
    53.             if error != nil {  
    54.                 dispatch_async(dispatch_get_main_queue(), { () -> Void in  
    55.                     println(error)  
    56.                     // 请求出现,则返回nil对象表示  
    57.                     completion(data: nil)  
    58.                 })  
    59.             } else { // 请求成功,则返回正确的数据  
    60.                 let parseData = self.parseJSONData(data)  
    61.                   
    62.                 dispatch_async(dispatch_get_main_queue(), { () -> Void in  
    63.                     completion(data: parseData)  
    64.                 })  
    65.             }  
    66.         }  
    67.     }  
    68. }  

    2、对String的扩展:
    1. import Foundation  
    2. import UIKit  
    3.   
    4. ///  
    5. /// @brief String的通用扩展方法  
    6. /// @date  2014-10-09  
    7. /// @author huangyibiao  
    8. ///  
    9. extension String {  
    10.     ///  
    11.     /// @brief 获取字符串的高度  
    12.     /// @param fontSize 字体大小  
    13.     /// @param width 限制一行显示的宽度  
    14.     /// @return 返回文本在width宽度的条件下的总高度  
    15.     ///  
    16.     func height(let fontSize: CGFloat, let  CGFloat) ->CGFloat {  
    17.         let font = UIFont.systemFontOfSize(fontSize)  
    18.         let size = CGSizeMake(width, CGFloat.max)  
    19.           
    20.         var style = NSMutableParagraphStyle()  
    21.         style.lineBreakMode = NSLineBreakMode.ByCharWrapping  
    22.           
    23.         var attributes = [NSFontAttributeName: font, NSParagraphStyleAttributeName: style.copy()];  
    24.           
    25.         // 强转成NSString  
    26.         var text = self as NSString  
    27.         var rect = text.boundingRectWithSize(size,  
    28.             options: NSStringDrawingOptions.UsesLineFragmentOrigin,  
    29.             attributes: attributes,  
    30.             context: nil)  
    31.           
    32.         return rect.size.height  
    33.     }  
    34.       
    35.     ///  
    36.     /// @brief 把时间戳转换成“2014年12月12日 8:20:20”格式的日期字符串  
    37.     /// @param timeStamp 时间戳  
    38.     /// @return “2014年12月12日 8:20:20”格式的日期字符串  
    39.     ///  
    40.     func dateStringFromTimeStamp(let timeStamp: NSString) ->String {  
    41.         var formatter = NSDateFormatter()  
    42.         formatter.dateFormat = "yyyy年MM月dd日 HH:MM:ss"  
    43.           
    44.         let date = NSDate(timeIntervalSince1970: timeStamp.doubleValue)  
    45.         return formatter.stringFromDate(date)  
    46.     }  
    47. }  

    3、UIView扩展:
    1. import Foundation  
    2. import UIKit  
    3.   
    4. ///  
    5. /// @brief UIView的扩展方法,方便工程全局使用扩展方法来创建或者使用所有继承于UIView的控件  
    6. /// @date  2014-10-09  
    7. /// @author huangyibiao  
    8. ///  
    9. extension UIView {  
    10.     ///  
    11.     /// 获取或设置origin.x  
    12.     ///  
    13.     func originX() ->CGFloat {  
    14.         return self.frame.origin.x  
    15.     }  
    16.       
    17.     func originX(let originX: CGFloat) {  
    18.         var rect = self.frame  
    19.         rect.origin.x = originX  
    20.         self.frame = rect  
    21.     }  
    22.       
    23.     ///  
    24.     /// 获取或设置origin.y  
    25.     ///  
    26.     func originY() ->CGFloat {  
    27.         return self.frame.origin.y  
    28.     }  
    29.       
    30.     func originY(let originY: CGFloat) {  
    31.         var rect = self.frame  
    32.         rect.origin.y = originY  
    33.         self.frame = rect  
    34.     }  
    35.       
    36.     ///  
    37.     /// 获取或设置origin  
    38.     ///  
    39.     func origin() ->CGPoint {  
    40.         return self.frame.origin  
    41.     }  
    42.       
    43.     func origin(let origin: CGPoint) {  
    44.         var rect = self.frame  
    45.         rect.origin = origin  
    46.         self.frame = rect  
    47.     }  
    48.       
    49.     ///  
    50.     /// 获取或设置width  
    51.     ///  
    52.     func width() ->CGFloat {  
    53.         return self.frame.size.width  
    54.     }  
    55.       
    56.     func width(let  CGFloat) {  
    57.         var rect = self.frame  
    58.         rect.size.width = width  
    59.         self.frame = rect  
    60.     }  
    61.       
    62.     ///  
    63.     /// 获取或设置height  
    64.     ///  
    65.     func height() ->CGFloat {  
    66.         return self.frame.size.height  
    67.     }  
    68.       
    69.     func height(let height: CGFloat) {  
    70.         var rect = self.frame  
    71.         rect.size.height = height  
    72.         self.frame = rect  
    73.     }  
    74.       
    75.     ///  
    76.     /// 获取rightX  
    77.     ///  
    78.     func rightX() ->CGFloat {  
    79.         return originX() + width()  
    80.     }  
    81.       
    82.     ///  
    83.     /// 获取或设置bottomY  
    84.     ///  
    85.     func bottomY() ->CGFloat {  
    86.         return originY() + height()  
    87.     }  
    88.       
    89.     func bottomY(let bottomY: CGFloat) {  
    90.         var rect = self.frame  
    91.         rect.origin.y = bottomY - height()  
    92.         self.frame = rect  
    93.     }  
    94. }  

    第二步:分析好项目的特性,这几个显示的内容格式很像,因此这里使用了同一个基类,这也需要我们先封装一个基类:

    BaseRefreshController

    1. ///  
    2. /// @brief 由HotController、LatestController、TruthController继承,用于  
    3. ///        统一管理数据显示  
    4. /// @data   2014-10-09  
    5. /// @author huangyibiao  
    6. class BaseRefreshController: UIViewController,  
    7.     UITableViewDataSource,  
    8.     UITableViewDelegate,  
    9.     RefreshViewDelegate,  
    10.     JokerCellDelegate {  
    11.     var refreshView: RefreshView?  
    12.     var dataSource = NSMutableArray()  
    13.     var tableView: UITableView?  
    14.     var currentPage: Int = 1  
    15.     var cellIdentifier = "JokerCellIdentifier"  
    16.       
    17.     override func viewDidLoad() {  
    18.         super.viewDidLoad()  
    19.           
    20.         self.automaticallyAdjustsScrollViewInsets = false;  
    21.         self.view.backgroundColor = UIColor.whiteColor()  
    22.         // table view  
    23.         self.tableView = UITableView(frame: CGRectMake(0, 64, self.view.width(), kScreenHeight - 49 - 64))  
    24.         self.tableView?.dataSource = self  
    25.         self.tableView?.delegate = self  
    26.         self.tableView?.separatorStyle = UITableViewCellSeparatorStyle.None  
    27.         self.view.addSubview(self.tableView!)  
    28.         var nib = UINib(nibName: "JokerCell", bundle: nil)  
    29.         self.tableView!.registerNib(nib, forCellReuseIdentifier: cellIdentifier)  
    30.           
    31.         // refresh view  
    32.         var array = NSBundle.mainBundle().loadNibNamed("RefreshView", owner: self, options: nil) as Array  
    33.         self.refreshView = array[0] as? RefreshView  
    34.         self.tableView!.tableFooterView = self.refreshView  
    35.         self.refreshView!.delegate = self  
    36.     }  
    37.       
    38.     ///  
    39.     /// @brief 加载更多数据,此方法由子类调用  
    40.     /// @param urlString 请求地址,其中不指定page值  
    41.     func downloadData(#urlString: String) {  
    42.         let url = "(urlString)(self.currentPage)"  
    43.           
    44.         self.refreshView!.startLoadingMore()  
    45.           
    46.         HttpRequest.request(urlString: url) { (data) -> Void in  
    47.             if data == nil {  
    48.                 UIAlertView.show(title: "温馨提示", message: "加载失败!")  
    49.             } else {  
    50.                 var itemArray = data?["items"] as NSArray  
    51.                   
    52.                 for item: AnyObject in itemArray {  
    53.                     self.dataSource.addObject(item)  
    54.                 }  
    55.                   
    56.                 self.tableView!.reloadData()  
    57.                 self.refreshView!.stopLoadingMore()  
    58.                 self.currentPage++  
    59.             }  
    60.         }  
    61.     }  
    62.       
    63.     ///  
    64.     /// UITableViewDataSource  
    65.     ///  
    66.     func numberOfSectionsInTableView(tableView: UITableView) -> Int {  
    67.         return 1  
    68.     }  
    69.       
    70.     func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {  
    71.         return self.dataSource.count  
    72.     }  
    73.       
    74.     func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {  
    75.         var cell = tableView.dequeueReusableCellWithIdentifier(self.cellIdentifier, forIndexPath: indexPath) as? JokerCell  
    76.           
    77.         cell?.delegate = self  
    78.           
    79.         if indexPath.row < self.dataSource.count {  
    80.             var dataDict = self.dataSource[indexPath.row] as NSDictionary  
    81.             cell?.data = dataDict  
    82.         }  
    83.           
    84.         return cell!  
    85.     }  
    86.       
    87.     ///  
    88.     /// UITableViewDelegate  
    89.     ///  
    90.     func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat {  
    91.         var index = indexPath.row  
    92.         var data = self.dataSource[index] as NSDictionary  
    93.           
    94.         return  JokerCell.cellHeight(data)  
    95.     }  
    96.       
    97.     func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {  
    98.         var index = indexPath.row  
    99.         var data = self.dataSource[index] as NSDictionary  
    100.           
    101.         let comment = CommentController()  
    102.         comment.jokeId = data["id"] as? String  
    103.         self.navigationController?.pushViewController(comment, animated: true)  
    104.     }  
    105.       
    106.     ///  
    107.     /// JokerCellDelegate 代理方法实现  
    108.     ///  
    109.     func jokerCell(cell: JokerCell, didClickPicture picutre: String) {  
    110.         let browser = PhotoBrowserController()  
    111.         browser.bigImageUrlString = picutre  
    112.         self.navigationController?.pushViewController(browser, animated: true)  
    113.     }  
    114. }  

    如果使用的cell不一样,那么子类需要重写对应的代理方法,像查看评论这个就需要重写:

    CommentController:

    1. import UIKit  
    2.   
    3. ///  
    4. /// @brief  查看评价信息  
    5. /// @data   2014-10-09  
    6. /// @author huangyibiao  
    7. class CommentController: BaseRefreshController {  
    8.     // 不可空  
    9.     var jokeId: String?  
    10.       
    11.     override func viewDidLoad() {  
    12.         super.viewDidLoad()  
    13.   
    14.         self.title = "评论"  
    15.         var nib = UINib(nibName: "CommentCell", bundle: nil)  
    16.         self.tableView!.registerNib(nib, forCellReuseIdentifier: "CommentCellIdentifier")  
    17.         self.tableView!.height(kScreenHeight - 64)  
    18.     }  
    19.       
    20.     override func viewWillAppear(animated: Bool) {  
    21.         super.viewWillAppear(animated)  
    22.           
    23.         if let root = self.tabBarController as? RootTabBarController {  
    24.             root.tabBarView?.hidden = true  
    25.         }  
    26.           
    27.         if self.jokeId != nil {  
    28.             downloadData(urlString: "http://m2.qiushibaike.com/article/(self.jokeId!)/comments?count=20&page=")  
    29.         }  
    30.     }  
    31.       
    32.     override func viewWillDisappear(animated: Bool) {  
    33.         super.viewWillDisappear(animated)  
    34.           
    35.           
    36.         if let root = self.tabBarController as? RootTabBarController {  
    37.             root.tabBarView?.hidden = false  
    38.         }  
    39.     }  
    40.       
    41.     ///  
    42.     /// RefreshViewDelegate  
    43.     func refresh(refreshView: RefreshView, didClickButton button: UIButton) {  
    44.         if self.jokeId != nil {  
    45.             downloadData(urlString: "http://m2.qiushibaike.com/article/(self.jokeId!)/comments?count=20&page=")  
    46.         }  
    47.     }  
    48.   
    49.     ///  
    50.     /// UITableViewDataSource  
    51.     ///  
    52.     override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {  
    53.         var cell = tableView.dequeueReusableCellWithIdentifier("CommentCellIdentifier", forIndexPath: indexPath) as? CommentCell  
    54.           
    55.         if indexPath.row < self.dataSource.count {  
    56.             var dataDict = self.dataSource[indexPath.row] as NSDictionary  
    57.             cell?.data = dataDict  
    58.         }  
    59.   
    60.           
    61.         return cell!  
    62.     }  
    63.       
    64.     ///  
    65.     /// UITableViewDelegate  
    66.     ///  
    67.     override func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat {  
    68.         var index = indexPath.row  
    69.         var data = self.dataSource[index] as NSDictionary  
    70.           
    71.         return  CommentCell.cellHeight(data)  
    72.     }  
    73.   
    74.     override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {  
    75.         // 重写而已,以防调用父类的方法  
    76.     }  
    77. }  

    这样封装好以后,下面的最新、热门、真相这三个模块就很简化了:
    1. import Foundation  
    2. import UIKit  
    3.   
    4. ///  
    5. /// @brief 热门 模块视图控制器  
    6. /// @author huangyibiao  
    7. class HotController: BaseRefreshController {  
    8.     ///  
    9.     /// @brief 生命周期函数  
    10.     ///  
    11.     override func viewDidLoad() {  
    12.         super.viewDidLoad()  
    13.           
    14.         self.title = "热门";  
    15.         downloadData(urlString: "http://m2.qiushibaike.com/article/list/suggest?count=20&page=")  
    16.     }  
    17.       
    18.     ///  
    19.     /// RefreshViewDelegate  
    20.     func refresh(refreshView: RefreshView, didClickButton button: UIButton) {  
    21.         downloadData(urlString: "http://m2.qiushibaike.com/article/list/suggest?count=20&page=")  
    22.     }  
    23. }  

    1. import Foundation  
    2. import UIKit  
    3.   
    4. ///  
    5. /// @brief 最新 模块视图控制器  
    6. /// @author huangyibiao  
    7. class LatestController: BaseRefreshController {  
    8.     ///  
    9.     /// @brief 生命周期函数  
    10.     ///  
    11.     override func viewDidLoad() {  
    12.         super.viewDidLoad()  
    13.           
    14.         self.title = "最新";  
    15.         downloadData(urlString: "http://m2.qiushibaike.com/article/list/latest?count=20&page=")  
    16.     }  
    17.       
    18.     ///  
    19.     /// RefreshViewDelegate  
    20.     func refresh(refreshView: RefreshView, didClickButton button: UIButton) {  
    21.         downloadData(urlString: "http://m2.qiushibaike.com/article/list/latest?count=20&page=")  
    22.     }  
    23. }  

    1. import Foundation  
    2. import UIKit  
    3.   
    4. ///  
    5. /// @brief 真相 模块视图控制器  
    6. /// @author huangyibiao  
    7. class TruthController: BaseRefreshController {  
    8.     ///  
    9.     /// @brief 生命周期函数  
    10.     ///  
    11.     override func viewDidLoad() {  
    12.         super.viewDidLoad()  
    13.           
    14.         self.title = "真相";  
    15.         downloadData(urlString: "http://m2.qiushibaike.com/article/list/imgrank?count=20&page=")  
    16.     }  
    17.       
    18.     ///  
    19.     /// RefreshViewDelegate  
    20.     func refresh(refreshView: RefreshView, didClickButton button: UIButton) {  
    21.         downloadData(urlString: "http://m2.qiushibaike.com/article/list/imgrank?count=20&page=")  
    22.     }  
    23. }  

    那么剩下定制cell及动态调整内容就让大家自己去查看源码了!!!!!

    想要源码吗?猛击这里

    版权声明:本文为博主原创文章,未经博主允许不得转载。

     
     
  • 相关阅读:
    asp.net 2.0 treeview控件“简单”操纵
    http://www.cnblogs.com/Terrylee/archive/2006/11/12/aspnet_ajax_quickstarts.html(ajax入门 )
    JS实面treeview中选中父节点,子节点也选中
    系统地学习ASP.NET AJAX(5) 客户端脚本编程(Sys.UI命名空间下的类和快捷方法)(转)
    图例显示投标数据
    怎么用正则表达式判断数字(包括正,负,小数。。)
    treeview常见用法
    TreeView小结
    sql split分隔
    WCF 漫谈
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/4863450.html
Copyright © 2011-2022 走看看