Read iOS Programming: The Big Nerd Ranch Guide, 3/e (Big Nerd Ranch Guides) Online
Authors: Aaron Hillegass,Joe Conway
Tags: #COM051370, #Big Nerd Ranch Guides, #iPhone / iPad Programming
Now that an
RSSChannel
can be copied, you can create the third instance of
RSSChannel
for the store to use for merging the cached and new feeds. In
BNRFeedStore.m
, update
fetchRSSFeedWithCompletion:
.
We can now update
ListViewController
. In
ListViewController.m
, replace the block that is passed to
fetchRSSFeedWithCompletion:
in
fetchEntries
.
When the
ListViewController
makes a request, it will get back its cached copy as usual and update its table. When the request finishes, it will get the merged channel. It can count the number of items in each channel and determine how many new rows to add to the table view, animating each one in.
Build and run the application. Note the items currently in the
BNR
feed. Create a new post and refresh the feed. The new post will slide into the table view instead of just appearing out of nowhere. Pretty cool stuff.
Now that you can cache both RSS feeds, let’s add another useful feature: when the user selects an
RSSItem
, we want the
ListViewController
to add an indicator to the table that shows that this item has been read (
Figure 29.7
). Even if the user closes the application, the list of read items should persist.
Nerdfeed
, then, needs to store the list of read
RSSItem
s on the filesystem.
Figure 29.7 RSSItems marked as read
The simplest way to add this feature would be to add a
hasBeenRead
Boolean instance variable to
RSSItem
. When the user tapped on a row, the corresponding
RSSItem
would change its value of
hasBeenRead
to
YES
. For each row in the table, a checkmark would be displayed if the corresponding
RSSItem
’s
hasBeenRead
variable is
YES
.
In normal circumstances, this is a great approach, but our plan for
Nerdfeed
is more ambitious. We’d like users to be able to use
Nerdfeed
on all of their iOS devices, and if an RSS item is read on one device, then that item should appear as read on every device. Another feature of iOS, iCloud, will allow
Nerdfeed
to do this with minimal effort.
We’ll get into the specifics of iCloud in the next chapter, but here’s a brief introduction. iCloud allows documents to be stored in a user’s iCloud account instead of in the application sandbox. These documents are then available to all of a user’s devices via the cloud. When one device changes one of those documents, every other device sees those changes, so the same application on other devices can read and modify the same document.
While we could store the cached
RSSItem
s in the cloud (along with a
“
hasBeenRead
”
flag), this would be a waste of space and bandwidth. The data for the
RSSItem
s is already available on another server, so there is no reason to redundantly store it in the user’s iCloud account. Instead, the only data that needs to be shared is the
link
of each item that has been read (
Figure 29.8
). (Remember, the
link
of an item is its URL and is what makes an item unique.)
Figure 29.8 Model diagram for read RSSItem
Core Data has iCloud support built in. An application can fetch and insert objects into a Core Data store in the cloud, and other devices will be informed of each change. Thus, maintaining the list of URLs with Core Data will be incredibly efficient: whenever an item is read, its URL will be inserted into the cloud. Other devices will download this small change instead of having to fetch the entire list of read items each time it changes.
In this section, we’ll take care of setting up Core Data and storing its SQLite database locally. In the next chapter, we will make the necessary changes to integrate iCloud support.
First, add the CoreData framework to the
Nerdfeed
target.
Next, add a Core Data model file to
Nerdfeed
and name it
Nerdfeed.xcdatamodeld
(
Figure 29.9
).
Figure 29.9 Adding a Core Data model file
In
Nerdfeed.xcdatamodeld
, add a new entity named
Link
and then add one
String
attribute named
urlString
(
Figure 29.10
).
Figure 29.10 The link entity
It will be
BNRFeedStore
’s job to manage interacting with Core Data (an external source of data). In
BNRFeedStore.h
, import the header for Core Data and add a forward declaration and a few new instance variables and methods.
Before moving on with the implementation, let’s see how it is going to work. Currently, when the user taps on a row that corresponds to an
RSSItem
, the
ListViewController
loads that
RSSItem
into the
WebViewController
to display it. Now, the
ListViewController
will also send the message
markItemAsRead:
to the
BNRFeedStore
with the selected
RSSItem
. The store will grab the
link
from the
RSSItem
and insert it into Core Data.
Also, each time the
ListViewController
reloads its table, it will ask the store,
“
Has this item been marked as read?
”
The store will check with Core Data, and the
ListViewController
will place a checkmark in the row if the corresponding item has been read.
In
BNRFeedStore.m
, add an
init
method to create the appropriate objects for Core Data to work.
This code – which is nearly the same as the code in
Chapter 16
– sets up the context for inserting and fetching objects. This context works with the persistent store coordinator and its SQLite persistent store to save and load objects to the filesystem.
Now on to implementing the two new methods on the store. First, import
RSSItem.h
into
BNRFeedStore.m
.
Then, in
BNRFeedStore.m
, implement
markItemAsRead:
to insert a new
Link
entity into Core Data with the URL of the
RSSItem
’s
link
.
In
BNRFeedStore.m
, implement
hasItemBeenRead:
to return
YES
if the
RSSItem
passed as an argument has its
link
stored in Core Data.