Join Bill Weinman for an in-depth discussion in this video Parsing the feed with NSXMLParser, part of iOS SDK and SQLite: Building Data-Driven Apps (2013).
Now that we have an RSS feed, we need to run NSXMLParser to get the title and description of the feed. These will be stored in the database and used for displaying the main feed table view. In this movie, we'll concentrate on parsing the feed. We'll start by making a working copy of BWRSS-addView-03, and I'm going to use the -done version. You can use the version that you worked on in the last movie if you're following along. I'm going to rename this as addView-04 and open it in Xcode by double-clicking on the Xcode project file.
I'm going to come back out to the Finder now, and I'm going to grab this methods.txt file, and I'm just going to select all of this. This is just all of the parser code. And I'll select all with Command+A and Command+C to Copy, and come back here into Xcode and drop it in here at the bottom before the end tag. Command+S to save, and we're going to back up here to connectionDidFinishLoading, and where we have this self parseRSSHeader, I'm going to just uncomment that. And then we're going to come up to haveFeed, which is in our RSS Feed Management. And where we call the delegate haveAddViewRecord-- we haven't implemented that delegate code yet-- I'm going to comment that out.
I'm also going to comment out this dismissViewController so that we can see this result. And I'm going to put in a status message, self statusMessage:@* Have feed, and it's name, which will be from feedRecord kTitleKey, and Command+S to save. Now, let's go ahead and run it in the Simulator. And we'll add that CNN feed again. And we have the feed, and you can see it says, "CNN.com Top Stories," and that means that we are successfully parsing the feed because that's the title of the feed.
So, I'll press Cancel just to dismiss our view controller and come back over here to Xcode and press Command+. to stop the simulator. Let's take a look at the parsing process. Again, this is very simple and straightforward. We call the parser, and the parser starts its process and uses these callback methods, these delegate methods, in order to allow us to control the different parts of the parsing process, and to extract our data where we need to. DidStartDocument allows us to set up our feed record to MutableDictionary. didStartElement gets called at the beginning of each element and allows us to finish up the element before, and to store some data. And you'll notice that there is something here that's not working in iOS 6, and I'll get back to that in a moment.
Parser didEndElement gets called at the end of each element. And again, it allows us to process the data from that element. parser foundCharacters for elements that are containers, this allows us to accumulate date within those containers. And parseErrorOccurred gets called whenever there is an error, and when Abort is called, although that's not working in iOS 6. So, let's come back up here to didEndElement, and you see this if (haveTitle && haveDescription), didFinishParsing = TRUE, and then a call to parser abortParsing.
Now, what's supposed to happen when you call parser abortParsing is you're supposed to get an error message sent to parseErrorOccurred saying that the parsing had been aborted. And this used to work fine and previous versions of this code used this because we're just looking for a few items in the top part of the XML file; we don't need to parse an entire 100k XML file just to find the first few entries in the file, and that's what this is supposed to before. So, when we get our title and our description, we want to just abort at that point and stop wasting everybody's time and energy. And this used to work in previous versions. Starting in beta 4 of iOS 6, this did not work anymore. And I was finding that existing versions of my RSS reader had just stopped working on iOS 6, so I hunted around, I found the problem, and I found the workaround, and I sent a bug report to Apple and they have acknowledged that. But it has not yet been fixed, and we're now on iOS 6.1 as in beta as I'm recording this, and this particular bug still hasn't been fixed.
So, I've just taken it out. We're not doing that anymore. And we're parsing the entire file, although you'll notice that that I set a flag that says didFinishParsing, and I have this in a lot of these methods, if (didFinishParsing), and I just return, so that I'm still not wasting anymore energy than I need to be. So, we're now successfully parsing the header of the RSS feed, and as you can see, this is a lot less complicated than the parser in the item view controller because here, really, we're only looking for a couple of things. The delegation pattern used by NSXML parser and also used by a lot of the Cocoa framework is flexible enough that we can really just pay attention to the parts that matter, giving us the simplicity where we need it or the complexity where we might need that.
- Prototyping the app
- Coding and working with a testbed
- Creating an Objective-C interface for SQLite
- Designing a database schema
- Creating the view controllers
- Reading and writing to the database
- Parsing the RSS feed with NSXMLParser
- Updating the item view with feed items
- Implementing the pull to refresh gesture for iOS 6
- Creating a universal application with multiple views
Skill Level Intermediate
Q: Why is the RSSDB library in the exercise files different than the one in the videos?
<p>A: The RSSDB library had to be updated to work around a bug in the iOS 7 SDK.</p> <p>There is a bug in the iOS 7 SDK that prevents the BWDB fast enumeration implementation from working on a device. The symptom is code that runs fine on the emulator, but not on a device. iOS devices use an ARM processor, while the emulator runs on your Mac's Intel processor. This points to the LLVM ARM code generator as the source of the bug. Because the bug appears to be in the LLVM compiler, it may be some time before it is fixed.</p> <p>As a workaround we have changed the getFeedIDs and getItemIDs methods in the RSSDB library so they don't use Objective C fast enumeration. </p> <p>Please note that this same bug also affects some of the BWDB testbed code in Chapter 2. The result is that it will run on the emulator but not on a device.</p>
Q: After upgrading to Xcode 5.1 I get an error that says: <blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;"> <p>"Used type va_list (aka_builtin_va_list) where arithmetic or pointer type is required"</p> </blockquote>
A: Please download the exercise files again to get the latest version of the BWDB library.
Q: I'm using Xcode 6. Why am I getting error messages with the exercise files?
<div>A: A lot has changed in iOS since this course was released. The author is in the process of rewriting the code and updating the course for iOS 8. In the meantime he has prepared a version of the app that works in iOS 8 and Xcode 6. Download it here: </div> <div> </div> <div>http://ios.bw.org/ </div> <div> </div>