使用ReactiveCocoa开发RSS阅读器

目前已经完成的功能有对RSS的解析和Atom解析,RSS内容本地数据库存储和读取,抓取中状态进度展示,标记阅读状态,标记全部已读等。这些功能里我对一些异步操作产生的数据采用了ReactiveCocoa来对数据流向进行了控制,下面我来说下如何运用RAC来进行的开发。

初始时读取本地存储首页列表数据,过滤无效数据,监听列表数据变化进行列表更新

这里会用到RAC这个宏可以方便的来进行键值和信号的绑定,RACObserve这个宏方便的进行键值变化的监听处理。具体实现代码如下:

@weakify(self);

//首页列表数据赋值,过滤无效数据

RAC(self, feeds) = [[[SMDB shareInstance] selectAllFeeds] filter:^BOOL(NSMutableArray *feedsArray) {

if (feedsArray.count > 0) {

return YES;

} else {

return NO;

}

}];

//监听列表数据变化进行列表更新

[RACObserve(self, feeds) subscribeNext:^(id x) {

@strongify(self);

[self.tableView reloadData];

}];

//本地读取首页订阅源数据

- (RACSignal *)selectAllFeeds {

@weakify(self);

return [RACSignal createSignal:^RACDisposable *(id subscriber) {

@strongify(self);

FMDatabase *db = [FMDatabase databaseWithPath:self.feedDBPath];

if ([db open]) {

FMResultSet *rs = [db executeQuery:@"select * from feeds"];

NSUInteger count = 0;

NSMutableArray *feedsArray = [NSMutableArray array];

while ([rs next]) {

SMFeedModel *feedModel = [[SMFeedModel alloc] init];

feedModel.fid = [rs intForColumn:@"fid"];

feedModel.title = [rs stringForColumn:@"title"];

feedModel.link = [rs stringForColumn:@"link"];

feedModel.des = [rs stringForColumn:@"des"];

feedModel.copyright = [rs stringForColumn:@"copyright"];

feedModel.generator = [rs stringForColumn:@"generator"];

feedModel.imageUrl = [rs stringForColumn:@"imageurl"];

feedModel.feedUrl = [rs stringForColumn:@"feedurl"];

feedModel.unReadCount = [rs intForColumn:@"unread"];

[feedsArray addObject:feedModel];

count++;

}

[subscriber sendNext:feedsArray];

[subscriber sendCompleted];

[db close];

}

return nil;

}];

}

通过网络获取订阅源最新内容,获取后进行本地存储,转成显示用的model进行列表的显示

这里的异步操作比较多,而且为了尽快取得数据采用的是并行队列,需要准确的获取到每个源完成的状态,包括解析的完成,本地存储完成,全部获取完成等数据完成情况。具体使用RAC方式的代码如下:

//获取所有feeds以及完成处理

- (void)fetchAllFeeds {

[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

self.tableView.tableHeaderView = self.tbHeaderView;

self.fetchingCount = 0; //统计抓取数量

@weakify(self);

[[[[[[SMNetManager shareInstance] fetchAllFeedWithModelArray:self.feeds] map:^id(NSNumber *value) {

@strongify(self);

NSUInteger index = [value integerValue];

self.feeds[index] = [SMNetManager shareInstance].feeds[index];

return self.feeds[index];

}] doCompleted:^{

//抓完所有的feeds

@strongify(self);

NSLog(@"fetch complete");

//完成置为默认状态

self.tbHeaderLabel.text = @"";

self.tableView.tableHeaderView = [[UIView alloc] init];

self.fetchingCount = 0;

[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

}] deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(SMFeedModel *feedModel) {

//抓完一个

@strongify(self);

//显示抓取状态

self.fetchingCount += 1;

self.tbHeaderLabel.text = [NSString stringWithFormat:@"正在获取%@...(%lu/%lu)",feedModel.title,(unsigned long)self.fetchingCount,(unsigned long)self.feeds.count];

[self.tableView reloadData];

}];

}

//网络获取以及解析本地存储

- (RACSignal *)fetchAllFeedWithModelArray:(NSMutableArray *)modelArray {

@weakify(self);

return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {

@strongify(self);

//创建并行队列

dispatch_queue_t fetchFeedQueue = dispatch_queue_create("com.starming.fetchfeed.fetchfeed", DISPATCH_QUEUE_CONCURRENT);

dispatch_group_t group = dispatch_group_create();

self.feeds = modelArray;

for (int i = 0; i < modelArray.count; i++) {

dispatch_group_enter(group);

SMFeedModel *feedModel = modelArray[i];

dispatch_async(fetchFeedQueue, ^{

[self GET:feedModel.feedUrl parameters:nil progress:nil success:^(NSURLSessionTask *task, id responseObject) {

//解析feed

self.feeds[i] = [self.feedStore updateFeedModelWithData:responseObject preModel:feedModel];

//入库存储

SMDB *db = [[SMDB alloc] init];

[[db insertWithFeedModel:self.feeds[i]] subscribeNext:^(NSNumber *x) {

SMFeedModel *model = (SMFeedModel *)self.feeds[i];

model.fid = [x integerValue];

//插入本地数据库成功后开始sendNext

[subscriber sendNext:@(i)];

//通知单个完成

dispatch_group_leave(group);

}];

} failure:^(NSURLSessionTask *operation, NSError *error) {

NSLog(@"Error: %@", error);

dispatch_group_leave(group);

}];

});//end dispatch async

}//end for

//全完成后执行事件

dispatch_group_notify(group, dispatch_get_main_queue(), ^{

[subscriber sendCompleted];

});

return nil;

}];

}

读取RSS列表,异步读取,主线程更新

这里通过RAC能够很方便的进行主线程操作UI,非主线程操作数据这样的操作,具体实现如下:

//获取列表数据以及对应的操作

- (void)selectFeedItems {

RACScheduler *scheduler = [RACScheduler schedulerWithPriority:RACSchedulerPriorityHigh];

@weakify(self);

[[[[[SMDB shareInstance] selectFeedItemsWithPage:self.page fid:self.feedModel.fid]

subscribeOn:scheduler]

deliverOn:[RACScheduler mainThreadScheduler]]

subscribeNext:^(NSMutableArray *x) {

@strongify(self);

if (self.listData.count > 0) {

//进入时加载

[self.listData addObjectsFromArray:x];

} else {

//加载更多

self.listData = x;

}

//刷新

[self.tableView reloadData];

} error:^(NSError *error) {

//处理无数据的显示

[self.tableView.mj_footer endRefreshingWithNoMoreData];

} completed:^{

//加载完成后的处理

[self.tableView.mj_footer endRefreshing];

}];

self.page += 1;

}

//数据库获取信号

- (RACSignal *)selectFeedItemsWithPage:(NSUInteger)page fid:(NSUInteger)fid {

@weakify(self);

return [RACSignal createSignal:^RACDisposable *(id subscriber) {

@strongify(self);

FMDatabase *db = [FMDatabase databaseWithPath:self.feedDBPath];

if ([db open]) {

//分页获取

FMResultSet *rs = [db executeQuery:@"select * from feeditem where fid = ? and isread = ? order by iid desc limit ?, 20",@(fid), @(0), @(page * 20)];

NSUInteger count = 0;

NSMutableArray *feedItemsArray = [NSMutableArray array];

//设置返回Array里的Model

while ([rs next]) {

SMFeedItemModel *itemModel = [[SMFeedItemModel alloc] init];

itemModel.iid = [rs intForColumn:@"iid"];

itemModel.fid = [rs intForColumn:@"fid"];

itemModel.link = [rs stringForColumn:@"link"];

itemModel.title = [rs stringForColumn:@"title"];

itemModel.author = [rs stringForColumn:@"author"];

itemModel.category = [rs stringForColumn:@"category"];

itemModel.pubDate = [rs stringForColumn:@"pubDate"];

itemModel.des = [rs stringForColumn:@"des"];

itemModel.isRead = [rs intForColumn:@"isread"];

[feedItemsArray addObject:itemModel];

count++;

}

if (count > 0) {

[subscriber sendNext:feedItemsArray];

} else {

//获取出错处理

[subscriber sendError:nil];

}

[subscriber sendCompleted];

[db close];

}

return nil;

}];

}

完整代码可以在这里看:https://github.com/ming1016/GCDFetchFeed

时间: 2024-12-28 00:37:29

使用ReactiveCocoa开发RSS阅读器的相关文章

android rss阅读器开发一点小技巧

这几天一直在学习开发Rss阅读器,遇到一个很坑的问题,InputSource这里总是出错.弄了好久,终于让我找到一个解决方法----看代码: new Thread(){ @Override public void run() { try { URL url = new URL(RSS_URL); SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser();

对下载到RSS阅读器里订阅内容

网络推广方法有很多,RSS推广就是其中的一种,RSS订阅能够为网站增加访问量,这是众人皆知的事实.不过,如何推广RSS,让更多人知道并促使更多人订阅RSS,却是一个很大的问题.下面就有我给大家讲解一下什么事RSS推广,如何利用RSS进行网络推广. 首先来说说什么是RSS? RSS是在线共享内容的一种简单方式(也叫聚合内容,Really Simple Syndication).通常在时效性比较强的内容上使用RSS订阅能更快速获取信息.网站提供RSS输出,有利于让用户获取网站内容的最新信息.网络用户

RSS阅读器&amp;BT sync

①RSS阅读器? 答:RSS阅读器是一种软件或是说一个程序,这种软件可以自由读取RSS和Atom两种规范格式的文档,且这种读取RSS和Atom文档的软件有多个版本,由不同的人或公司开发,有着不同的名字. Really Simple Syndication “真正简单的聚合”就是RSS的英文原意.把新闻标题.摘要(Feed).内容按照用户的要求,“送”到用户的桌面就是RSS的目的. ②BT sync BT sync 是一个文件同步工具,让你在几台不同的设备之间,同步文件.

基于JSP的RSS阅读器

阅读器访问地址:http://easyrss.tk/,欢迎体验! 目录 一.    概述  二.    设计的基本概念和原理  1.    RSS与RSS阅读器概念 2.    阅读器实现原理 三.    设计方案 1.    架构设计 2.    数据库设计 3.    界面设计 4.    功能设计 5.    网络安全补充 四.    主要源代码  1.    视图部分 五.    阅读器使用说明 1.    注册与登录 2.    添加与管理RSS源 3.    阅读文章 概述 获得信息

网易新闻RSS阅读器

首先需要分析网易RSS订阅中心的网页布局情况. 网易RSS订阅中心:http://www.163.com/rss/ 你会发现RSS文件由一个<channel>元素及其子元素组成,除了频道本身内容之外,<channel>还以项的形式包含表示频道元数据的元素. 其中频道下面主要的三个元素就是: 1.title:频道或提要的名称. 2.link:与该频道关联的WEB站点或者站点区域的URL. 3.description:简要介绍该频道是做什么的. 当然还有其他子元素是可选的,比如常用的有

C#版简易RSS阅读器

C#版简易RSS阅读器.由VB版修改完成,感谢aowind的技术支持! 源代码: using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data; using System.Xml; using System.IO; using System.Threading; namespace Yu

那些值得收藏的神奇的网站,使用RSS阅读器订阅喜欢的网站 --授人以鱼不如授人以渔

知识越是分享越是精通.姿势越学习越标准越熟练..咳咳..好邪恶...在分享自己的神器之际把自己淘宝的地方和大家共享,我觉得还是十分有必要的 一些神器的网站 包含放放面面,随机排序: 1.iPc.me    异次元软件世界  师出同门,分享有意思的东西,好软件,IT业界新闻,限免推荐,正版国内代购,推广各种优秀实用软件.网络资源. 2.On HAX 软钥  On HAX是我最喜爱的网站之一,软件xx工具和Serial聚集地.笔者在这上面淘到东西还真不少,小红伞Pro.Revo Uninstalle

SAX实现的简易RSS阅读器

RSS RSS是简易信息聚合,用户可以订阅多个RSS源,从而在不打开网站页面的情况下阅读RSS输出的网站内容. 一个RSS文件就是一段规范的XML数据,如:http://sse.tongji.edu.cn/SSEMainRSS.aspx SAX与DOM SAX(Simple API for XML)是一个事件驱动的顺序访问XML解析API.不同于DOM(Document Object Model)将整个XML文档作为一个整体,SAX解析器按顺序解析XML文档的每个部分. DOM解析器在任何处理开

RSS阅读器

RSS阅读器基本可以分为三类. 第一类大多数阅读器是运行在计算机桌面上的应用程序,通过所订阅网站的新闻供应,可自动.定时地更新新闻标题.在该类阅读器中,有Awasu.FeedDemon和RSSReader这三款流行的阅读器,都提供免费试用版和付费高级版 第二类新闻阅读器通常是内嵌于已在计算机中运行的应用程序中.例如,NewsGator内嵌在微软的Outlook中,所订阅的新闻标题位于Outlook的收件箱文件夹中.另外,Pluck内嵌在Internet Explorer浏览器中! 第三类则是在线