这里面使用到第三方库,因此需要使用mix and match特性。
请大家指出其中的错误,谢谢!
rss 阅读器,很简单的代码,只是为了学习Swift语言而写。
1、BaseViewController.swift:
- import Foundation
- import UIKit
- //
- // @brief Each controller must directly or indirectly inherit from BaseViewController to
- // configure.
- // @author huangyibiao
- //
- class BaseViewController : UIViewController {
- // use to config ios7 or later and below ios7
- var _originX: CGFloat = 0.0
- var _screenHeight: CGFloat = 480.0
- var _isIOS7Version = true
- override func viewDidLoad() {
- super.viewDidLoad()
- _isIOS7Version = UIDevice.currentDevice().systemVersion >= "7.0"
- // 难道坐标系统变化了?这么写法反面适配失败了
- //_originX = _isIOS7Version ? 64.0 : 0.0
- // 获取到的屏幕的高度怎么也只有self.view的高度,不是整个屏幕的高度了?
- _screenHeight = UIScreen.mainScreen().bounds.size.height
- }
- override func viewWillAppear(animated: Bool) {
- super.viewWillAppear(animated)
- // config navigations
- let dict = [UITextAttributeTextColor: UIColor.whiteColor()]
- self.navigationController.navigationBar.titleTextAttributes = dict
- self.navigationController.navigationBar.barTintColor = UIColor.orangeColor()
- }
- }
2. need a model: FeedModel.swift
- import Foundation
- //
- // @brief Feed data model, just stores datas
- // @author huangyibiao
- //
- class FeedModel : NSObject, NSCoding {
- var _name: String?
- var _url: String?
- // designated initializer
- init(name: String?, url: String?) {
- super.init()
- _name = name
- _url = url
- }
- //
- // The following functions are NSCoding protocol methods
- //
- // encode
- func encodeWithCoder(aCoder: NSCoder!) {
- aCoder.encodeObject(_name, forKey: "_name")
- aCoder.encodeObject(_url, forKey: "_url")
- }
- // decode
- init(coder aDecoder: NSCoder!) {
- _name = aDecoder.decodeObjectForKey("_name") as? String
- _url = aDecoder.decodeObjectForKey("_url") as? String
- }
- }
3. write an extension: Extension.swift
- import Foundation
- import UIKit
- //------------------------------------------------------------------------------------------
- // @brief extension UIAlertView, making easily to use
- // @author huangyibiao
- //
- extension UIAlertView {
- // @brief Shows an alert view, default showing with "cancel" and "ok" buttons
- // @param title: non-nil String object, shows the title
- // @param message: non-nil String object, shows the message
- // @return return non-nil UIAlertView object
- class func showAlertView(title: String!, message: String!) -> UIAlertView! {
- // in fact, swift provides UIAlerController to do the same thing
- // in the future, it may be replaced by UIAlertController
- let alert = UIAlertView()
- alert.title = title
- alert.message = message
- alert.addButtonWithTitle("Cancel")
- alert.addButtonWithTitle("Ok")
- alert.show()
- return alert
- }
- }
- //------------------------------------------------------------------------------------------
- // @brief 扩展String结构体,追加获取feed缓存路径的方法
- // @author huangyibiao
- //
- extension String {
- // @brief 获取缓存路径
- // @param check: default value is true, meaning that needs to check is exist
- // @return Optional String type, if nil, means no value at all, otherwise, returns path
- //
- static func feedCachePath(isCheck check: Bool = true) -> String? {
- let path = NSHomeDirectory() + "/Documents/data"
- if check {
- if NSFileManager.defaultManager().fileExistsAtPath(path) {
- return path
- }
- }
- return path
- }
- }
4. need a feed manager: FeedManager.swift
- import Foundation
- //
- // @brief Here FeedManager is a singleton, use to manage feed data objects
- // @author huangyibiao
- //
- // never use this global variable directly, because directly using it may not
- // has a value.
- // I don't know how to make it invisible outside in swift
- var g_sharedFeedManager: FeedManager!
- class FeedManager {
- var _dataSource = NSMutableArray() // use to store FeedModel objects
- // singleton
- class func sharedFeedManager() -> FeedManager! {
- if g_sharedFeedManager == nil { // no value
- g_sharedFeedManager = FeedManager()
- }
- return g_sharedFeedManager
- }
- // designated initializer
- init() {
- }
- // return the numbers of feed models
- func count() -> Int {
- return _dataSource.count
- }
- // add model
- func addFeedModel(feedModel: FeedModel!) {
- // found whether is exist
- for model: AnyObject in _dataSource {
- let feedModelObject = model as FeedModel
- if feedModelObject._name == feedModel._name {
- return
- }
- }
- _dataSource.addObject(feedModel)
- saveAllFeeds()
- }
- // remove model
- func removeFeedModel(atIndex index: Int) {
- assert(index >= 0 && index < count(), "out of range in array", file: "Extension.swift", line: 57)
- _dataSource.removeObjectAtIndex(index)
- saveAllFeeds() // update local datas
- }
- // obtain
- func feedModel(atIndex index: Int) -> FeedModel {
- assert(index >= 0 && index < count(), "out of range in array", file: "Extension.swift", line: 57)
- return _dataSource[index] as FeedModel
- }
- func saveAllFeeds() {
- let path = String.feedCachePath(isCheck: false)
- if path { // 若已经存在,先清除
- NSFileManager.defaultManager().removeItemAtPath(path, error: nil)
- }
- // 归档
- NSKeyedArchiver.archiveRootObject(_dataSource, toFile: path)
- }
- func loadAllFeeds() {
- let path = String.feedCachePath()// default isCheck is true
- if path {
- let feedModels = NSKeyedUnarchiver.unarchiveObjectWithFile(path) as? NSArray
- if feedModels {
- _dataSource.addObjectsFromArray(feedModels)
- }
- }
- }
- }
5.need a HttpRequest: HttpRequest.swift
- import Foundation
- @objc protocol HttpRequestDelegate {
- // @brief when request finished, and will call this delegate method if comforms to
- // @param request: an non-nil HttpRequest object
- // @param downloadedData: you can do something with the parameter,
- // which is the data downloaded from ns service
- @optional func requestFinished(request: HttpRequest!, downloadedData: NSMutableData!)
- // @brief fail to download
- @optional func requestFailed(request: HttpRequest!)
- }
- //
- // @brief 网络请示类,这里只是简单实现,没有做缓存处理
- // @author huangyibiao
- //
- class HttpRequest : NSObject, NSURLConnectionDelegate {
- var _delegate: HttpRequestDelegate?
- var _urlString: String?
- var _connection: NSURLConnection?
- var _downloadData: NSMutableData?
- init() {
- super.init()
- _downloadData = NSMutableData()
- }
- // begin to request data
- func startRequest(delegate: HttpRequestDelegate?, urlString: String!) {
- cancelRequest() // cancel current request before a new request
- _delegate = delegate
- _urlString = urlString
- // clear _downloadData
- _downloadData!.resetBytesInRange(NSRange(location: 0, length: _downloadData!.length))
- _downloadData!.length = 0 // update length
- var url = NSURL(string: _urlString)
- var request = NSURLRequest(URL: url)
- _connection = NSURLConnection(request: request, delegate: self)
- _connection!.start()
- }
- func cancelRequest() {
- if _connection {
- _connection!.cancel()
- _connection = nil
- }
- }
- //
- // The following funcs are NSURLConnectionDelegate methods
- // download fail
- func connection(connection: NSURLConnection!, didFailWithError error: NSError!){
- _downloadData!.resetBytesInRange(NSRange(location: 0,length: _downloadData!.length));
- _downloadData!.length = 0;
- _delegate?.requestFailed?(self)
- }
- // receive data and append to the downloaded data
- func connection(connection: NSURLConnection!, didReceiveData data: NSData!){
- _downloadData!.appendData(data);
- }
- // download finished
- func connectionDidFinishLoading(connection: NSURLConnection!){
- _delegate?.requestFinished!(self, downloadedData: _downloadData!);
- }
- }
7.write a root controller: RootViewController.swift
- import Foundation
- import UIKit
- class RootViewController : BaseViewController, UITableViewDelegate, UITableViewDataSource {
- var _tableView: UITableView?
- override func viewDidLoad() {
- self.title="网易Rss"
- let addButton = UIButton(frame: CGRect(x: 0, y: 0, width: 50, height: 40))
- addButton.setTitle("添加", forState: UIControlState.Normal)
- addButton.titleLabel.font = UIFont.systemFontOfSize(12);
- addButton.setTitleColor(UIColor.blackColor(), forState: .Normal);
- addButton.addTarget(self, action: "onAddButtonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
- var addButtonItem = UIBarButtonItem(customView: addButton);
- super.navigationItem.rightBarButtonItem = addButtonItem;
- var aboutButton = UIButton(frame: CGRect(x: 0,y: 0,width: 50,height: 40))
- aboutButton.setTitle("关于", forState: .Normal)
- aboutButton.titleLabel.font = UIFont.systemFontOfSize(12);
- aboutButton.setTitleColor(UIColor.blackColor(), forState: .Normal);
- aboutButton.addTarget(self, action: "onAboutButtonClicked:", forControlEvents: .TouchUpInside)
- var aboutButtonItem = UIBarButtonItem(customView: aboutButton);
- super.navigationItem.leftBarButtonItem = aboutButtonItem;
- _tableView = UITableView(frame: self.view.bounds);
- _tableView!.dataSource = self;
- _tableView!.delegate = self;
- self.view.addSubview(_tableView);
- }
- override func viewWillAppear(animated: Bool) {
- super.viewWillAppear(animated)
- _tableView!.reloadData()
- }
- //
- // The following are UIButton event methods
- //
- // clicke add button
- func onAddButtonClicked(sender: UIButton!) {
- let rss = FeedRssListViewController()
- self.navigationController.pushViewController(rss, animated: true)
- }
- // clicked about button
- func onAboutButtonClicked(sender: UIButton!) {
- // call extension method
- UIAlertView.showAlertView("关于", message: "参考thilong,欢迎学习swift语言,请勿用于商业用途")
- }
- //
- // The following are UITableViewDataSource protocol methods
- //
- func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int{
- return FeedManager.sharedFeedManager().count()
- }
- func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!{
- let cellIdentifier = "cellIdentifier" ;
- var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? UITableViewCell;
- if cell == nil {
- cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: cellIdentifier);
- cell!.selectionStyle = UITableViewCellSelectionStyle.None;
- }
- let model = FeedManager.sharedFeedManager().feedModel(atIndex: indexPath.row)
- cell!.textLabel.text = model._name;
- return cell;
- }
- //
- // The following are UITableViewDelegate protocol methods
- //
- func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!){
- let model = FeedManager.sharedFeedManager().feedModel(atIndex: indexPath.row)
- let detail = RssDetailViewController(model)
- detail.hidesBottomBarWhenPushed = true
- self.navigationController.pushViewController(detail, animated:true);
- }
- }
8.FeedRssListViewController.swift
- import Foundation
- import UIKit
- //
- // @brief Rss contents for selected
- // @author huangyibiao
- //
- class FeedRssListViewController : BaseViewController, UITableViewDelegate, UITableViewDataSource {
- var _tableView: UITableView?
- var _dataSources: Array<FeedModel> = [
- FeedModel(name:"网易新闻", url:"http://news.163.com/special/00011K6L/rss_newstop.xml"),
- FeedModel(name:"网易科技", url:"http://tech.163.com/special/000944OI/headlines.xml"),
- FeedModel(name:"网易NBA", url:"http://sports.163.com/special/00051K7F/rss_sportslq.xml"),
- FeedModel(name:"网易英超", url:"http://sports.163.com/special/00051K7F/rss_sportsyc.xml"),
- FeedModel(name:"网易娱乐", url:"http://ent.163.com/special/00031K7Q/rss_toutiao.xml"),
- FeedModel(name:"网易电影", url:"http://ent.163.com/special/00031K7Q/rss_entmovie.xml"),
- FeedModel(name:"网易互联网", url:"http://tech.163.com/special/000944OI/hulianwang.xml"),
- FeedModel(name:"网易IT界", url:"http://tech.163.com/special/000944OI/kejiyejie.xml"),
- FeedModel(name:"网易汽车", url:"http://auto.163.com/special/00081K7D/rsstoutiao.xml"),
- FeedModel(name:"网易数码", url:"http://tech.163.com/digi/special/00161K7K/rss_digixj.xml"),
- FeedModel(name:"网易笔记本", url:"http://tech.163.com/digi/special/00161K7K/rss_diginote.xml"),
- FeedModel(name:"网易手机", url:"http://mobile.163.com/special/001144R8/mobile163_copy.xml"),
- FeedModel(name:"网易时尚", url:"http://lady.163.com/special/00261R8C/ladyrss1.xml"),
- FeedModel(name:"网易星运", url:"http://lady.163.com/special/00261R8C/ladyrss4.xml"),
- FeedModel(name:"网易游戏", url:"http://game.163.com/special/003144N4/rss_gametop.xml"),
- FeedModel(name:"网易旅游", url:"http://travel.163.com/special/00061K7R/rss_hline.xml")
- ]
- override func viewDidLoad() {
- super.viewDidLoad()
- self.title = "Feed Models"
- // config tableview
- _tableView = UITableView(frame: self.view.bounds);
- self.view.addSubview(_tableView);
- _tableView!.dataSource = self
- _tableView!.delegate = self;
- }
- //
- // @brief The following funcs are UITableViewDataSource protocol methods
- //
- func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int{
- return _dataSources.count;
- }
- func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!{
- let cellIdentifier = "cellIdentifier" ;
- var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? UITableViewCell;
- if cell == nil {
- cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: cellIdentifier);
- cell!.selectionStyle = UITableViewCellSelectionStyle.None;
- }
- let model = _dataSources[indexPath.row] as FeedModel
- cell!.textLabel.text = model._name;
- return cell;
- }
- //
- // @brief The following funcs are UITableViewDelegate protocol methods
- //
- func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!){
- let model = _dataSources[indexPath.row] as FeedModel;
- FeedManager.sharedFeedManager().addFeedModel(model)
- self.navigationController.popViewControllerAnimated(true);
- }
- }
9.RssDetailViewController.swift
- import Foundation
- import UIKit
- //
- // @brief Detail rss content
- // @author huangyibiao
- //
- class RssDetailViewController : BaseViewController, HttpRequestDelegate {
- var _httpRequest: HttpRequest?
- var _webView: UIWebView?
- var _feedModel: FeedModel?
- init(_ feedModel: FeedModel) {
- super.init(nibName: nil, bundle: nil)
- _feedModel = feedModel
- }
- override func viewDidLoad() {
- super.viewDidLoad()
- self.title = _feedModel!._name
- _webView = UIWebView(frame: self.view.bounds)
- self.view.addSubview(_webView)
- _httpRequest = HttpRequest()
- _httpRequest!.startRequest(self, urlString: _feedModel!._url)
- }
- //
- // @brief The following funcs are HttpRequestDelegate protocol methods
- //
- func requestFinished(request: HttpRequest!, downloadedData: NSMutableData!) {
- let doc = GDataXMLDocument(data: downloadedData, options: 0, error: nil)
- if doc == nil {
- UIAlertView.showAlertView("error", message: "read xml file error")
- return;
- }
- var rootElement = doc.rootElement();
- var titleNode = rootElement.nodeForXPath("/rss/channel/title", error: nil);
- var linkNode = rootElement.nodeForXPath("/rss/channel/link", error: nil);
- var channelNode = rootElement.nodeForXPath("/rss/channel", error: nil);
- var items = doc.nodesForXPath("/rss/channel/item", error:nil);
- var entrysBuilder : NSMutableString = NSMutableString();
- var baseHTMLPath : NSString = NSBundle.mainBundle().pathForResource("FeedEntryList",ofType: "html");
- var finalHTML : NSString = NSString.stringWithContentsOfFile(baseHTMLPath,
- encoding: NSUTF8StringEncoding,error: nil);
- for (var i = 0; i < items.count; i++){
- var item = items[i] as GDataXMLElement;
- var itemTitleNode = item.elementsForName("title")[0] as GDataXMLElement;
- var itemDescriptionNode = item.elementsForName("description")[0] as GDataXMLElement;
- var itemUrlNode : GDataXMLElement = item.elementsForName("guid")[0] as GDataXMLElement;
- var entryBuilder : NSMutableString = NSMutableString();
- entryBuilder.appendString("<a href='");
- // link here
- var urlString : NSString! = itemUrlNode.stringValue();
- var stringS = urlString.componentsSeparatedByString("/");
- var finalString : NSString? = stringS[stringS.count - 1] as? NSString;
- if finalString && finalString!.hasSuffix(".html"){
- urlString = NSString(string:"http://3g.163.com/touch/article.html?docid=");
- var docid : NSString = NSString(string:finalString!.stringByReplacingOccurrencesOfString(".html", withString:""));
- urlString = urlString.stringByAppendingFormat("%@",docid);
- }
- entryBuilder.appendString(urlString);
- entryBuilder.appendString("'><div class='entry'><div class='entryTitle'>");
- //title here
- entryBuilder.appendString(itemTitleNode.stringValue());
- entryBuilder.appendString("</div><div class='entryDescription'>");
- //description here
- var description : NSString = itemDescriptionNode.stringValue();
- entryBuilder.appendString(description);
- entryBuilder.appendString("</div></div></a>");
- entrysBuilder.appendString(entryBuilder);
- }
- finalHTML = finalHTML.stringByReplacingOccurrencesOfString("[[ENTRYLIST]]",
- withString: entrysBuilder);
- _webView!.loadHTMLString(finalHTML,baseURL: nil);
- }
- // fail to download
- func requestFailed(request: HttpRequest!) {
- println("request failed" + _feedModel!._url!)
- }
- }
- #import "GDataXMLNode.h"
- #import "JSONKit.h"