navigate site menu

Start learning with our library of video tutorials taught by experts. Get started

iOS SDK and SQLite: Building Data-Driven Apps

iOS SDK and SQLite: Building Data-Driven Apps

with Bill Weinman

 


The iOS software development kit (SDK) includes the popular SQLite library, a lightweight yet powerful relational database engine that is easily embedded into an application. In this course, Bill Weinman teaches you how to build an RSS reader for iOS devices, integrating XML data and a streamlined interface. He explains how to use the SQLite database, display information in a table view, code view controllers, and create a preferences pane for your app. The resulting application is optimized for all iPhone and iPad displays.
Topics include:
  • 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

show more

author
Bill Weinman
subject
Developer, Mobile Apps, Databases
software
iOS 6
level
Intermediate
duration
3h 45m
released
Jan 16, 2013

Share this course

Ready to join? get started


Keep up with news, tips, and latest courses.

submit Course details submit clicked more info

Please wait...

Search the closed captioning text for this course by entering the keyword you’d like to search, or browse the closed captioning text by selecting the chapter name below and choosing the video title you’d like to review.



Introduction
Welcome
00:04Hi, I'm Bill Weinman, and welcome to iOS SDK and SQLite Building Data-Driven Applications.
00:11In this course I will show you how to build a solid RSS reader for iOS that supports both
00:16the iPhone and iPad form factors, integrating XML data into a clean and simple presentation.
00:22I'll explain how to use the SQL database, which is included in iOS, and display information
00:29in a clear, intuitive table view.
00:31I'll teach you how to code the necessary view controllers for your application and how to
00:35use the Settings application to provide a Preferences Interface for your users.
00:40Finally, I'll show you how to make a universal app that runs on both phone and tablet form factors for iOS.
00:46Creating an application for iOS doesn't have to be a difficult experience, so let me show
00:51you how in iOS SDK and SQLite Building Data-Driven Applications.
Collapse this transcript
Exercise files
00:00The exercise files for this course are included with your basic lynda.com membership.
00:05If you are a lynda.com member you have access to the exercise files used throughout this title.
00:11Copy the exercise files to a location where you can find them on your system.
00:16Make sure it's a location that doesn't have any spaces in the file path.
00:20Some of Xcode's tools do not work properly if there are spaces in file names.
00:24I have copied them to the desktop on this system.
00:28The exercise files are laid out by Chapter with each folder corresponding to a Chapter in the course.
00:35Within the Chapter folder there are other folders with Xcode projects in them.
00:41An Xcode project will have one or more folders inside of it and a file with the name of the
00:48project followed by .xcodeproj.
00:51You open this project in Xcode by double-clicking on the Xcode project file.
00:56I recommend that you make a working copy of one of these projects before you open it in Xcode.
01:02You can easily do that on a Mac by holding down the Option key and dragging the folder
01:07into an empty space in the containing folder.
01:10When you let go of the mouse button, Finder will make a copy of that entire folder tree
01:15and rename it with a number after it.
01:19Then you simply click on it, maybe click on it again, and Finder will allow you to rename it.
01:27And then you can open that project in Xcode by double-clicking on the Xcode Project file.
01:33Some of the Chapters have files in them that end in .txt, these are text files that contain Objective-C code.
01:41You want to open these in a plain text editor like TextWrangler or BBEdit or another plain
01:46text editor that is not a Word Processor.
01:50Word Processors add other information, other invisible information to your code and make
01:55it unusable in Xcode.
01:57The code in these files will be copied and pasted in the Xcode so that you don't have
02:01to type a lot of code yourself.
02:04The exercise files are here to make you a learning experience easier and more powerful.
02:09Be sure to take the time to read the code and experiment with it, make changes, make mistakes.
02:14There is a lot of code here, take the time to learn with it.
Collapse this transcript
Course overview
00:01iOS is capable of supporting many kinds of applications, games, utilities, social networking,
00:08entertainment, news, business, education.
00:12What do all of these applications have in common? They all use data.
00:17The intent of this course is to show you how to build a data-driven application that uses
00:21an external source of data.
00:24In order to best demonstrate the techniques you'll need to accomplish this, I have built
00:28a simple data-driven application in the form of an RSS news reader.
00:33Many applications drive their content or even their navigation on external data, these are
00:38called data-driven applications.
00:41The application presented here is a simple example of a data-driven application.
00:46The techniques you learn here will apply to many applications in many different categories.
00:52Data sources today are commonly in an XML format and iOS provides native support for XML.
00:59In this application we'll be reading RSS feeds as RSS feeds are typical of many other types
01:06of XML data feeds. The XML portion techniques covered here will apply to many different XML data sources.
01:14After receiving and parsing an XML feed, you will often want to store that data on the device.
01:20The native format for data storage in iOS is provided by the SQLite database engine.
01:25SQLite is a powerful database that is small, fast, and uses a single file for storage.
01:32SQLite is also supported on many other mobile platforms, including Android, Symbian, WebOS, and others.
01:39It has even been ported to Windows Mobile.
01:42The techniques you learn here for supporting SQLite should be usable from many of your mobile projects.
01:49Once you have your data, you'll want to display that data on the screen.
01:53iOS provides a native table view display model, which is commonly used to display data from a database.
02:00Table View is very powerful and flexible, and you will likely use Table View a lot for
02:04you data-driven applications.
02:06Often, external data sources provide links to web pages or other dynamic data.
02:12iOS provides a native web view for displaying web pages with all the power of the internal Safari browser.
02:18RSS feeds typically link to a web page for their associated content.
02:23These days iOS is more than just the iPhone.
02:27So you'll want to learn how to make a universal application that supports iPhone, iPad, and
02:32Retina Displays, leveraging your code to take advantage of these platforms while using a single code base.
02:38I will also show you how to use the iPad's split view controller providing side by side
02:43a Table View for selecting from the database on the left and a web view for displaying
02:48content on the right.
02:50This is all designed to give you the tools you need to use data in your applications,
02:55reading data from an external data source, storing data in a local database on the device,
02:59and using data to provide the necessary user experience for your audience.
Collapse this transcript
Application overview
00:00The application we'll be using for this course is a simple RSS feed reader.
00:05I call it BW RSS, and it's available for free in the App Store.
00:09This app is designed to be simple for the purpose of demonstrating how to retrieve,
00:14parse, store, update, and use data from an external data source on the iOS platform.
00:19It's clean, fast, and reliable, and it's not cluttered with lot of features.
00:25Here is how it works. The main screen has a list of available feeds.
00:29You select one, and it displays a list of items in that feed.
00:34You select an item, and it displays that item in a web view.
00:41You may add a feed by pressing the add feed button, this little plus sign up here.
00:47You can enter the URL of an RSS Feed here or a web page that has a link tagged in the
00:52header with a link to the RSS Feed, this is sometimes called RSS Auto Discovery.
00:57Once you've added a feed, you can use it immediately.
01:10You may delete a feed at any time by pressing the Edit button and selecting the red Delete
01:17icon of the feed you want to delete, or you may delete an item by swiping it.
01:27As new items come in on each feed, older items are automatically deleted.
01:34There's a setting available in the Settings App to select the maximum number of items
01:39retained by the feed.
01:41BW RSS is a universal app, and it works especially well on the large iPad screen.
01:48It uses a split view on the iPad to take a maximum advantage of the iPad's large screen
01:55while conforming to Apple's human interface guidelines.
02:02As we go through the course you'll see how these techniques were coded and how you can
02:06apply them to the applications that you've built for your own purposes and for your clients.
Collapse this transcript
1. An iOS Testbed
Prototyping in a testbed
00:00Sometimes in the course of your work as a programmer you need to try a snippet of
00:04code or test out an idea or even write a simple test suite for a class or a library that you're writing.
00:10For these situations it can be helpful to have a small, simple, flexible base of code
00:14to use as a test bed to test your ideas in.
00:18Here we have such a test bed, and I call it Testbed, and you'll notice if I run this in
00:23the simulator it displays some messages up on a text view here on this iOS Device.
00:32If we look at the code here I have a simple runTest function that puts out messages using
00:37this message function, Testbed version and for id in this array I have a little message
00:44that says object is with the string for each member of the array and right here we have
00:50Testbed Version 1.0, object is Klaatu, barada, nikto, and that's exactly what we have there.
00:56So you can see that this is very simple to test code in.
01:01Now, you could leave the stimulator alone, and you could use NSLog, and that's okay,
01:05and many people do that--and you can certainly do that if you want to--but it's nice to have
01:10the log for errors and the stimulator screen is a lot less cluttered, and it's easy to read this way.
01:16So, this Testbed is easy to build and in fact I've already done a lot of the work for you,
01:21so let's take a moment out from our busy day and build a little Testbed to experiment and learn with.
Collapse this transcript
Building the view controller
00:01The first step in building our Testbed is to create the view controller in interface builder.
00:05So let's create a project in Xcode and get started.
00:09Let's start up Xcode here and under the File menu I'm going to select New > Project.
00:16Under iOS and Application I'm going to select Single View Application and press Next.
00:22The Name of our project will be Testbed, and I leave the Organization Name alone.
00:29Company Identifier, example.com, you'll notice that's in reverse domain notation, and you'll
00:34just use your own domain name, or you'll make something up for it.
00:40Our Class Prefix is Testbed, that's used for building the Class Names and Devices just
00:47the iPhone, and we're going to Use Storyboards, Use ARC, and we do not need Unit Tests for
00:53this, so I press Next.
00:56This is in our exercise files Chap01 and Create, and there is our Testbed application.
01:05So before we can create the view controller and interface builder we need to create an outlet in the code.
01:11So I'm just going to go into the code here, and I'm going to close that on the right so we can see the code.
01:17I'm in the .m File because we're going to create the outlet as part of the private interface,
01:22that's because we don't need it exposed to the public, there is no property, and it's
01:27not in the header file, it's just going to be right here in the .m file.
01:31Under interface I am going to put in some brackets and create the outlet right here.
01:36IBOutlet UITextView, because this is going to be a text view, ViewController and an asterisk
01:45to make it a pointer because objects in Objective-C are Pointers, and I'm going to
01:50call it TextView like that and a semicolon and pressing Command+S on my Mac keyboard
01:55to save this, and we're done.
01:56You notice it creates this little circle over here that we're going to use as an outlet,
02:00and we'll get to that in a moment.
02:02Now I'm going to up here to the Storyboard, and you'll notice--I'm just going to minimize
02:07this controller thing over to the left there because we have limited real estate here on
02:12this display for the purpose of the recording--you'll notice down here at the bottom it says Testbed View Controller.
02:19I'm going to bring the inspector back on the right and show the attributes Inspector.
02:26You notice there's nothing there yet because I haven't selected anything yet.
02:30Under my objects here, so you want to make sure that your Objects tab is selected, under
02:35Objects I'm going to select Data Views, that's what we want.
02:38We want the TextView, which is right here, I'm going to grab a TextView, and I'm going
02:43to drag it on to my View Controller and just get it all lined up just right there.
02:48And now under my Inspector you'll notice that it's got text in it, so I'm just going to
02:52select all of that and delete it.
02:53I'm going to press Enter on my keyboard, and you see all that text goes away in the View.
03:00I am going to uncheck Editable because we don't need this to be actually Editable.
03:06Now I'm going to bring up my Assistant editor, and you'll notice that it brings up the TestbedViewController.h.
03:13We actually want the .m file so I'm going to select the .m File here because there is
03:18outlet, and I just drag that over to the View Controller, and we're done.
03:25So the View Controller now, if I select my View Controller and go over here to the Inspector,
03:29you'll see that my TextView is in the Referencing Outlets, and that's exactly what we want.
03:35So now we've created the View Controller and all that's left is to plug in the code to make it work.
03:40So I'll save this, and we'll plug in the code in the next movie.
Collapse this transcript
Coding the testbed
00:01At this point we have built the text view in the interface builder, and we just need
00:04to plug in the code to make the testbed work.
00:06The results of what I did in the previous movie are in this Testbed-02-done folder,
00:13and that's actually our project folder.
00:15And so I'm going to take that folder, and I'm going to copy it, and I'm going to paste
00:18it into this Chapter 1 folder, and I'm just going to rename it to Testbed-O3, because
00:26this is Movie 3 in this chapter.
00:28And I'm going to open the project by double clicking on Testbed.xcodeproject.
00:32And that will invoke Xcode, and it will open the project.
00:39And I can navigate over here to Testbed View Controller.m, and I'm going to close the Inspector pane.
00:48I'm actually going to close the Assistant Editor as well and just come over here to
00:52the Plain Editor, and that gives the maximum amount of room.
00:55You're on this limited real estate.
00:56You can leave all that stuff open if you like on your screen, because you probably have
01:01a lot more room on your screen than I do.
01:03So, this is our whole view controller class here.
01:06And so, the first thing I'm going to do is I'm going to bring in some library code from our exercise files.
01:12So under Libraries here, I'm going to grab this BWUtilities folder, and I'm just going
01:17to drag it over here into our project.
01:19You see I'm dragging it where it says Testbed, not in any of these other places just right
01:23there in that Testbed folder, and I'm going to let go of it.
01:26And you'll notice here in Xcode, I get this little dialog box.
01:29I want to make sure I select copy items, and create groups for any added folders and Add
01:35to targets has to have Testbed checked.
01:37So, what that does is that it copies the libraries from BWUtilities folder into our project.
01:46If I don't have this checked, then it won't copy, it will just use it in place, and that's
01:51not really what we want.
01:51We want to copy it into the project, and I Create groups for any added folders, and you'll
01:57see what that will do here in a moment.
01:59It will create a group that looks like a folder in this display here.
02:03And Add to targets means it is going to get compiled into this Testbed target, and we
02:08need that in order to be able to use the code.
02:10So, I'm going to say Finish, and there's our BWUtilities folder and just has this BWUtilities.m and BWUutilities.h.
02:18And all this is a few functions that are useful for our Testbed.
02:23Here's the message function and our alert message so we can display alerts, flattenHTML trim string.
02:31These are things that we use throughout the project.
02:33We're also going to use them in the final RSS reader project, or at least some of them.
02:38And then in the h file, we have our interface.
02:41Now, it's not actually a class in the strictest sense.
02:44It's not using object oriented techniques, these are all individual functions, because they
02:49are actually more useful that way, and the way that we are going to be using them.
02:53But the h file exposes this interface to rest of the codes so that we can actually use the
02:58functions in the .m file.
03:00So, I'm going to close that group. So, that's the group that we created.
03:04It looks like a folder in this interface, but it's actually called a group.
03:07Now I'm going to come over here in the TestbedViewController.h, and I'm going to come down here, and I am
03:13going to say import and in the double quotes I'm going to say, "BWUtilities.h", and you
03:19see the code completion is right there already.
03:22And I'm also going to come down here, and I'm going to create a static string.
03:28And I'm going to make it constant. I'm going to call it kTestbed.
03:33So, using a k at the beginning of a variable name means it's a constant.
03:38That's a convention that's often used in Objective-C.
03:41And kTestbedVersion equals and 1.0, and a semi-colon.
03:50I'm going press command S to save this file and then I'm going to switch to the .m file.
03:55So now, we've included our utilities when we created a string for our version.
04:00And under viewDidLoad here, I'm going to just start adding a little bit of code.
04:04First time I'm going to declare an external variable, extern, and it's a UITextView, and
04:13it's a messageTextView.
04:16And you'll notice that that variable is actually declared in our BWUtilities.h, and there it is.
04:24So, what I'm going to do is I'm going to populate that variable so that the utilities knows
04:29where our TextView is so that it can display stuff in our TextView.
04:33So, I'm going to say, messageTextView = textView.
04:40So, that tells the BWUtilities where our textView is so that it can actually post messages to it.
04:47And I'm going to set the font in our textView, so it sets it to a system font of size 12.
04:58And I'm going to run a function called RunTest, which we have not declared yet.
05:01So, I'm going to say self runTest.
05:07And we're going to get a littler error here, because it's not declared yet, and I'm going
05:09to come up here above it, and I'm going to declare it.
05:12I'm going to say (void) runTest, and now, we don't have an error down here anymore,
05:18because we have a function called runTest.
05:20In our runTest, I'm going to display a message, and it is going to say Testbed version, and
05:30I'm going to use our kTestbedVersion variable there.
05:34So, the message function actually is variadic function, it works just like printf does.
05:40You'll notice here in the code it actually calls format.
05:43So, it's a variadic function, it has va_list and va_start just like a normal variadic function
05:49in C and feel free to check out my C and C++ Essential Training for tutorial on how variadic functions work.
05:59And here, it uses NSString initWithFormat, which is very much like format using C, and
06:05it passes at the argument so that it works like a normal variadic function.
06:09So, that allows me to do things like this %@ to display Objective-C object.
06:17So now, we're going to display a series of strings like this.
06:23And this is using the new Objective-C literal object syntax.
06:32So, this is called a boxed array, and it's a much easier way to declare an array than the old way.
06:40So, I can just declare a bunch of strings in here in this array like that, and then
06:45inside in each of the strings I can put some text.
06:49So now we have our little runTest function.
06:54It will display the TestbedVersion, and that constant is declared in our .h file, and it
07:02steps through this boxed array and displays each of these strings individually.
07:07So, when I save this, and I'm going to make sure I've selected the iPhone 6.0 simulator and press Run.
07:16It will go ahead and compile it, Build Succeeded, and it will bring up the simulator, and there it is it's running.
07:24And you'll notice that these messages are now displaying in our text view.
07:29So now, we have a working iOS testbed. I find this a very valuable tool.
07:35Whenever I have a specific task to accomplish, I'll start with the testbed like this one,
07:39and I'll do some prototyping to try out different approaches and decide on a strategy.
07:44This saves me a lot of time and headache that I would otherwise spend trying to debug a
07:48new idea while it's intermingled with other working code.
07:52We'll see an example of how to use this in the next movie.
Collapse this transcript
Using the testbed
00:00So now, I'd like to show you an example of how I've used the Testbed in this application,
00:05so you can get an idea of how to use it yourself.
00:08As I mentioned before, when I have a specific task to accomplish, I'll start with the Testbed
00:13like this one and do some prototyping to figure out what approach to take.
00:17This is an example of a task that I needed to play with in order to understand it well
00:21enough. So, let's open Testbed-dates.
00:25The project is in the Xcode project file, and I'll double-click on that, and that will
00:30open it up in Xcode.
00:32And if we open this up to the source code here, you'll notice in TestbedViewController
00:39everything else is the same.
00:40I'm just going to get rid of that so that we have a little room for the code.
00:45In this runTest function, you'll notice that I have a bunch of date testing codes.
00:50So, I have Testbed version and then date testing.
00:53And I've got a for loop with a boxed array of strings.
00:58And then for each of those strings I'm converting the string to a date format and then I'm displaying
01:04that in a number of different date formats. So, let's Run this in the iPhone simulator.
01:11You'll notice that here are each of those dates and in each of these different formats.
01:16And so, I'm able to play with my approach for how it is that I want to accomplish this
01:20task and see the results in real time here on the simulator screen.
01:26So like I've said, the Testbed is a useful tool, it's not an essential tool.
01:29You can use NSLong for the same purpose.
01:31But it is useful, and I use it a lot in my iOS development work, and we'll be using it later in this course.
01:37I hope you find it a useful tool for your projects as well.
Collapse this transcript
2. Building a Database Library
Understanding SQLite in iOS
00:01SQLite is a full featured relational database.
00:04It's small, it's fast, it's lightweight, and it's perfectly suited for mobile applications.
00:09The SQLite Database Management System lives entirely in a driver.
00:15This means that there is no server and no client.
00:17You access the database directly.
00:20The database itself is fully contained in one file.
00:24This makes it very convenient to use in a mobile environment.
00:28To say that iOS supports SQLite natively is to say that the driver is built-in, the interface
00:35to the driver is written in C, so it's not Object Oriented, and it's not an Objective-C Interface.
00:42To make it easier to use, we will build a Native Object Oriented Interface for SQLite in Objective-C.
00:49This kind of interface is sometimes called a Wrapper as it wraps one interface around another.
00:55It's designed to be convenient and easy for our development purposes.
00:59It's general purpose, so you can use it in your future projects.
01:03You have the source code, and you may modify it and expand it to suite your needs.
01:08To further support the iOS Model-View-Controller architecture, we will build a more specific
01:12interface on top of our general interface.
01:15We will do this by subclassing our general interface and adding methods to specifically
01:20support this application.
01:22This makes it very easy for us to integrate the database into our application.
01:27Subclassing a normalized interface like this is a common and valuable technique in an object-oriented environment.
01:33As you follow along with the development process in this chapter, think about how you will
01:37use and expand on these techniques in your own projects.
Collapse this transcript
Creating an Objective-C interface for SQLite
00:00The native SQLite interface is written in C, and while it works very well, it's not very
00:05convenient in an Objective-C environment.
00:08So, we will begin by writing a wrapper, which is sometimes called an Adapter Pattern, to
00:13encapsulate the C Language SQLite interface in a native Objective-C interface that's easy
00:19to use and to extend for our purposes.
00:22So first, let's take a look at what we want this interface to accomplish.
00:26I'm just going to open this BWDB-testbed-code.txt, in my text editor, I'm using TextWrangler here.
00:33You can use whatever editor you like just make sure it's a real plain text editor and not a Word Processor.
00:39So, you'll notice here is the testDatabase function.
00:46And this is the method that I'm going to be using to test this database interface, and
00:50so it shows how the interface is called.
00:53And really my goal was to have an interface that works like this.
00:56So for instance, I can have something, that you know, sends a message to the db object that says doQuery
01:02and in a string it has an SQL query "drop table if it exists", CREATE TABLE with this
01:09schema, insert into table, values this and that, and you notice that there are place
01:13markers and then there are various values.
01:17These are actually Objective-C objects that are used as arguments.
01:22And so, my interface has to support what we call variadic arguments in C-based languages.
01:29And so, with variadic arguments I can have as many, or as few, of these arguments as I
01:34like after the string that has the format in it, and specifies how many arguments I'm
01:41going to actually be needing.
01:44My interface also allows me to do something like this for row in and then I have this
01:49expression here that calls this method getQuery on the db object and has a query in it.
01:56And so, what that will do is it will actually go through the database and get one row at
02:01a time and pass those rows off into this row variable and allow me to operate on that.
02:06It's a very convenient syntax for calling, and it's accomplished in Objective-C with
02:11a protocol called NSFastEnumeration, and we'll see how that's done as well.
02:16We also have these CRUD-based methods where I can do something like insertRow and then have a dictionary.
02:23This is a literal dictionary using the new Objective-C literal syntax.
02:28And I can just pass it a dictionary object, and it will insert that row into a table that
02:35has already been specified in the constructor.
02:39So, I have CRUD insert, here is a CRUD update and here is a CRUD delete.
02:46So, that's how we want to be able to use this.
02:49Let's go ahead and create an interface that will do exactly this.
02:53We're going to start by navigating to the Chapter02 folder in the exercise files.
02:57And we're going to make a working copy of Testbed.
03:01I'm just going to press Command+C on this Mac and select my folder and press Command+V,
03:07and that will allow me to make a working copy here.
03:09And I'm going to call this Testbed-02-working, and I'm going to open it up by navigating
03:15to the Xcode project file inside of that folder and double-clicking.
03:19So, this is actually our finished Testbed from the previous chapter.
03:24You notice if I select the iPhone Simulator and press Run, it will build, and it will
03:30run it in the iPhone Simulator.
03:34And you can see this is exactly the same Testbed that we had in the last chapter.
03:38So, I'm going to come back over here to Xcode, I'm going to press Command+Period
03:42to stop these simulators, here it says Finished running the simulator.
03:46Now, we're going to select the target, so we select Testbed up here in the top of the Project navigator.
03:54And then, I will select Target over here and Summary over here, and scroll down for a while,
04:00and you see we have these Linked Frameworks.
04:02We're going to add a framework for our SQLite here.
04:04So, I'm going to press the plus button, and I'm going to type, sqlite in the Search there, sql was enough.
04:12I'm going to select sqlite 3. dynamic library and click Add.
04:17And now, you'll notice that there it is in our frameworks, and we've added the sqlite.dylib
04:21to our Link Frameworks.
04:25And then down here in our Testbed files, we want to add our database library.
04:31So, I've got a library called BWDB in the exercise files.
04:34So, we come back out here in the exercise files and select Libraries, and just grab the BWDB folder.
04:41You'll notice inside that folder there are just a couple of files: a .m file
04:44and a .h file. We'll take a look at those in a little bit here.
04:47So, we're going to grab this whole folder, and we're going to bring it over here until
04:52Testbed is highlighted.
04:53You see, you can highlight different things here, and you want to highlight Testbed in
04:58the folder version of it there, and it will then drop that in right there.
05:03Brings up this dialog box, you want to select Copy items, Create groups, and Add to targets
05:09for Testbed, and Finish.
05:11And so, it copies those files, it creates a group for them called BWDB, and there are
05:16the files, there's the m file which is the implementation and the h file which is the header file.
05:21Let's just take a quick look here.
05:24The header file has our interface, you notice it I reads in the sqlite3.h header file from
05:30the SQLite 3 Framework that we imported earlier.
05:33And you'll notice down here, we have our actual interface.
05:39We have a constructor with Filename, a constructor with a Filename and a TableName that's used
05:44for the CRUD methods.
05:46We have an openDB, closeDB, a d structure-- dealloc is a d structure--and it basically
05:51just closes the database. We have Fast enumeration support.
05:55That allows us to do that trick where we put the object in an enumeration for loop.
06:00We have SQL queries, doQuery, getQuery, prepareQuery, valueFromQuery.
06:05And you notice these have the variadic arguments.
06:08If you want to know more about variadic arguments in C-based languages, you can take a look
06:12at my C and C++ Essential Training on the lynda.com online training library.
06:19These raw results are pretty much just used internally to translate these variadic queries
06:25into something that will return a value. And then, here we have the CRUD methods.
06:30This is the heart and soul of this.
06:31We can insert a row, update a row, delete a row, get a row, and count rows.
06:37And we also have Subscripting methods that support the new keyed subscripts that are
06:41available in the latest version of Objective-C.
06:45This is all implemented in our .m file and just briefly we're not going to go through
06:49this in a lot of detail.
06:51You've got the source code here, and you're welcome to look through it and modify it and
06:54use it in whatever way you like.
06:57Our constructors simply set up the file name and open the database.
07:01And they call this openDB, which goes through a little bit of trouble to actually find the
07:07database file in the iPhone iOS file system.
07:11An SQLite database is kept entirely in one flat file, all the tables in a given database
07:18are all in one very portable file, which is why SQLite is used on so many mobile platforms.
07:26closeDB simply calls SQLite 3 to close, that's the C interface for SQLite 3 and dealloc simply calls closeDB.
07:35Here is the Fast enumeration support.
07:37There's very little documentation in the Apple documentation of Objective-C as to how fast enumeration works.
07:45Basically they give you some examples, and you can play around with those examples until
07:48you get something to work, which is what I did here.
07:53Here is our basic doQuery, which you'll notice uses variadic arguments here and here is the
07:59va_list and va_start for the variadic arguments.
08:02And you'll notice that it uses the SQLite C interface, sqlite3_step, sqlite3_finalize, sqlite3_changes.
08:09And again, prepareQuery is very simple, getQuery is likewise simple, as is valueFromQuery.
08:19bindSQL is where a lot of the work is done.
08:23This actually introspects the arguments, the objects that are passed in the variadic list
08:30using respondsToSelector to figure out what the type is of the argument and to call the
08:37appropriate sqlite3_bind_int, double sqlite3_ bind_text in order to interface with SQLite.
08:48Our raw results here are used mostly internally within the BWDB class.
08:53And these are our CRUD methods, this is for inserting a row.
08:57InsertRow uses some string methods in order to construct a sql query to insert the row into the database.
09:06Likewise, updateRow constructs an sql query for updating a row in the table.
09:13deleteRow and getRow are very straightforward, because how you do that in SQL is very straightforward.
09:23And likewise, these Keyed Subscripting Methods are also very simple.
09:28And then we have a couple of simple Utility Methods for getting a call in value in getting the lastInsertId.
09:33So, you can see that the value of the wrapper is in its ability to hide the complexity of
09:39the native SQLite interface from the Objective-C implementation.
09:43The C Language interface for SQLite is full-featured, but it's cumbersome.
09:48And when we finish the Testbed implementation using this wrapper, we'll get a good idea
09:52of just how much easier it is to use this in Objective-C.
Collapse this transcript
Testing the BWDB interface in the sandbox
00:00At this point we have started to incorporate BWDB in the Testbed code for testing.
00:06We've set up the SQLite 3 Framework in Xcode, and we've imported the BWDB Library into our Testbed app.
00:13Now, it's time to test the library in the testbed.
00:16So, you're going to take the results from your last exercise or if you prefer, you can
00:22use Testbed-02-done, which is my version. And I'm going to make a working copy of this.
00:28And I'm just going to call it Testbed-03-working, and so this way we can pick up where we left
00:34off at the end of the last movie.
00:36And I'm going to double-click on the Testbed. xcodeproject inside of that folder to open the project in Xcode.
00:44So, we have our BWDB Library, there is the m file, and there is the h file.
00:48I'm just going to close that up for now, we go to our BWUtilities.
00:53And I'm going to come over here to the TestbedViewController.m file, and up here at the top I'm going to
01:01import the BWDB header.
01:04And I'm going to come back out here into our finder, and I'm going to take this BWDB testbed
01:11code and open that up in my text editor. And we've got a couple of methods here.
01:17I'm just going to copy these and paste them into my m file.
01:21So, Command+C to copy, coming back here into Xcode, and down here in the implementation
01:29I'm going to paste those in, and there they are.
01:33And you see that our method here is called testDatabase.
01:37And so, I'm just going to come down here in viewDidLoad and instead of runTest, I'm just
01:43going to type in testDatabase like that.
01:48And so runTest here is actually often we can leave it there, or you can delete it, it's up to you.
01:54So, let's just go ahead here and run this and then we'll come back, and we'll look at the code.
01:59Make sure you select the iPhone Simulator and press the Run button, Build Succeeded,
02:05that's always a good sign.
02:08And so there is the Simulator, we see we have our BWDB version, SQLite version, create table,
02:15and all of these database operations happening successfully.
02:20So, let's take to look at the code. So, there's a table name and a file name.
02:26And there is an actual BWDB object being declared.
02:30And here we have our alloc init pattern, and we're initializing with the file name and the table name.
02:39And we call getVersion to display the version, and there is our version there.
02:44And SQLite version is value from query select sqlite_version, so there is the sql query
02:50to get the SQLite version, and that's getting displayed here.
02:54So, that actually tells us that a lot of stuff is working here.
02:59Our interface to the SQLite Framework is working and the interface to BWDB is working.
03:09So, we're actually able to send an SQL query and get a value from that, and that's a really good sign.
03:15So now, we come out here, and we create a table.
03:17You notice I have this message call to create--to display the create table string.
03:23And doQuery is the version of the query code, and if we come in here to the BWDB header
03:31and SQL query's doQuery simply returns a number of rows that were affected, if any.
03:38So, it's typically called without testing the return value.
03:42And we come back down here, and we can see doQuery here has been called without testing the return value.
03:47Drop table if exists and then CREATE TABLE.
03:52We're creating a table with an id column, INTEGER PRIMARY KEY that's SQLite for an auto
03:59incremented integer key.
04:02SQLite allows you to create columns without a type because it's really a very loosely
04:08typed thing anyway.
04:10And stamp is TEXT DEFAULT CURRENT_TIMESTAMP and so it will always put a timestamp on every single row.
04:18And so, now we're going to go ahead and insert a row, and we insert into BW table, so we're
04:23using doQuery for this insert, and we return the lastInsertId, and we see that we get one for that.
04:33And then using CRUD to insert with insertRow, and these are literal NSDictionary types.
04:41So, we have key value, key value, key value, that's a new feature in Objective-C, and it's
04:48much more convenient than the old way. So, I tend to use these literal values a lot.
04:53So, you see I'm using some different types here, I've got the literal floating point,
04:58I've got literal integers and here is a literal string.
05:02So, NSNumber doubles, integers and Mixed.
05:06And you see, when we look at these values, we get the return values based on the way
05:11that SQLite handles these sorts of things.
05:15And here I'm reading it back, and that's where it's displayed here using the NSFastEnumeration.
05:22And so, I simply pass the query into the db object and for a row in, the value that's
05:28returned by that is the actual db object.
05:30If we look at the getQuery code over here, we notice that it returns itself.
05:37So, that's actually returning the BWDB object.
05:42And because of NSFastEnumeration, I'm able to just say for row in that object, and then
05:48call display row with that row.
05:51And display row of course is up here, and it's just this simple message with the row.
05:56And again, we're using this new subscripting feature that's new in Objective-C.
06:01So, we use db countRows here, and there we have count rows 4, and then we delete a row
06:09and then we get count rows 3.
06:11So here, we delete row three with deleteRow, and we call countRows again we get a different value.
06:17And then we look, and we have just row 1, row 2 and row 4, and that again is using the
06:22NS enumeration for displaying the rows in the table.
06:26And then we're able to display an individual row using getRow.
06:30So, this should make it clear that the value of this wrapper is it makes it easy to work
06:36with SQLite in an Objective-C environment.
06:39We are using Objective-C paradigms for all of this, rather than having to write C code
06:44in the middle of our Objective-C.
06:45It makes this all seamlessly integrate with our Objective-C code for iOS.
06:52It's also easy as we'll see in another lesson in this chapter to subclass BWDB and create
06:57a specific interface for a specific application.
Collapse this transcript
Designing a database schema
00:00Because we're using a database for this application, we must start with a database schema.
00:04A schema is simply a description of the structure of the database that contains descriptions
00:10of tables, columns, indexes, and other associated constructs that are part of the database.
00:16There are tools available for defining a schema for a database.
00:20But this database is simple, and we'll be writing it in SQL in a text editor, and creating
00:24the database using the SQLite 3 Command Line client.
00:28So, in your Chapter 2 folder in exercise files, you'll find a file called bwrss.sql, and I'm
00:36going to open that in my text editor.
00:37I'm using TextWrangler which is free, and it is a great text editor.
00:42You may use whatever text editor you like just make sure it is not a word processor.
00:47This is a very simple database.
00:50It has two tables, one for Feeds and one for Items.
00:53You'll notice here, at the top, we do DROP TABLE IF EXISTS feed, and DROP TABLE IF EXISTS item.
00:59This is SQL, and if you need a premier on SQL, I have a course on the lynda.com online
01:06training library called SQL Essential Training, which would help you in SQL.
01:10There is also one specifically for SQLite called SQLite Essential Training with PHP,
01:16and that will give you a really good introduction to the SQLite Database engine.
01:20So we drop the tables if they exist, and then we create the tables.
01:23And each of these tables again is very simple, it has a unique ID for the record and they
01:28both have that URL for the data, title, description, the date of the last time it was updated, and a timestamp.
01:37For the Item, it is the same thing.
01:38There is a feed id which links back to the ID in the feed table that makes these two
01:44tables related to each other, and there's the URL of the item, title, description, publication date, and stamp.
01:50They're really very simple tables.
01:54We create a UNIQUE INDEX for the feed so that we look them up by URL, which we actually do.
02:00And then we insert into the database Default feeds, one for the lynda.blog, one for the
02:05lynda.com New Releases, and one for my Technology Blog, which I update about once a year.
02:11So, that's the SQL for creating the database. It is really very simple.
02:16We call this a database schema because it describes the database itself, and it is also
02:23SQL so we can use it to actually create the database.
02:26We are going to do that right now.
02:27I am going to quit my text editor, and I'm going to open up a terminal session.
02:32This is a terminal session on a Mac.
02:33It is basically a Unix Command Line, so I am going to be typing Unix commands.
02:39The Unix command cd stands for Change Directory, that allows me to navigate to a particular
02:45location as if I was clicking around in the Finder.
02:48So I am going to say cd Desktop/, and you'll notice that I just typed a couple of letters,
02:54and I pressed the Tab key, because this is the bash shell on Unix works like that and
03:00so it has something called Command Completion.
03:01I can just type a few letters and press Tab, and it will complete things for me.
03:05And so it puts in that slash for the subdirectory, and I can type E-X-E and press Tab, and it will
03:11get my exercise files on the Desktop, which is what's right over here.
03:15And then I'm going to type capital C-H-A-- these are case-sensitive, so I'm actually typing
03:21the capital letters--and press Tab, and it takes me to Chap0 because there are several
03:26of them if I press Tab again you'll see I'll get a choice.
03:29So I can press the 2 and Tab again.
03:31It gets me to my Chapter 2 folder press Return, and there I am, if I type Pwd it will tell
03:36me where I am in the File System.
03:41L-S will give me a listing of the folder or directory, and you notice it's got the same files here.
03:46At this point what I want to do is I want to take this SQL File, which is this one here
03:52that we're just looking at in our editor.
03:54I want to read that into the SQLite 3 Command Line Utility as a script to create a database.
04:02So the way I do that is I type sqlite3, which is the name of the Command Line Utility for
04:08SQLite 3, and it comes with your Mac. It is built-in.
04:11I am going to give it the name of the database, I'm going to call it bwrss.db.
04:16You'll notice that we don't have that yet. It is not listed here in the files.
04:20It is not listed here in the files.
04:22There is a done version of it, which is exactly what we are going to be creating.
04:28Then I used the left angle bracket, which is a Pipe Command in Unix shell, which means
04:34to read-in this file I'm about to name and use that as if I were typing it.
04:40The file I am going to read-in is bwrss.sql.
04:44This command here sqlite3 bwrss.db the left angle bracket, and bwrss.sql.
04:54That will read-in this sql file into this command.
04:58This command here is sqlite3 bwrss.db that will that will run the SQLite 3 Utility, it
05:04create this database file if it does not already exist and then read-in these commands and exit.
05:09I am going to press Enter, and you notice this doesn't take very long at all.
05:14If you saw over here, we now have this file bwrss.db.
05:19If I type L-S here, you notice we now have that file here we did not have before bwrss.db.
05:25If I type L-S dash L bwrss.db, it will give us some statistics about this file, and you notice
05:33that it's 16,384 bytes in size.
05:37In fact, if I say ls-l bwrss-done. db, it is exactly the same size.
05:46That is the one that I created earlier.
05:49The thing about SQLite is that the entire database is stored in this one file, unlike
05:55other database management systems where they have various files for indexes and for the
05:59different tables and sometimes even for columns.
06:02Everything is contained within this one file in SQLite 3, which is part of the beauty of it.
06:07It is in fact a platform agnostic file, which means that I can take this same file, and
06:12I can use it in Unix, I can use it in Windows, I can use it in any other platform, and be
06:17able to actually read it and write to it and use it with any SQLite 3 application.
06:22Right now, I'm just going to use this Command Line Utility, sqlite3 bwrss.db, press Enter.
06:31I am going type in an sql statement, select * from sqlite_master.
06:41Semicolon terminates a command in SQL.
06:45I'm going to press Enter, and it describes what's in this database.
06:50So I have these two tables.
06:52There is the actual SQL that was used to create them.
06:56I have this unique index. Also, I can look at the feed table.
07:02I can say select * from feed and a Semicolon, and there is the data inside that feed table.
07:09That's the data that we inserted using the SQL.
07:12If I come over here and open that up again, and you see down here at the bottom, we inserted
07:17these rows into the table. There we have them in our Command Line Utility.
07:23So I type .quit, and that will exit the SQLite 3 Command Line Utility.
07:31Type exit here at Shell Prompt, and I can Quit Terminal now.
07:38I can quit TextWrangler. There we have it.
07:41We have created our database, and there it is in our bwrss.db file.
07:47That's the complete working SQLite 3 database.
07:49It is really all there is to it, the entire database is contained in this one file.
07:53The file was completely cross-platform, so no matter what operating system you use to
07:58create it, it will work wherever you want to use it.
08:01All we need to do now is copy this file into the App and use it, and we'll do that in the next movie.
Collapse this transcript
Supporting the application with a specific interface
00:00At this point, we have a working SQLite 3 database wrapper class called BWDB and a working
00:06SQLite 3 database called bwrss.db.
00:10Now we want to take these components and make an Objective-C class for using these components in iOS.
00:15So we will start by making a working copy of our project so far.
00:20So you can make a working copy of your results from movie three or like I am going to do
00:24here, I am just going to make a working copy from Testbed-03-done, and I am going to rename
00:31this to Testbed-05-working.
00:36I am going to open up the project here in Xcode by double-clicking on the Xcode project file.
00:43Here we've got our BWDB Library, and you notice our testdatabase method here in our ViewController.
00:49I'm going to come right back over here to the Finder, and I am going to--first of
00:54all, I'm going to read-in our database.
00:56This is the database we created in the last movie, bwrss.db.
00:59I'm just going to drag this over here into our target, and you notice that I get this dialog box.
01:07I want to make sure Copy is checked, and I also want to make sure Add to Target is checked
01:10for our Testbed target.
01:13I'll click Finish, and there's the file there, right next to the dynamic library.
01:16And now I'm going to come back out here in the Finder, I am going to Libraries, and I am going to do the same thing.
01:21I am going to drag this RSSDB folder, and we'll take a look at this one as we import it.
01:26This is going to go in our Testbed group here inside of the target.
01:30I'll let go of that and make sure that Copy and Create Groups and Testbed are all selected,
01:38and there is our RSSDB code.
01:40If we look up here at the Header File, we see that what we are doing is we're extending
01:45the BWDB class, with a new class called RSSDB. This new class has got a bunch of methods in it.
01:55This is all specific for dealing with feeds and items.
01:58If we come over here into the m file, the implementation file, you see we've got a new
02:04constructor that calls the super constructor.
02:07That's the constructor of the parent class, the inherited class, and it initializes a
02:13list of id's, and it sets some defaults.
02:17So it is basically extending it with file name constructor from the parent class.
02:23getVersion is just over written.
02:25This getMaxItemsPerFeed, that's reading a preference pane value, we'll get to that later on in the course.
02:32This addNewIndex, there was a previous version of this App, which used a database file that
02:38did not have an index, and so it just creates the index if it doesn't exist.
02:42You'll notice that it is just using SQL for that, and it's calling doQuery on the parent class.
02:48RSSDB because it inherits BWDB, everything in BWDB is available.
02:55As a result of that, all of these methods that have to do specifically with feeds and
03:01with items, these are all very, very simple and straightforward some of them have some
03:06SQL in them but they are just calling doQuery from the parent class.
03:10So it makes it really easy because we already have this wrapper, it makes it really easy
03:15to write these functions that are very specific for this application and to simply put them
03:20in a class extension.
03:22Some of the most complicated stuff like this deleteOldItems is all accomplished in SQL.
03:29So you can see that it makes this job a lot easier that we can just extend a class that's
03:33already written, that's already wrapping the SQLite C interface in a nice Objective-C interface.
03:40Now, we can come out here to our TestbedViewController.
03:45Instead of BWDB here, we are going to import RSSDB.h.
03:53Now, we are going to come down here in our dispRow and our Test database.
03:57We are just going to replace those.
04:00So I'm going to select all of that, and I'm going to come back out here to the Finder,
04:03and in Chapter 02, RSSDB-testbed-code.txt, I'm just going to select all of that and copy
04:11it and come back over here into Xcode and paste that in.
04:16You can see that's very simple, so I am pressing Command+S to save.
04:22You see all this does is it initializes this RSSDB object.
04:27It passes it the file name bwrss.db, that's the database that we created in the last lesson,
04:35and we've already copied it into our project.
04:38It just displays the RSSDB version, and it reads these feed id's and displays them.
04:47Now we are going to make sure that the iPhone Simulator is selected and go ahead and run
04:52this in the Simulator. There we have our results.
04:56It is possible that you may get just the version number and not the actual database.
05:01There may be some errors down here on the screen. If that's the case, what you need to do is
05:05you need to actually delete the App from the Simulator and run it again.
05:10The reason for this is if this App has been loaded before, and it did not have the database
05:15in it, and then you load the database in Xcode and run it in the Simulator, it may not actually
05:22replace the whole bundle in the Simulator.
05:24So you have to delete the bundle and load it again.
05:28It sounds complicated, but if you just follow these steps, it should work.
05:32The first thing I am going to do is I am going to select Xcode, press Command+Dot, and that
05:37will bring up this message Finished running Testbed on the Simulator.
05:40Let's switch back to the Simulator, I am going to click on Testbed here and hold it down,
05:46you notice that it does this little wobbly thing just like on your iPhone when you go to delete something.
05:52I am going to press the Delete, and I am going to actually delete that whole bundle.
05:57Because my Simulator is the small version because I have the small screen, there is
06:00no button, I happen to know that Command+Shift+H presses the Home button.
06:06You see that the whole second page is gone now, because there is no App that goes there.
06:10You may have other Apps there, and that's fine. You just want to make sure deleting this one.
06:14Now I come back over here to Xcode.
06:16I have deleted the bundle off of the Simulator, and when I run it again, it is going to load
06:20up the correct bundle. You see that now we have the database.
06:25If you get that condition where it just shows the RSSDB version number, and it doesn't show
06:29any of the data that is probably because you've got an old version of the bundle on your Simulator
06:34that didn't have the database in it.
06:35You just delete that bundle, run it again from Xcode, and it should load up the correct
06:40bundle with the database in it.
06:41Here, we are just displaying these rows from the database, and we're showing that our App
06:46Specific Interface is working.
06:48As we go through the rest of the application the rest of this course, we will be using
06:51and discussing more of the methods from this library.
06:54An App Specific Database Interface is a simple technique, and it is a powerful tool.
06:59As your apps get larger, this technique becomes more and more valuable.
07:02I find that it is almost always worth the effort.
Collapse this transcript
Using C pointers with automatic reference counting (ARC)
00:00At the Worldwide Developers Conference in 2011, Apple introduced an extension to Objective-C
00:06called Automatic Reference Counting, or ARC.
00:09Like many object-oriented languages, Objective-C uses the concept of object ownership to keep
00:14track of how many places an object is used so that it may know when to retain and release
00:19memory associated with objects.
00:22This was traditionally handled manually by the programmer using retain and release method
00:26calls on the globally-inherited NSObject class. It was messy, but it worked.
00:31The new Automatic Reference Counting feature, or ARC, automates this process.
00:36ARC is a pre-compilation phase that automatically creates all of your retain and release calls,
00:42so you no longer have to do that manually.
00:45This is a fantastic addition to Objective-C, and it makes your job as a programmer a lot easier.
00:50Unfortunately, it also creates some new problems, one of which is how to interface with libraries
00:55written in plain old C. Let's take a look at an example.
00:59Here we have BWDB.h, which is a wrapper, around a C library for the SQLite 3 data base.
01:08And originally I had written this wrapper before ARC was introduced, and it worked just
01:13fine, and when ARC was introduced, it gave me trouble around this bit of code right here,
01:19which is the Fast Enumeration interface.
01:24And the reason for this is that we're passing it plain old C pointers like this stack buffer
01:31and ARC was having trouble dealing with that.
01:34Now, SQLite is of course, widely used for persistent storage throughout iOS and Fast
01:39Enumeration is a feature that's not actually very commonly used but is very, very handy.
01:45SQLite is of course, written in plain old C, and it has no concept of retain and release.
01:50It just uses plain old malloc and free for its memory allocation.
01:54For the most part, this is not an issue, and it's completely transparent, but when you
01:57need the interface with the foundation protocol like Fast Enumeration, it becomes an issue.
02:03So, if we look over here in the .h file, we see this NSDictionary enumRows, and
02:10this is used right there, and right here in the Fast Enumeration countByEnumeratingWithState method.
02:20So, what I had to do is in order to make this work is I had to declare this as unsafe, un-retained storage.
02:28And this is just one of the four storage classes that are available.
02:32It's actually a new one that was introduced with ARC and basically it just tells the compiler,
02:38when you're doing your ARC stuff, ignore this completely. And that works fine because
02:43it's statically allocated, and it doesn't need to be retained and released anyway.
02:48The other thing that I had to do is I had to qualify this id for stackbuf with unsafe_unretained.
02:57And again, this was not in the example for the Fast Enumeration on how to implement it
03:03in your own class as it's not very well-documented.
03:05It's only documented by example and so I kind of had to figure this out myself.
03:10But in a nutshell unsafe_unretained tells the system to bypass reference counting and
03:15not to zero out pointers.
03:17And this makes this particular feature work with ARC.
03:22Now, using Fast Enumeration is a convenience, it's not really a requirement.
03:26I find it very convenient and powerful and useful.
03:29It's also powerful and useful to understand how ARC works, not just to use it but to understand
03:34what it does and how to use it especially in exceptional use cases like this one.
03:39So, if you'd like to know more about ARC, this page on the llvm website explains all
03:45the gruesome details about how Automatic Reference Counting is implemented in Objective-C.
03:51It's a bit dense, but I find that it was worth the effort to read it.
Collapse this transcript
3. Creating the Table View App
Understanding the table view
00:00Table view is one of the most useful and revolutionary features in iOS.
00:04I was at the Macworld keynote address in 2007 when Steve Jobs first announced the iPhone.
00:10When he first put his finger on the list of items and pushed it into a scroll, the audience
00:15literally got up and cheered.
00:17They had never seen a mobile interface this intuitive, and this easy to use.
00:22This is Apple's email app that comes with the iPhone, it's a simple Table view, it's completely intuitive.
00:27You see this view, and you just want to scroll it.
00:30Table view is incredibly flexible too.
00:32Here is the settings app. This represents a grouped table view.
00:36The organization of items in this view is clear and obvious.
00:39The IMDB app uses a Table view to display REACH information.
00:44You got the movie poster and lots of date in the first cell, ratings in another cell,
00:48other artwork, an obvious link to the trailer.
00:51Again, it's intuitive you need no training to know that you pressed on that to watch a trailer.
00:56Then scroll down to get more information in other groups.
00:59It's clear, and it's obvious.
01:01This is the RSS app that we're building in this course.
01:04We're using a simple table view for displaying and selecting from list of feeds and items.
01:09As we work with it, you'll see how easy it is to work with the table view interface.
01:14The Table view is a powerful and flexible interface that's useful for a variety of applications.
01:19Take the time to experiment with it. Play with it.
01:22Learn what it has to offer.
01:23The REACH interface provides a wealth of options that you can advantage of to provide you data
01:28and navigate with a clear and obvious, user interface in your own applications.
Collapse this transcript
Creating the view controller
00:00As the first step of creating our data driven application, we will start a new project in
00:05Xcode and create the main table view controller.
00:09This is the project that will become our BW RSS application.
00:13So start by opening Xcode, and we're going to create a new project, so File New, select
00:20Project and under iOS and application we're going to select the master detail application.
00:28This gives us a table view in the iPhone version, and it gives us a split view in the iPad version,
00:36so we'll go ahead and press Next, and we're going to name our project.
00:39We're going to call it BWRSS, organization name, you'll just use whatever you use for that.
00:45Company identifier, or I'm using example.com, and this becomes part of the bundle identifier,
00:51as you can see down here.
00:52It's in reverse domain order and so you want to use your domain name, example.com is a
00:58generic one that's set aside for educational purposes like this.
01:02And so that's the one that I'm using, and you're welcome to use that or whatever you
01:05like in reverse domain format.
01:07Under class prefix, again, I'm going to use BWRSS here, and it'll use this to start the
01:13names of the classes.
01:14I'm going to select universal, this will create a universal application, an application that
01:19has support for both iPhone and iPad.
01:23For the first part of the course, we're just going to be developing with the iPhone version
01:27and then later on the course, we'll take those same classes, and we'll adapt them for use
01:31with the iPad, and you'll see how this is done.
01:34I'm going to check Use Storyboards and Use Automatic Reference Counting.
01:39We're not using Core Data, we're not using Unit Tests, and I'm going to press Next, and
01:43it'll give me an opportunity to create a local git repository.
01:48We're not going to be using this, but it's always a good idea and I'll refer you to the course
01:51on git in the lynda.com online training library.
01:56And so we'll select Chapter three, and I'm going to click Create, and it has created
02:01our project, and if I come over here back to the finder you'll see that there's project
02:05called BWRSS, and there's the Xcode project file that's open up in Xcode.
02:10At this point, we haven't done anything but create the project and Xcode has assembled
02:14a set of templates for us that create actually a working table view application.
02:19So if I go ahead and launch this in the simulator, so I'm going to select the iPhone Simulator
02:25and click Run, notice that it compiles it, it builds it without any problems, and it
02:31loads up the simulator, and there's our little empty table view application.
02:36So I'm going to select Xcode again, I'm going to press Command
02:39and the period, and that will stop the application running in the simulator.
02:44At this point, there's a couple of things we want to do to do the interface before we
02:47start implementing the database.
02:49First, we're going to rename the Master View Controller Class.
02:53So you see we have this class here called BWRSSMasterViewController, and I just want
02:59to rename this to be FeedsTableViewController.
03:05And so, I'm just going to select that and copy it here because we'll be using this.
03:10I'm going to come down here to where it says interface, and it has this BWRSSMasterViewController,
03:14and I'm going to right-click or Control-click and come down to Refactor and Rename.
03:21And there I'm just going to paste in what I typed before BWRSSFeedsTableViewController,
03:27and when I click preview it'll show me all the changes that it's going to make here.
03:31You'll notice it updates it in the storyboards, it updates it in the .h and .m files,
03:38and it shows me all of these places where it actually changes it, and that's a useful
03:43feature of Xcode, it's refracturing for renaming.
03:46I'm just going to say Save, and we'll get this little dialog box here that asks if we
03:50want to make snapshots.
03:51I'm going to say Enable because that never hurts. And there we go.
03:54Now we see that these files are now named FeedsTableViewController, I'm just going to
03:58update also this one here, this little comment here.
04:03Save that, and I'm going to come over here to the iPhone storyboard, and I'm just going
04:08to make a little more real estate on my screen here, and I'm going to come in up here where
04:12it says Master, and I'm just going to change that to say BW RSS, and we'll get back to the
04:20storyboard later and do some more things.
04:21For right now, I'm going to also delete these files over here, BWRSSDetailViewController,
04:28and I'm going to move it to the Trash, and I'm going to come in here to our .h or
04:33rather our .m file, and I'm going to delete this detail view controller .h reference.
04:41And so, we're just kind of cleaning this up a little bit to get ourselves a nice starting
04:44place for our application because I wanted to reflect the type of application we're building
04:51not just some generic application.
04:54And then just a couple of more clean up things we want to do here, our .h file should
04:58be just fine, yeah, actually we need to remove this reference to the detail view controller
05:04and remove this reference to the detail view controller.
05:08And then in our .m file, there's a couple more things to do here.
05:12Up here this little selector at the top allows me to jump around in the file and come down
05:17here to didSelectRowAtIndexPath, and I'm just going to comment all of this out.
05:24We'll get back to that later and likewise here this prepareForSegue, comment all of that out.
05:31I highlight it and then I press Command then the slash key on my keyboard here in Xcode
05:36that comments things out.
05:37I'm going to call for this little red line is here, and again, we have a reference that
05:41DetailViewController and just all of this code in here we're not going to need this,
05:46I'm just going to delete all of that.
05:53There's a few commented out functions down here, moveRowAtIndexPath, canMoveRow, we're
06:00not going to be using any of those, I'm just going to delete them and save, and this looks
06:05like it needs to be saved over here. Press Command+S.
06:09We have a nice, slimmed down, ready to use, and I'm going to save the storyboard as well,
06:16and I'm going to go ahead and press the Run button.
06:18We have the iPhone selected, and we'll notice that it compiles, and it runs just fine, it
06:23says BW RSS at the top here.
06:26So that was simple, we now have a functioning table view controller and then all we need
06:30to do is plug in the database calls.
06:32The iOS Cocoa touch framework actually makes this all pretty easy,
06:36as we'll see as we move forward building this app.
Collapse this transcript
Reading from the database
00:00Now that we have a working table view, we need to bring in our database library, so we
00:04can display the feeds in our main view.
00:07We'll start by making a working copy of the BWRSS project from earlier in this chapter,
00:13or you can copy from my BWRSS-02-done, like I'm doing here, and I'm just going to rename
00:20that to BWRSS-03-working.
00:24I'm going to open into Xcode by double clicking on the Xcode project file.
00:28And the first thing we need to do is we need to load in the libraries that we're going to be using.
00:33We're going to start by loading in the SQLite Framework so I'm going to select the Target
00:37here and Summary and scroll down to where we have the Linked Frameworks, press the plus
00:44button and type in sqlite and select sqlite 3.dylib, which stands for Dynamic Library.
00:53And I'll click Add, and that adds in the dynamic library here.
00:58Now I'm going to bring in the libraries from the exercise files so we'll come back over
01:03here to the finder and under Exercise Files in Libraries, I am going to select all three
01:07of these BWDB, BWUtilities, and RSSDB--I'm just holding down the command button on the
01:14keyboard while I select those. And I'm going to drag all of those into our BWRSS folder
01:21here in our project, and when I let go over that, you'll see we get this dialog box in Xcode.
01:26I want to make sure Copy items is checked, Create groups is checked, and the target BWRSS is checked.
01:34And I'll select Finish, and it copies those libraries in.
01:38Finally, coming back out here to the libraries folder in finder, I'm going to grab this BWRSS.db
01:45file, this is the starting point database that we created in our previous chapter, and
01:51I'm going to drag that into our project as well, and I'm going to make sure Copy items
01:57and Create groups and the target are checked and press Finish, and there we have database as well now.
02:04So now we'll come into our header file, and I'm going to import RSSDB.h header file and press Command+S to Save.
02:14And I'm going to come over here in our View Controller and up here in this interface section
02:21here, this is where we declare local object variables, and I'm just going to remove this
02:26objects variable, and I'm going to come in here and add some other variables.
02:31We'll have a BOOL for iPadIdiom, and that'll be a logical variable for checking if we are
02:39on an iPad or a non-iPad iPhone.
02:43A dictionary object, NSDictionary, and we call this newFeed, and I'm using the underscore
02:50for a lot of these, because that's convention for instance variables in Objective-C and
02:55RSSDB, this will be our database object and then an array for the feedIDs.
03:02We'll make a little space there, press Command+S on my keyboard to Save my progress so far.
03:09Now we're going to add database support.
03:11First of all, I want to point something out here, we'll get to this a little bit later.
03:14You notice these red lines that have appeared down here.
03:17That's because I deleted that object variable, and you notice that that's used throughout here.
03:23We're going to get to that and clean that up in a minute.
03:26First I want to bring the database support, and that comes in from Chapter03, this file
03:32here, there's a text file here with a bunch of Objective-C code in it.
03:36Objective-C code tends to be a little bit verbose, and so, rather than type a lot of this stuff,
03:41and there's quite a bit of it, we're just going to copy and paste it.
03:44So starting there and coming down to just before where it says view methods here on
03:48line 52, so I'm going to select all the way down to line 51, I'm going to press Command+C
03:53to Copy and come back in here to Xcode, I'm going to go all the way down here to the end
03:58of the file just before where it says end, put my cursor right there and press Command+V to Paste.
04:05So that end needs to be at the end of the file, and I've got all of this code that I
04:10just added before that.
04:11That's our database methods, and we'll be looking into that a little bit more later.
04:16Now let's come up here to where some of these errors are, insertNewObject.
04:19We don't need that anymore, because that objects instance variable was just there as part of
04:25the template for the table view application.
04:28numberOfRowsInSection, we can find that also in our text file over here.
04:33I'm just going to grab that and copy that and paste it in here, and scrolling down cellForRowAtIndexPath,
04:43we're going to update that a little bit.
04:45I'm just going to delete these two lines for now.
04:47We'll be getting back to this.
04:49And finally, this whole commit editing style, we don't need any of that, I am just going
04:55to delete that whole thing.
04:57Now I'm going to press Command+S to Save, and I'm just going to press Command+B on my
05:01keyboard here to Build and make sure that this compiles, and you see the Build Succeeds,
05:06and there aren't any issues. So that's a good sign so far.
05:09Now we've got just a few more things we need to do in order to inform the table view about
05:14the data so that the table view can display the data.
05:17There's a function in here called awakeFromNib, and see I can select from this little selector
05:23up here, it's a convenient feature of Xcode.
05:26And we're not going to be using that because we're not using a nib, we're using storyboards
05:31instead, so I'll delete that method.
05:33Under viewDidLoad, there's just another line we want to add in here to display the edit
05:38button in the navigation bar, and it look likes this, self.navigationItem.leftBarButtonItem
05:49= self.editButtonItem, and that will display that edit button item in the navigation bar,
05:56and I want to add a viewWillAppear method, and we can find that again in our text file here.
06:03Right there, I'm just going to grab that and copy it and paste it into our Xcode.
06:07I'm just going to put it right here before this pragma.
06:11And so when the view is just about to appear, it checks to see if our current device user
06:17interface idiom is the iPad, and if so, it sets a little iPadIdiom flag to Yes.
06:23Then it calls loadFeedIDs and reloadData on the table view.
06:28LoadFeedIDs is our own method down here.
06:32We come down here into our database stuff, and you see it's very simple, it simply checks
06:37to see if we have a database, and if not, loads the database.
06:41That loadFeedDB will alloc and init the database right there.
06:46And then once it has the database, it comes up to our feedIDs variable, and it loads that
06:51by getting all of our feedIDs from the database.
06:55And so what we end up with is this array, and if we come up here to the top we can see
06:59our instance variable that says NSArray of feedIDs and is an array of the IDs of the
07:07individual feed items, that are going to be displayed in the table view.
07:10Now if we come down here to number of sections in table view, that's always going to be one,
07:15because we only have one section and number of rows and section, of course, we've loaded
07:19that already, and that is the count of the number of feedIDs.
07:23And so finally, this cellForRowAtIndexPath, that's where the actual cell is populated,
07:30and before we can do that, I'm going to press Command+S to Save what we've done so far.
07:35We're going to go in to our iPhone storyboard.
07:37That's this one here, and we just need to set up this table cell a little bit.
07:41So I'm going to scroll that over, and I'm going to bring up our Inspector, and I'm going
07:47to make sure I select the Attributes Inspector, which is this one here.
07:51The Table View Style is going to be Subtitle, and we need an Identifier for it.
07:57That Identifier is going to be FeedsCell, and I'm just going to select it and press
08:02Command+C, put it in my copy buffer, because we're going to need that in just a moment.
08:07And then I'm going to come down here where it says Accessory, and I'm going to select
08:10None, because we don't need a disclosure arrow for that.
08:13So I've got my main storyboard selected over here, I'm going to press Command+S, and you
08:17see that that now is showing saved, I'm going to get rid of the inspector pane and come
08:23back over here to our FeedsTableViewController, and you'll notice where it says cellForRowAtIndexPath
08:29method, and you notice that it says dequeuReusableCellWithIdentifier,
08:33and it says Cell, I'm just going to select that and past that FeedsCell string.
08:38These need to be exactly the same, and it's really easy to misspell it--and I've on occasion
08:42I've forgotten the S or something--and that creates an error. I'll show you later on what
08:46that error looks like in case you actually get it.
08:49So makes sure that we're using this particular style.
08:54So here we have a style that's got the subtitle style.
08:57Pressing Command+S again, that was showing it wasn't saved.
09:01And so it's making sure that it's using the correct table cell from the storyboard.
09:05Now we want to actually load our data here, and so what happens is each time a table cell
09:12is populated, the iOS system will call this function in your application, and it will
09:19pass you an index path that tells you which cell it is that it's populating.
09:23So we need to take that index path and use it to find the correct data from our database. Okay?
09:31And so first, I'm going to make sure that I've loaded the FeedIDs, so I'm going to say
09:35self loadFeedIDsIfEmpty, then I'm going to Configure the cell.
09:40So I need a dictionary item for the feedRow itself, and I'm going to load that from the database.
09:48So I'm calling getFeedRow on the database and the row is this FeedIDs sub indexPath.row.
09:57The indexPath.row, that's the particular row in the table that's being populated.
10:02And I use that to index into our array of FeedIDs, and that will give me the correct
10:07FeedID which I can pass to get feedRow. And that will give me the dictionary entry that
10:12I can load here, and now I've got the data all loaded into my NSDictionary object, and I can use it.
10:18I can say cell.textlabel.text = feedRow title, and I can say cell.detailTextLabel.text = feedRow description.
10:34Now when I save this, I'm pressing Command+S on my keyboard, and I make sure I've got iPhone
10:40Simulator selected there, and I press Run, Build Succeeded, that's a really good sign.
10:46Now it loads up the simulator, and there it's displaying the data from our database in that table view.
10:52So these are the entries that we loaded up in the database in our previous chapter, the
10:57one we populated the database from the SQL schema.
11:00So now we have a working table view for our main page.
11:03I just want to show you one more thing.
11:05If we come back here into Xcode, and I'm going to press Command+Period, and that
11:09will stop--and you'll see it says Finish running-- that stops the app from running on the simulator,
11:15and I'm just going to misspell this FeedsCell identifier, so you can see what happens.
11:20It's a really cryptic error, and if you get this, I want you to know what it means.
11:23So I'm just going to misspell that, I'm going to press Command+S to Save, and I'm going
11:27to press Run up here, and you notice that instead of running, it gives us this error.
11:32It switches us into Debug View over here in the navigator pane, and it gives us our console
11:38down here, and you'll notice that there is just a whole bunch of junk showing there in the output.
11:44If you scroll up to the top, you see that there's an assertion failure, and it's in
11:49this table view, dequeueReusableCellWithIdentifier for IndexPath, and you'll notice that if we
11:56scroll down some more, it says uncaught exception and right over there, reason: unable to dequeue
12:02a cell with identifier xFeedsCell.
12:06And so, the error is buried in there, you got a bunch of stuff before it and a bunch
12:09of really pointless cryptic stuff after it.
12:13But if you look through there carefully enough you'll find what your error is.
12:17And if we come back over here to the Project Navigator and select our Table View Controller,
12:24we see there is that string xFeedsCell, so if I spell that correctly, it'll make it work.
12:32So I'm saving with Command+S and pressing Run, it says it's already running, it's actually
12:38crashed, but that's okay, I'm going to click Stop, Build Succeeded, and there we have it running properly.
12:45We can minimize this also with that button there.
12:48Just so you know when you see that error, that's what that means.
12:51So now we have a working table view for our main page.
12:53We're reading feeds from the database successfully.
12:56We're formatting them nicely in our table cells and displaying the data in the table view.
13:00This is the foundation of our application, and we'll be using this and building upon
13:04it for the rest of the course.
Collapse this transcript
4. Parsing XML Data
Understanding the parsing process
00:00XML is one of the most common formats for raw data on the Internet today.
00:05It's used for XHTML, SOAP, RSS, and many other data delivery applications.
00:11The iOS SDK provides a powerful event driven XML Parser, like many iOS Services, it's event
00:18driven, and it works with the delegate protocol.
00:20The parsing process can take some time, so we use a separate execution thread for it.
00:26This allows the application to continue to respond to touch events, while the parsing
00:30takes place in the background.
00:32This provides a better user experience as it keeps the application from seeming unresponsive.
00:37Before we can parse the XML, we need to get it from the network using the NSURLConnection Class.
00:43As we get the data from the network, we'll be displaying the activity indicator in the status bar.
00:48This gives the user some feedback so they know that something is happening and data is coming.
00:54Using the Activity Indicator is not an excuse to block User Input.
00:58The user must still be able to use the app.
01:00They will expect the user interface to still respond to input.
01:05XML data is parsed and added to a local database.
01:08We store the data for two reasons: one, a portable device has limited available memory,
01:13so we cannot carry around a lot of data at once.
01:16Storing data in the database freezes up valuable RAM, while keeping data readily available.
01:21And two, this gives our application data persistence.
01:26So the user can maintain a context between sessions and they don't have to read and parse
01:30the data from the net every time they need it. So we drive the app from the database.
01:35This allows the user to use the app without having to wait for data from the net every time they need it.
01:40This is the lifecycle of the data in our application.
01:43Read XML from the net, parse it, store the results in the database, and drive the application
01:48from the data in the database.
01:50This is a very common model for a data driven application as it allows the app to provide a great user experience.
Collapse this transcript
Creating the item view controller
00:00Before we can get the item data from the network for display, we need to create the table view
00:04for the item view controller.
00:06Let's start by making a working copy of the BWRSS-XML-start project.
00:11I'm going to Option drag this and rename it to BWRSS-XML-02.
00:19Now inside that folder, there is a file called BWRSS.xcodeproject, I'm going to double-click
00:25on that Xcode project file, and that will open the project in Xcode.
00:30We'll expand a couple of these disclosure triangles, so we can see our source code,
00:34and I want to select this BWRSS Group, which looks like a folder in its icon there.
00:40And I'm going to create a new class file.
00:42We need to set up our Table View for the items so we do that by creating a class.
00:46I can either right click on this and say New File, or I can just come up here in the File
00:51menu and select New File.
00:55Under iOS and Cocoa Touch, select Objective-C class and press Next.
01:01Now, I going to name the class, BWRSSItemsTableViewController,
01:07and that's a subclass of UITableViewController.
01:10If UITableViewController is not selected there, you want to select it from this drop down box.
01:14We're going to leave both of these items unchecked, we're not targeting for the iPad, and we're
01:19not using a NIB File.
01:21And I'll select Next and the default location here is in this BWRSS folder, which corresponds
01:26to this BWRSS Group over here.
01:29We want to make sure that the BWRSS Group is selected, and that it's targeted for the BWRSS Application.
01:35So we select Create, and there we now have our class files.
01:40I'm just going to drag them up here so that they're in with the other class files.
01:44Now we're going to open the Storyboard and create a segue for our new Table View.
01:49So, I'm just going to open this up a little bit, so we can see the storyboard_file name_iPhone_storyboard,
01:56and because I have such limited real estate here on the screen, I'm going to zoom out a little bit.
02:02You probably won't need to do that, and there's a lot of things that don't work right when it's zoomed out.
02:06So don't, if you don't need to.
02:08Then here, make sure that the Utilities Pane is selected, and under Objects here, I'm going
02:14to grab the Table View Controller, and I'm just going to drop it right about there and
02:21then I can adjust it so that it aligns properly. It's not necessary, but it's a good idea.
02:26Now I'm going to zoom back in here, and I'm going to create as segue.
02:31So I created a segue by control dragging from one object that can be selected to our New Table View.
02:38So, over here you see we have the Feeds Table View.
02:41If I scroll down you can see that it's Feeds Table View Controller.
02:45And I'm going to Control-click on the Table Cell here and drag over towards the New Table
02:53View, and you see that I get this little line, and when I let go of the mouse button, I
02:59get this Select a Segue, and I select the Push type of segue, and it creates this segue.
03:04So this here is the segue, and if I click on that, then I can actually edit it.
03:09Let me select over here the Attributes Inspector, and I can give the segue an identifier.
03:14So, I'm going to call this Segue, SegueToItemsTableView.
03:21I am going to press the Return key, because that actually makes this take effect, sometimes
03:24it doesn't happen if you type something into a field in Xcode, and you don't press the Return key.
03:29So, now our segue is named, and you see its Style is Push, and so we've created the segue.
03:36There are just a couple more of things we want to do to our New Table View.
03:39You'll notice down here it says Table View Controller, and so if I select this, and I
03:44select this orange circle here, which is the Actual View Controller, and come back over
03:48here to the Identity Inspector, you notice that its class is UITableViewController.
03:53We want our new sub-class to be the Class for this table view.
03:57So if I select this BWRSSItemsTableViewController, you'll notice that now, it says Items Table View Controller.
04:04If I select a different controller over here, it will say Items Table View Controller, and
04:08that's what you want it to say.
04:10And that way it will be actually be using the code in our BWRSSItemsTableViewController.m and .h file.
04:18So you notice that this is grayed out over here a little bit, this icon for our storyboard.
04:22I'm going to press Command+S on my keyboard, and that will take that gray away and make
04:26it white, to indicate that it's saved.
04:28I tend to press the Command+S key a lot, sometimes I might forget to say that I'm doing that.
04:34But it's an important habit to get into.
04:36Now I'm going to select our Table Cell, and if I come back over here to the Attributes
04:42Inspector, under Style I'm going to select Subtitle, make sure that the Accessory says
04:48None, and then the reuse Identifier, I am going to type in itemsCell, like that and press the Return key.
04:56You notice over here in our Feeds Table View that the cell has this little disclosure indicator.
05:04We actually don't need that.
05:05So I'm going to select that, under Accessory in the same pane, I'm going to select None,
05:08and you see that that goes away. So now, we're all set up.
05:13I am going to press Command+S to Save and come back over here to our ItemsTableViewController.h
05:19file, and the first thing I'm going to do in this .h file is I'm going to import our database header.
05:23So I'm going to come up here and type #import, and I am going to type RSSDB.h, see I got
05:32my code completion there, and Command+S to Save.
05:36Now, when I come back out here to Finder, and you'll notice we've got a few text files
05:40here in our Exercise Files folder in the Chapter04 folder. That's because Objective-C tends to
05:46be pretty verbose, and we don't want to have to type all this stuff.
05:48So I am going to open this header, this is 02-header.text file.
05:53In my text editor--I'm using TextWrangler, you can use any text editor as long as it's
05:57a plain text editor, a coding text editor and not a Word Processor.
06:01I'm going to select these three lines here, press Command+C to Copy, and come back over
06:07here into Xcode, and I'm going to just select this one line, here on line 12 and press Command+V.
06:12Now, we have our interface property, property, and end, and that's the way that that should look.
06:18Now, press Command+S to Save.
06:20Let's go ahead and close our Utilities pane, so this all fits on my little screen here.
06:25You can leave that open on yours. I just have limited screen real estate here.
06:30We can see that our class is called BWRSSItemsTableViewController.
06:35It's a subclass of UITableViewController, and it implements the NSXMLParserDelegate protocol.
06:43We have two properties declared, rssDB and currentFeedID, and those are populated actually
06:49from the FeedsTableViewController. We'll see that in a little bit.
06:54So, this header file is now complete.
06:56I'm going to press Command+S to Save, and we're going to open up the .m file for the
07:01ItemsTableViewController.
07:04As I scroll down here, you'll notice a couple of these orange lines here, these are warnings.
07:10We can just remove this safely.
07:11We'll be editing these methods later on in this chapter, but I'm just going to remove
07:16the warnings for now. Press Command+S to Save.
07:19I'm going to come back out here to the Finder, and I'm going to open this text file here, -02-methods.
07:27This will open up in my text editor, and you see we have quite a few things in here.
07:31The first thing we're going to do is select these class extension for private members
07:35lines, and I'm going to press Command+C to Copy. And come back over here into Xcode, and
07:40I'm just going to select this line right here, which is our interface declaration for a class.
07:45And I'm going to press Command+V, and we'll replace that line with what we've copied and
07:50pasted from our text file.
07:52So, we have a few variables here that are being used as private members for our class,
07:57and we'll talk more about each of them later on.
08:00Going back over here to our text editor, I've got some data properties, and again, these
08:06are private variables inside our class.
08:09I'm going to copy all of those, and I'm going to paste those in right here, and press Command+S to Save.
08:17Finally, down here we have this viewWillAppear method.
08:22I'm going to copy that, and I'm going to paste that in right here.
08:27Press Command+S to Save.
08:29So you notice here in this code, one thing that we do is we check the currentDevice userInterfaceIdiom
08:35to see if we're running on an iPad.
08:36If we are, we set this private member variable iPadIdiom = YES, and you can see up here in
08:43our class extension, we have this BOOL iPadIdiom.
08:47So, we can test that later on in the code to see if we're running on an iPad.
08:52One other thing you'll notice here, I'm using this rssDB property and also this feedRecord property.
08:59These are populated from the FeedsTableViewController, and we'll get to that in a moment, and we're
09:04using that to actually find the current record for this view.
09:08So, we select a row on the FeedsViewController, it will bring this ItemsViewController already
09:15populated with the items in that feed, and this is how that's done.
09:19So, if we go over here into the FeedsTableViewController--make sure this is saved,
09:23I'm pressing Command+S again--and we come over here into the FeedsTableViewController,
09:29and we select this prepareForSegue. You notice that this is not populated yet.
09:36Come back out here into Finder and open this FeedsTableViewController-02-Support.txt in
09:43our text editor and here's our segue delegate for that file.
09:46So, I'm going to copy and paste that into Xcode.
09:50Just select this entire method here and press Command+V, and we haven't yet imported this
09:56header file, so we're getting a couple of errors.
09:59We'll take care of that in a moment.
10:01You'll notice that this gets called when a segue happens from this view controller.
10:07This is the FeedsTableViewController, and it gets passed this segue object, and that segue
10:13object has a destinationViewController, and so I can assign that destinationViewController
10:18to a BWItemsTableViewController class object and then I can actually populate
10:26ItemsTableViewController.currentFeedID and ItemsTableViewController.rssDB.
10:30So if I come up here to the top then I'm just going to import our header file BWRSSItemsTableViewController.h.
10:42Now, when I come back down here to the prepareForSegue, you see those errors have gone away, and we
10:48are now assigning our FeedID and our rssDB to the properties in the ItemsTableViewController.
10:55I press Command+S to Save this, and we see over in our ItemsTableViewController in ViewWillAppear,
11:02this is where we're using those variables.
11:03We are also over here setting our row height so that we have enough height to display the
11:09things that we want to display. Now, I can just build this.
11:13I'm going to press Command+B to Build.
11:15Before I run in the simulator, I want to make sure I've got the iPhone simulator and not
11:19the iPad simulator selected, and then I can just press Run, and this will run it in the simulator. There we are.
11:27This is the 4-inch Retina iPhone simulator, and this is scaled down because this screen is so small.
11:32It doesn't have enough pixels to actually support that.
11:35Hopefully you're running on a bigger screen. So, this doesn't have any borders.
11:38It doesn't have a Home button, but this is the iPhone simulator.
11:41Yours will probably look different, and when I select one of these feeds here, you see
11:46it brings up our new ItemsTableViewController, and you can see there's the title that gets
11:51populated right here, self.title = self.feedRecord (@"title"), so it's actually reading that
11:56from the database based on the current feedID that got passed from the FeedsTableViewController. So, there it is.
12:05That is completely working. I can bring up the lynda blog.
12:07Of course, none of these are being populated yet.
12:11That will happen in one of our later movies, but we now have a working table view for the items.
12:16We're using the segue from the storyboard to set up the ItemsTableView, and now we are
12:20ready to fill in the ItemsTableView with some data, and we'll do that in the next lesson.
Collapse this transcript
Reading data from the internet
00:00Because of the data that we're using comes from the network, we need to create a network
00:04connection and read that data before we can parse it and use it.
00:07For this, we'll use the NSURLConnection class.
00:12Start by making a working copy of BWRSS-XML-02, or in this case, the -done version.
00:18You can use your version from the previous lesson if you have it, which would not have
00:22this -done at the end.
00:24So, I'm going to make a working copy of this, and I'm going to rename it BWRSS-XML-03, and
00:32I'm going to go ahead and open the project by double-clicking on this Xcode project file.
00:37We have a working table view here, so now it's time to set up the NSURLConnection class,
00:43so we can grab the feed from the network.
00:45We're going to start by importing the BWUtilities, because we're going to use that for our error displays.
00:55We're going to come back out here to Finder, and we're going to grab a bunch of codes from
00:58this 03-NSURLConnection.txt file.
01:03This just has a lot of stuff in it that we don't want to have to type right now.
01:07We're going to start by grabbing a bunch of these constants.
01:10These constants are used for a number of purposes.
01:12We'll take a look at them in a moment here.
01:15Copy that and just going to paste all of that right in here at the top of the Source file.
01:21This should be right after these imports and right before this class extension for private members.
01:28So these constants are used throughout the code for a lot of different purposes, both
01:32for the URL connection and for the parsing code, and it's just that we don't have to
01:37type a lot of these literal strings and having them all in one place makes it easier to make changes later.
01:43So, this is just good programming practice, to use constants instead of literals.
01:48So, I'm going to press Command+S to Save that and come back out here to my text file, and
01:53I'm going to grab everything from here all the way to the end.
01:58We're just going to paste this in, and we'll look at it as we go through it.
02:02So, I'm going to copy, and I'm going to come down here all the way to the end of our code
02:06and just before the end marker there, I'm going to paste this all in, and you can see
02:14here, starting with our Support methods, we have loadRSSFeed, which creates the NSURLRequest
02:20object, and it uses the URL from the feedRecord.
02:26And then it sets up the connection with the delegate as the self, that allows us to use
02:30all of these NSURLConnection delegate methods.
02:33It sets our networkActivityIndicator that's the little spinner in the bar at the top of
02:38the screen on our iOS device.
02:41Once that's started, then the NSURLConnection calls these delegate methods, which are again very simple.
02:49Set up the connection, we didReceiveResponse, we set that networkActivityIndicatorVisible
02:53again, and we set up a place to store the data.
02:57Every time we receive data, we go ahead and appendData that accumulates it in our NSMutableDate object.
03:05When we're done, we'll go ahead and detachNewThread to parse the data.
03:09Now, we don't have our parser code set up in here yet, so I'm going to comment that
03:13out and in the event of an error, I have this didFailWithError, we go ahead and call our error code.
03:20So, we have this handlError down here and the errorAlert, which uses the alertMessage
03:25method from the BWUtilities, or if we have more data to display, it goes ahead and creates a UIAlertView.
03:32So, in order for this to work, we need to call all this code some place.
03:37So, we're going to come back up here to our viewDidLoad--and I'm just going to take out
03:44all of these comments here--and I'm going to go ahead and call our loadRSSFeed, self
03:51loadRSSFeed, and we will compile, I am pressing Command+B on my keyboard. Build Succeeded.
03:59Make sure the iPhone Simulator is selected up here and press Run.
04:05Now when I click on this, you see a little network indicator came up, but we don't have
04:08any indication yet that anything is happening.
04:11You can see the network indicator kind of flash up there.
04:14So, let's go back here in the code, and I'm going to press Command+Period to stop
04:19the Simulator. And in our DidFinishLoading in the URLConnection delegate, you notice
04:27where I commented out this detachThread for calling our parser that we don't have yet,
04:32I'm going to put in an NSLog, so we can see that we got to this point, which means that
04:38we have finished loading the data, and we have data.
04:40I'm just going to type have data in the NSLog, press Command+S and press the Run button,
04:47and now when I click on one of these, you see we get that have data down here.
04:51Just make a little more room for that, and I'll go ahead and click on another one, we
04:56have data, and I'll click on another one, we have data.
04:59We see our little network indicator coming up there on the Carrier Bar at the top of the Simulator.
05:04So, I'm going to switch back to Xcode.
05:06Press Command+Period, and we've stopped running the Simulator.
05:10Now, our NSURLConnection is complete.
05:13You can see it's pretty simple to use or at least it's a bit demystified.
05:16The delegate classes tend to appear less intimidating over time as you get to know them.
05:21Now, we are successfully reading the feed using our NSURLConnection object, and we have
05:27RSS data that we're ready to parse for the Item View.
Collapse this transcript
Parsing the feed with NSXMLParser
00:00Parsing XML is a processor intensive operation and mobile devices tend to have limited processing power.
00:07Even though Apple continues to improve the specs of each iteration of their devices,
00:11in order to preserve the responsiveness that these devices are known for, we'll be doing
00:15our parsing in a separate execution thread.
00:18This ensures that we don't block the main thread, which could cause the user interface
00:22to freeze during parsing.
00:24Let's start by making a working copy of BWRSS-XML-03.
00:28I'm going to use the -done version here, and I'm just option dragging to make a copy
00:34and rename that to -04.
00:37I'll open the project in Xcode by double-clicking on this Xcode project file.
00:44Now, remember we have this NSLog line, which says we have data, and that happens when we
00:50finish loading from the NSURLConnection.
00:52So, if I run this in the iPhone Simulator, I select the iPhone Simulator and click Run.
01:00When I click on one of these feeds, you'll notice we'll get a message down here in the
01:04log that says have data. Click on another feed, have data.
01:10So, I'll go ahead and stop this from running in the Simulator by selecting Xcode and pressing Command+Period.
01:18I'm just going to minimize our log area down there.
01:21Now, we're going to bring in a whole bunch of code in our text editor, because it's just
01:25way too much typing for us to do here in this lesson.
01:28So, you'll see the file here TableViewController-04-NSXMLParser.txt.
01:34I'm going to open that in my text editor, I'm using TextWrangler here.
01:37I'm going to go ahead and select all of the file, you'll notice that there's just a whole
01:42lot of code in here, and we'll go through this, and we'll take a look at it.
01:46We're going to do that in Xcode. So, I'm going to Copy that with Command+C and select Xcode.
01:51I'm going to come all the way down here to the end.
01:53I'm going to put this in just before the Error handling here, and I'll Paste that with Command+V
02:02and press Command+S to Save.
02:04So, if we look at what we've added to the file here, we have the NSLXMLParser delegate methods.
02:10So, the way this works is when we set up the Parser, we set our own class as the parser
02:17delegate and then the parser calls the delegate methods inside of our class at each step in
02:25the parsing process so that we can process the data.
02:29We have a few little Utility methods, and we'll look at these.
02:31These mostly have to do with formatting dates and these error handlers were in there before.
02:35So, if we look at didStartElement, this is a parser delegate that's called at the beginning
02:41of each element in an XML stream.
02:43Basically, what we do at the beginning of an element, depending on the type of an element,
02:47if it's a container, we just set things up to start accumulating data, and if it's not
02:52on a container, then we decide what to do individually based on that.
02:56For instance, if it's the ChannelElement, we start setting up the feed and item objects.
03:02If it's an ItemElement, then we know that we've completed the item before, and we can
03:07use the contents of that item to start populating the database.
03:12If it's one of our containerElements then we just start accumulating data.
03:18DidEndElement tells us that we've gotten to the end of the element and especially in the
03:21case of the containerElements, it tells us that we can start adding items to the list,
03:26because we've reached the end of a container and all of the content of that container that's
03:30been accumulated, we can start adding that to the Items List.
03:35In particular, if we have one of these dateElements, so these are really just different names for
03:40the PubDateElement, but then we need to clean up the date format, and if we come down here
03:46into our Utilities and look at dateStringToSQLDate, of all these different possible formats
03:52that I've discovered in RSS Feeds, and I know that there's more.
03:56There are probably still some that don't work with this app, because they have these different date formats.
04:01They are supposed to use a standardized format for their dates, but everybody uses a different
04:06format, and I don't know why.
04:07It's just annoying mostly, but this is how we deal with it.
04:10So, we parse in from these different dates, we use the built-in dateFormatter in iOS.
04:16It's the same as in OS X and then we simply format it into the standard SQL format for
04:22storing in the database. That makes it possible.
04:25Compare dates, it makes it possible to sort dates, because this is a really sensible format for computer processing.
04:32Now, especially for our containers whenever we find characters, we accumulate that and
04:38at different points in the process we say, okay, we're done with this chunk of data,
04:42and we'll go ahead and process it.
04:44And if there is an error, then we call handleError on the main thread and of course, handleError
04:50is the same as we've used elsewhere in this application for, especially in the NSURLConnection methods.
04:57So, we come back up here to our Support methods, parseRSSData that sets up the NSXMLParser
05:06in a separate thread.
05:08You notice that we have to put all of this code in this autoreleasepool that's because
05:12it's running in the secondary thread, and this is the new syntax for doing this with
05:16ARC, Automatic Reference Counting, starting in iOS 5.
05:20In our addItemsToList method, this is where we add items to the database.
05:26Now because we haven't set up our Table methods yet, we're not going to be displaying this on the screen.
05:30So, we're going to put in here an NSlog so that we can see when we actually have the
05:37parser data, because we're not going to be actually displaying it on the screen yet,
05:41because we haven't set up those methods yet for handling the table.
05:44We'll do that in the next movie.
05:46For right now we just want to say item and use that for the title.
05:50We'll put the publication date in parentheses, and we'll put the URL in square brackets.
05:57I'm a big fan of copy and paste.
06:00We're going to use our constants for keying off the Item here, kItemTitleKey and kItemPubDate and kItemUrlKey.
06:14It's looking like it's got a little warning here. Ah, yes, typo.
06:21Here we go and press Command+S to Save.
06:25Now, we need to come back here to connectionDidFinishLoading, and you
06:31remember we have this NSLogin there that says have data.
06:33I'm going to go ahead and take that out, and I'm going to uncomment this detachNewThreadSelector
06:39so that we can go ahead and run the parser in our secondary thread.
06:43So you see there's our call to parseRSSData as the selector getting passed to detachNewThreadSelector,
06:49Target:self, Object: self.rssData.
06:52I'll go ahead and press Command+S, and we are going to Build, I'm going to press Command+B
06:58on my keyboard here and Build Succeeded. No problems.
07:01We can go ahead and run this in the iPhone Simulator.
07:04Now, when I click on one of these, you see down here we got our parsed data, and you
07:14can see here is item: On Choosing a Programming Language, that's the title, there's the publication
07:20date in the parentheses there.
07:22Down here in the square brackets, that's the URL associated with that.
07:26So, I can go ahead and click on one of these other feeds, and you see we got a lot of data
07:30there for that feed.
07:35I can click on the final feed, and we get even more data.
07:39So, now we're successfully parsing the feed, and we're updating the Item Table in the database
07:45with the Items from the RSS Feed.
07:47At this point, all that's left to do is to update the TableView with the Items from the
07:51database just as we did with the feeds in the FeedsTableViewController.
07:54So, I'll go ahead and quit the Simulator and minimize this and get ready for the next lesson.
Collapse this transcript
Updating the item view with the feed items
00:00At this point, we have a working parser running in a separate thread that's updating items in the database.
00:05Now, it's time to update the ItemTableView from the database, and now that all the heavy
00:10lifting has been done, this becomes pretty simple.
00:14We'll start one by making a working copy of BWRSS-XML-04.
00:18In this case, I'm going to use the -done version.
00:22You can use the one that you completed in the last movie, if you've been following along with the exercises.
00:27I'm going to rename this to BWRSS-XML-05, and I'm going to open it in Xcode by double-clicking
00:34on the Xcode project file.
00:39I'm going to go ahead and expand this and select the iPhone Simulator there and select
00:45the ItemsTableViewController here.
00:48I'm going to minimize this Utilities Bar, and that way we have plenty of screen real
00:54estate here to look at our code.
00:56So, you notice as we add items to the database here, we have this little NSLog that displays the items.
01:05If I go ahead and run this in the Simulator--
01:08I've selected the iPhone Simulator, and I'm going to run this.
01:13You see that as I select a feed, we get the output down here in the log, and that's from this NSLog here.
01:22So, we have the item title, we have the pubDate, and we have the URL.
01:31I'm going to stop the Simulator by pressing Command+Period, and we'll go ahead
01:36and minimize this so that we have some room here.
01:39Now, what we have to do is to update the TableView from the database.
01:43So, there are couples of steps to that.
01:45We're going to come back up here to our Table view data source section and the number of
01:51sections in the TableView is going to be one because there's always just one section.
01:56We don't use the Sections Feature for this application.
02:00Number of rows in section is already filled out here.
02:03We have the itemRowIDs getting updated from the getItemIDs in the database and then we
02:10return the count and so that's the number of rows in the section.
02:13I'm going to press Command+S here on my keyboard to save.
02:16Now, our cellForRowAtIndexPath, this is a bit of code, so we're going to go ahead and
02:22read this from a txt file, coming back here into Finder, our 05-Table.txt.
02:27We're just going to grab this whole thing because this is all just that one method.
02:33I'm going to select all with Command+A and Command+C to copy and come back here into
02:39Xcode, and I'm going to select this method here, cellForRowAtIndexPath.
02:45Select the entire method and paste and then we can look at the code here in Xcode.
02:50I'm going to press Command+S on my keyboard to save.
02:56Our CellIdentifier, we want to come back over here into the iPhone storyboard and select
03:03our cell and bring up our Utilities View.
03:08You see the Identifier here says ItemCell, all right?
03:11If we come back over here to our TableViewController, we see that it says ItemCell, so it does match. That's important.
03:18If it doesn't match, we know that the cell won't get updated.
03:22Now, we get the FeedItem based on the indexPath.row, and now we have what I call the clever variable font size trick.
03:32It's really very simple.
03:33All we're doing here is we're taking the text that's going to go in the ItemCell, and we're
03:38looking at whether it would take up more than one line, and if it takes up more than one
03:43line, then we're using a smaller font size, and we're using a larger font size if it takes
03:49up just the one line. I'll show you that when we run this.
03:53Again, we're reformatting the date.
03:56This time we're taking an SQLDate, and we're making it into a displayable date, and if
04:02we look down here in our Utility methods, SQLDateToDate, that puts it in an NSDate format
04:08and then we have dateToLocalizedString, which puts it in a localized format.
04:13If we come back up here to our cellForRowAtIndexPath, you see we call dateToLocalizedString, based
04:22on the SQLDateToDate, and that all gets loaded into the detailTextLabel.
04:27Now just before we run this, we want to come back up here to addItemsToList, and we just
04:33want to take out this NSLog line here.
04:37We're not going to need that anymore because we're now updating the TableView.
04:39So, I'll save this, and we've got iPhone Simulator selected, and we'll go ahead and we'll run
04:44this in the Simulator, and I'll select one of these feeds, and there we have it.
04:49Now, we have our data being displayed, and you'll notice we have the title and the date in the localized format.
04:57If I go ahead and look up one of these other entries, you'll notice that we have two different font sizes.
05:03This line here InDesign FX is in a larger font than these that have more than one line.
05:09What can happen here as well, I don't have an example of it here, but I think I have
05:13an example of it in this one.
05:15You'll notice that some of these are in a smaller size because they wouldn't fit all
05:19on one line in the larger size.
05:21So, this one is a larger size, this one is a larger size, and these three are actually
05:25the smaller size and they don't wrap around to the second line, but if they were in the
05:30larger size, they would and so they get that smaller font size anyway.
05:35So, that's that clever font-size trick that's used in cellForRowAtIndexPath.
05:39Now, we have a working TableView for the feed items.
05:43It reads the RSS feed from the net, it parses it in a separate thread, it stores the results
05:48in the database, and it reads the results from the database for display in the TableView.
05:52We'll implement a WebView for displaying the items in a later chapter.
Collapse this transcript
5. Using a Modal View
Understanding the modal view
00:00On the main view of the BWRSS app you will see a button with a plus sign.
00:05This is for adding a new feed.
00:07When you press on the Add Feed button, a modal view appears with the form for adding the feed.
00:12This is a common visual model for an add item action,
00:15so it will be familiar to the user.
00:18It's a modal view because it's temporarily displayed on top of another view, and it must
00:22be dealt with before returning to the parent view.
00:26A modal view is typically used to present an edit page or additional details of a model object.
00:32Take care to always include clear and prominent completion and cancel buttons.
00:37In this case, the completion button is labeled Add.
00:40A modal view is a very different kind of animal.
00:43When you're using a modal view, you'll want to keep a few things in mind.
00:47Never display an alert or any other modal object from a modal view.
00:52The danger is that the modal view may be dismissed before the alert, and this would leave the
00:56alert orphaned and cause your app to crash.
01:00Never communicate directly with another view object, including your parent view.
01:04You may be tempted to pass a view object pointer to your modal view to make it easy to send
01:09messages back and forth.
01:11Again, it's just too easy to orphan your pointer, leaving a nasty memory leak or worse.
01:17The easy thing to do is to create a delegate protocol and communicate with that.
01:22I know this sounds complicated, but it's actually very easy to do in Objective-C, and I will
01:26show you how in this chapter.
01:28A modal view is a powerful tool and like any powerful tool, it must be used with care.
01:33Visually, it's a strong indication to the user that it is necessary to enter some information
01:38or take some action immediately.
01:40You just need to make sure that there is a very clear path out of the modality, and that
01:44it's easy to get back to the normal workflow.
01:49
Collapse this transcript
Constructing the view controller
00:00At this point, we have a working FeedsTableViewController for viewing feeds and a working ItemsTableViewController for viewing items.
00:08In this movie, we will create the AddViewController for adding feeds to the database.
00:13This will be accomplished by creating a modal dialog view for getting the feed URL from the user.
00:19We'll start by making a working copy of BWRSS-addView-start, and we'll call it BWRSS-addView-02.
00:25I'm just going to expand this a little bit. And there is our addView, and that's our start,
00:33and I make a copy, and I rename it with 02. And I'm just going to open the Xcode by double-clicking
00:38on this Xcode project file.
00:42And now, before we can create the screen in storyboard, we need to create a new class
00:46to support the AddViewModal dialogs.
00:48So, I'm going to select our BWRSS folder up here.
00:52You could just right click on this and say New File, or you can go up to the File menu
00:57and say New > File; either one does exactly the same thing.
01:02And we're going to select a Cocoa Touch Objective-C class, press Next, and this is BWRSSAddViewController, like that.
01:12And it is a subclass of UIViewController, so you want to select UIViewController and
01:18not UITableViewController, if that's the last one that you used.
01:21It was apparently the last one that I used.
01:24And leave both of these unchecked.
01:25It is not going to be targeted for the iPad. We're not using NIBs.
01:28And I'll select Next, and it will get stored right there in the BWRSS folder with all the
01:35other m and h files. And you want to make it in the BWRSS group and make sure that the
01:40BWRSS application is targeted so that check box needs to be checked there.
01:46I'll press Create, and there we have our new class files.
01:50I'm just going to drag them up above that Supporting Files folder.
01:54And I'm going to open the .h file, and we'll get started in there. And switching
01:59back to my Finder, you see here that I have an AddView02-header.txt file.
02:05So, I'm going to open that up, and I'm just going to select all of these and drop it in this Xcode file.
02:11I'm just going to select these there and make sure our ends are matched up; they are.
02:17And so there are a couple of interesting things going on here.
02:19You will notice that we have a protocol declared. This is the RSSAddViewControllerDelegate protocol.
02:25This has three methods defined in it. And we're going to be implementing that towards
02:30the end of the chapter, but that allows the AddViewModalViewController to communicate
02:36with the FeedsTableViewController.
02:38The FeedsTableViewController is going to be the parent of this ModalViewController, but
02:43because this is a ModalViewController, we don't want to do things like dealing with
02:46the database directly;
02:47we want to communicate back to the parent ViewController, which is not modal, and allow
02:52it to do those time- and resource-intensive things.
02:55Otherwise, we end up affecting the performance of the rest of our device.
02:59And in fact, iOS even prevents us from doing certain things from a ModalDialogueViewController.
03:04So, we had this protocol. And we'll see that it adds a layer of complexity, but it's not that bad.
03:09You will see it is relatively easy to implement.
03:12Our AddViewController itself will be using the NSURLConnectionDelegate and NSXMLParserDelegate protocols.
03:18We have this delegate property, which actually gets populated from the FeedsTableViewController,
03:24and we'll see how to do that later in the chapter.
03:27And then we have a TextField, a Label, and a couple of Actions.
03:31We'll be hooking those up to our ModalViewController.
03:33So, I'm going ahead and press Command+S to Save, and I'm going to switch to the .m file.
03:38I just did that by pressing Ctrl+Command+Up Arrow here on my keyboard.
03:43You'd also just select it in the Project Navigator.
03:45Of course, you may want to be using the Assistant Editor.
03:49I'm not using the Assistant Editor because I have such limited screen real estate here.
03:53So, over here in the .m file, or methods file, I'm going to go back to the Finder
03:58and I'm going to bring up the stuff that we don't want to have to type a lot of.
04:02You can see there is quite a bit of that.
04:05Now, first, we have this import BWUtilities because we used some of those utilities.
04:10So, I'll go ahead and I'll paste that in right there.
04:15And we have a whole lot of constants, and we'll be using these throughout this chapter
04:21and throughout this class.
04:22So, I'm just going to go ahead and select all the way to the end here,
04:25and I'm going paste this in, in Xcode.
04:28I'm going to select these and replace that.
04:31Notice we have this warning here. That is probably for an incomplete implementation
04:35because there are things that we had declared in the header file that we haven't implemented in here yet.
04:40So, we have a number of constants that we are using for various different purposes.
04:43It's always a good idea to use a constant rather than typing in a literal string or
04:47a literal number, especially if you're going to be using that literal more than once.
04:52We are also declaring a number of instance variables here.
04:55We have an enum that we use for a mode switch later on.
04:59The xmlData is used for accumulating data as we read it from the network connection,
05:04currentElement is used during parsing, feedRecord is used to accumulate data for the feedRecord
05:09before we pass it back to the parent controller, and a number of flags here, and some local
05:15properties as well.
05:18We also have a number of methods that we're going to go ahead and just drop these in right now.
05:23And so I'm going to copy that and come down in here and paste them just before this @end.
05:32We have a duplicate here of the viewDidLoad, so I'll go ahead and I'll delete that one.
05:37So, viewDidLoad, it sends a becomeFirstResponder message to the URL text feed.
05:44We'll see what that does in a little while.
05:46It makes that TextField the focus as soon as the view is loaded.
05:51And we have actions for our Cancel button and our Add button, and we also have this
05:55textFieldShouldReturn, which intercepts the Return button, or the Return key from the keyboard,
06:01and allows us to take an action based on it.
06:04We'll see how that works as well.
06:05So, I'm going to go ahead and press Command+S to save this,
06:09and now we're going to create the interface in our storyboard.
06:13So, I'm going zoom out here a little bit because this is just too big to work with in this
06:19small amount of real estate I have here on the screen.
06:21And I'm going to bring out our Utilities pane. And the first thing I'm going to do is I'm
06:27going to come over here to the FeedsTableViewController and I'm going to add a button.
06:32And so I'll come down here into Windows and Bars.
06:37There it is, Bar button.
06:39I'm going to drop that on to--yeah, it looks like I need to zoom in in order to do that.
06:43I'm going to drop that on there and under Style, Bordered is fine, Identifier, Add,
06:50and that will give it a little plus sign.
06:53And I'm going to zoom out again, and I'm going to create a new Controller. Under Controllers
07:01& Objects, I just want a Plain View Controller.
07:05Now, I want us to get under this TableViewController here, and I'm going to select both of them
07:13and scroll them up a little bit.
07:18And I'm going to create a new segue from this plus button that I've just created.
07:23So I'm holding down the Control key on my keyboard while I drag a line from here to
07:27our new ViewController, and I'm going to select modal for the segue.
07:32Now, we have our new segue here, and I'm going to select that.
07:38Its identifier will be SegueToAddView.
07:44Its style is Modal, and its Transition will be Cover Vertical.
07:49I'm going to press the Enter key there and press Command+S to save.
07:54Now, we're going to zoom in to our new ViewController here, and I want to select the orange circle
08:02there which identifies our controller and come over here to show the Identity Inspector,
08:06and we're going to select our new BWRSSAddViewController for that.
08:11And so now we can see it's the AddViewController.
08:15And I want to set some properties on this controller--make sure I've got the Controller selected.
08:22I'm going to get a Scroll View and drop that on here so that we can add some items to that.
08:34So, there's our Scroll View, get that nicely centered in there.
08:37And I'm going to select the Background and make it the Scroll View Textured Background Color.
08:44Now, the thing about the Scroll View Textured Background Color is that it doesn't actually
08:48show up here on this screen, but it is a dark color.
08:51So, I'm going to be putting items on it. I'm going to setting their color to white so that
08:54we can actually see them.
08:56And this will make sense when we go to test it, and you'll see what it looks like.
08:59But in the meantime, it's going to make things a little bit difficult to work with, and that's
09:02just a quirk of how Interface Builder works and how storyboards work.
09:07So, I'm pressing Command+S to save.
09:09I do that a lot. And I'm going to grab a text Label here, under Controls, and Label. I will
09:17bring it up to the top here and center, or you can bring it up to the top and left, and
09:23you can just drag its right side out all the way to the other line.
09:27So, I'm using these guides to help to line things up.
09:31And it makes it so that everything looks like nice on the screen when we're done laying it out.
09:35I'm going to select a Center Alignment and the System Bold Font.
09:41The Size of 17 is good, and it is going to say Add RSS Feed, and you can see that it says Add RSS Feed.
09:51If I take my cursor away and click over here, you can see how nicely centered that is and everything.
09:56But now I'm going to set its color to white, and we won't be able to see it very well anymore.
10:02Here's the Text Color and make it White Color.
10:08And so now it becomes much more difficult to see, but it is there.
10:12I'm going make sure this is properly centered.
10:16That is just necessary because this is actually a darker background than what it looks like.
10:21So, we going to grab one more Text Label here, and we're going line this up so that it's
10:26centered under this other Text Label that we have got there.
10:29And I'm going to grab the ends of it and drag them out to the sides.
10:34This one is going to say, "Enter a URL," and that will serve as a prompt.
10:38It is also going to serve as a status line, and this is going to be System Font and its
10:43Size is going to be 12.
10:48And again, we're going to set the color to white so it shows up really nicely.
10:53So, I can either select it down here or I can select it from the Recently Used Colors.
10:57So, that will be White also, and we'll have trouble seeing it until we run it.
11:01Now, we're going to grab a Text Field, and we're going to drop that in right under the Text Label.
11:07You see these little guides. They really help with this a lot, for lining things up.
11:14Our Text Field is going to start with http://. And I'm not using that as a placeholder text
11:20because we don't want it to disappear when we start to type in there.
11:23We want to be able to actually use that as a prefix or select it and get rid of it if
11:26we want to. So that works really well.
11:28We're going to set some options down here: Capitalization, None, Correction, No, the
11:35Keyboard will be the URL keyboard,
11:37its Appearance is the Default, and the Return key will say Done.
11:44And we're not going to change the Text Color on this one because it's going to show up
11:47like this with the white background, and it will actually look really nice with that textured background.
11:52Now, we're going to add a couple of buttons, round rectangle buttons. And I'm going to
11:58start with them over here to the left.
12:01And I'm just going to kind of put them close to each other like that, and then I'm going
12:05select both of them and drag them to the center so that they're centered but they're spaced just nicely.
12:10And the one on the left is going to say Cancel, and the one on the right is going to say Add.
12:19Now, I'm just going to scroll a little bit so we can see our Controller Delegate--it's
12:25really difficult with the amount of space I have here on the screen--because we want
12:28to be able to hook up a few of these things here.
12:31Firstly, I'm going to control drag from the text field all the way down here to our controller,
12:37and I'm going to select Delegate.
12:41All right, and that allows this Text Field to delegate its protocol to our AddViewController,
12:49and I'm going to press Command+S here. That allows us to do this thing down here.
12:54Text Field should return, that allows us to get this message when the Done key is pressed on the keyboard.
13:01And the Cancel and Add buttons, again, I'm going to control drag all the way down here.
13:07So, that's the Cancel action.
13:13It looks like it worked. Let's just do it this way.
13:17Check and make sure that worked.
13:19Yes, there is our Cancel action, that's great. And our Add action, I can just drag right
13:26from there to our Add button, and it's Touch Up Inside.
13:30You'll notice that the Default Action is Touch Up Inside, so you can drag it this way.
13:34It's just a little bit more complicated to do it that way.
13:36If I didn't do that, I can drag it from here, and I have to drag it all the way down here
13:43to the Add action there.
13:46And then when I select this, we can see that we get that Touch Up Inside action.
13:52So, if we select the Controller and our Connections Inspector, we can see all of these connections.
14:00Our statusLabel will go here to our white label there.
14:05Our URL Text Field will come here.
14:08And now, it looks like we've hooked up everything that we need to hook up.
14:11So, I'm going to press Command+S again to make sure this is saved.
14:16And now let's go ahead and run it on the iPhone Simulator.
14:19I'm going to select our Run button here.
14:22Now, we're just going to press this Plus button, and there's our modal dialog.
14:29And you'll notice that it gave the focus to our Text Field, and so here's our little keyboard.
14:34Our label RSS Feed or Enter URL in white, those are very nicely visible.
14:39If I press the Cancel button, it dismisses it.
14:42If I press the Add button, of course dismissing it is all that anything it does. And if I
14:47type in a URL and press the Done button, you see that that dismisses it as well.
14:53We now have a working storyboard interface that we can use for the modal dialog box.
14:58The next step will be to implement the methods in the AddViewController so we can start
15:02adding feeds to our database.
15:07
Collapse this transcript
Finding a feed link in a web page
00:00Now that we have the Add View constructed, our first task is to get the URL for the RSS feed.
00:05Many website support the RSS autodiscovery specification using a link tag to point to
00:11the URL for an RSS feed.
00:14Our Add View controller will have support for either the URL of an RSS feed or the URL
00:18of a web page that supports RSS feed autodiscovery.
00:22When the user enters the URL, it could be either a web page or a feed.
00:26So the first thing we need to do is use NSURL Connection to fetch the URL.
00:31Then we inspect the MIME type to find out if it's a web page or an RSS feed.
00:36If we have a web page, we need to look in the header section of the web page to see
00:39if there's a link tag pointing to an RSS feed, and then go fetch that URL and treat it as the feed.
00:45For example, Ars Technica here, if I press Option+Command+U--this is Chrome so that will
00:51show the source for the web page--
00:54you notice down here we have this link tag right there: relationship, alternate, type,
00:59application rss+xml, and then the URL of the RSS feed.
01:03So, that's the RSS autodiscovery right there.
01:07On the other hand, Macworld's web page, if I press Option+Command+U to view the source,
01:13you notice there are a lot of link tags here, but those are all relationship style sheet.
01:17There is no RSS autodiscovering in this page.
01:20If I just search for the letters RSS on the page, all we find is this link to another
01:27page with the RSS feeds on it.
01:29So macworld.com is not supporting the RSS autodiscovery.
01:34Our implementation here in BWRSS is a very simple implementation that works in most circumstances.
01:39It does not support multiple RSS feeds per page, nor does it support relative links.
01:45You can see the full specification for the RSS autodiscovery here at the RSS Advisory Board website.
01:52Now, let's set up our Add View Controller to discover and fetch an RSS feed.
01:56So, we're going to start with our addView-02, and I'm going to use the addView-02-done here.
02:04You can start with the code that you wrote in the last movie if you're following along.
02:07I want to make a working copy of this, and I'm going to rename it to addView-03.
02:12I'm going to go ahead and open that in Xcode by double-clicking on the Xcode project file.
02:18I'm going to go ahead and hide this right-hand pane so we have a little more room on the screen here.
02:24I'm going to come back out to the Finder, and I'm going to open this methods.txt file,
02:29addView-03-methods.txt, in my text editor. And coming up here to the top of the file, I'm
02:35just going to grab the Error handling and Utilities, all the way down here to just before
02:42the RSS Feed Management.
02:43I'm going to press Command+C on my keyboard and paste this into the bottom of this file,
02:49just above the @end there. There we have it.
02:53The error routines are very straight forward.
02:56And the utilities, we have the statusMessage. This is new.
02:59What it does is it takes a variadic formatted argument or argument list, and it formats
03:07it and sets these statusLabel.
03:09The best way to explain this is to show an example of it.
03:12If I come back up here to our button actions, and the addAction, I'm just going
03:16to comment out this dismissed view controller, and I'm going to say self statusMessage and
03:25Add button pressed.
03:26And now, when I run this in the simulator-- select the iPhone Simulator and press Run--
03:33and I'll bring up our Add Feed view--
03:38And you notice when I press the Add button, you watch the statusMessage here on this text label.
03:43I press Add, and you see it says Add button pressed. Press Cancel, it goes way.
03:49If I do it again, you'll also notice, if I press this Done button down here, we get the
03:52same thing, Add button pressed. And that's because we have here textFieldShouldReturn.
03:58This class is set up as the delegate for the textField and so anytime that button is pressed,
04:03it just calls addAction and then we get our statusMessage again.
04:07So that's what statusMessage does. It's variadic.
04:10It allows for parameters, and we'll see a lot more examples of it as we go through this code.
04:16Now, let's fetch the web object with NSURL connection.
04:18We're going to come back out here to where text file. We're just going to select everything
04:23else here, all the way down to the end.
04:31You notice we have our button actions as well.
04:35Those are going to replace the ones. We'll move those ones we copied them in.
04:38So, let's go back into Xcode and come down here to the bottom, and I'm going to paste those in here.
04:45And you notice that these button actions, they get the error because they're duplicate.
04:49I'm just going to cut with Command+X and come back up here to our button actions and paste them in there.
04:59Press Command+S to save.
05:02So what we have here now, you'll notice in Add action, we're calling getRSSFeed, and
05:11we find that down here in RSS Feed Management. getRSSFeed, it first fixes up the URL to make
05:16sure that it has either a prefix of HTTP or HTTPS. And if not, it adds that by appending
05:23the string. And then it calls fetchURL, and fetch URL actually sets up the URL request
05:28with NSURLRequest. Aetting the delegate to self, and it calls that and passes off all
05:34of our execution to the NSURL delegate methods.
05:38Our NSURL delegate methods are very straightforward.
05:42You notice a lot of these methods are checking the BWRSSState to see if we're in the Parse
05:46Header or State Discovery mode.
05:48If we're in the State Discovery mode, then we're actually looking through an HTML file
05:53to find that RSS Discovery link tag, and if we're in the Parse Header mode then we're
05:58actually going through an XML file and reading the RSS data.
06:02But the rest of this we've mostly seen before. When we received before when we receive data,
06:05we append it into our mutable data structure. And on DidFinishLoading, depending on if we're
06:12on the discovery mode or the parse mode, we call the appropriate function.
06:15Now at this point, we're not ready to start parsing things yet,
06:19so we're going to go ahead and comment this out and comment this out. And I want to put
06:24in a little status message here so that we can see that we are actually getting the data
06:29from the feed, so I'm going to say self statusMessage, and I'm going to say Have, %d bytes of data,
06:39and we're going to get that from our xmlData.length.
06:42So, we save that with Command+S.
06:47Make sure the iPhone Simulator is selected, and I'm going to press the Run button.
06:52Looks like I didn't stop it last time. That's okay. I just press Stop, and I'm going to
06:57bring up our Add View Controller and type in cnn.com this time, because I know that's
07:03a good amount of data.
07:04I'm going to press the Add button, and here we have it, Have 134,791 bytes of data.
07:11Of course, your result will be somewhat different than that because I'm sure they change their
07:16website constantly.
07:18So at this point, we have fetched the web object, and you can see that result there
07:22and in DidReceiveResponse,
07:24we can check the mime type to find out if it's a web page or an RSS feed.
07:28If it's a web page, we need to check for a link tag that will point us to the actual
07:32RSS feed, and this is done in the rssLinkFromHTML code. Stop our simulator.
07:43There's the rssLinkFromHTML. And you'll notice that it uses the NSScanner object to scan
07:51through and look for a link, the relationship, and the type, and if it has the correct mime type.
08:00And so, if we come back up here to connectionDidFinishLoading--and we will uncomment this so that now we're
08:08calling findFeedURL--and then, down here in the StateParseHeader, we can put in a new
08:15statusMessage, and we'll go ahead and run this again in the Simulator. Type in cnn.com
08:26and press Add, and now we have an RSS feed.
08:30So, now we have found and retrieved the RSS feed from a web server.
08:34This involved fetching the provided URL and determining if it was a web page or an RSS
08:39feed, and for the RSS feed we simply fetch the feed for parsing, and for web pages we
08:44search for the first link tag that links to an RSS feed and fetch that for parsing as a feed.
08:50Now we can go ahead and parse the feed using NSXMLParser, and we'll do that in the next movie.
08:55
Collapse this transcript
Parsing the feed with NSXMLParser
00:00Now that we have an RSS feed, we need to run NSXMLParser to get the title and description of the feed.
00:07These will be stored in the database and used for displaying the main feed table view.
00:11In this movie, we'll concentrate on parsing the feed.
00:14We'll start by making a working copy of BWRSS-addView-03, and I'm going to use the -done version.
00:21You can use the version that you worked on in the last movie if you're following along.
00:24I'm going to rename this as addView-04 and open it in Xcode by double-clicking on the
00:30Xcode project file.
00:32I'm going to come back out to the Finder now, and I'm going to grab this methods.txt file,
00:38and I'm just going to select all of this.
00:40This is just all of the parser code. And I'll select all with Command+A and Command+C to
00:46Copy, and come back here into Xcode and drop it in here at the bottom before the end tag.
00:54Command+S to save, and we're going to back up here to connectionDidFinishLoading, and
01:01where we have this self parseRSSHeader,
01:04I'm going to just uncomment that. And then we're going to come up to haveFeed, which is
01:11in our RSS Feed Management. And where we call the delegate haveAddViewRecord--
01:17we haven't implemented that delegate code yet--
01:19I'm going to comment that out.
01:21I'm also going to comment out this dismissViewController so that we can see this result. And I'm going
01:27to put in a status message, self statusMessage:@* Have feed, and it's name, which will be from feedRecord
01:36kTitleKey, and Command+S to save.
01:41Now, let's go ahead and run it in the Simulator. And we'll add that CNN feed again. And we
01:50have the feed, and you can see it says, "CNN.com Top Stories," and that means that we are
01:55successfully parsing the feed because that's the title of the feed.
01:59So, I'll press Cancel just to dismiss our view controller and come back over here to
02:03Xcode and press Command+. to stop the simulator.
02:08Let's take a look at the parsing process.
02:10Again, this is very simple and straightforward.
02:14We call the parser, and the parser starts its process and uses these callback methods, these
02:19delegate methods, in order to allow us to control the different parts of the parsing process,
02:24and to extract our data where we need to.
02:27DidStartDocument allows us to set up our feed record to MutableDictionary. didStartElement
02:32gets called at the beginning of each element and allows us to finish up the element before,
02:38and to store some data. And you'll notice that there is something here that's not working
02:42in iOS 6, and I'll get back to that in a moment.
02:48Parser didEndElement gets called at the end of each element. And again, it allows us to
02:53process the data from that element. parser foundCharacters for elements that are containers,
02:59this allows us to accumulate date within those containers. And parseErrorOccurred gets called
03:05whenever there is an error, and when Abort is called, although that's not working in iOS 6.
03:11So, let's come back up here to didEndElement, and you see this if (haveTitle && haveDescription),
03:17didFinishParsing = TRUE, and then a call to parser abortParsing.
03:21Now, what's supposed to happen when you call parser abortParsing is you're supposed to
03:26get an error message sent to parseErrorOccurred saying that the parsing had been aborted.
03:33And this used to work fine and previous versions of this code used this because we're
03:38just looking for a few items in the top part of the XML file;
03:41we don't need to parse an entire 100k XML file just to find the first few entries in
03:45the file, and that's what this is supposed to before.
03:48So, when we get our title and our description, we want to just abort at that point and stop
03:54wasting everybody's time and energy. And this used to work in previous versions. Starting
03:58in beta 4 of iOS 6,
04:00this did not work anymore. And I was finding that existing versions of my RSS reader had
04:06just stopped working on iOS 6, so I hunted around, I found the problem, and I found the
04:09workaround, and I sent a bug report to Apple and they have acknowledged that. But it has
04:13not yet been fixed, and we're now on iOS 6.1 as in beta as I'm recording this, and this
04:19particular bug still hasn't been fixed.
04:21So, I've just taken it out.
04:23We're not doing that anymore. And we're parsing the entire file, although you'll notice that
04:27that I set a flag that says didFinishParsing, and I have this in a lot of these methods,
04:32if (didFinishParsing), and I just return, so that I'm still not wasting anymore energy than I need to be.
04:39So, we're now successfully parsing the header of the RSS feed, and as you can see, this
04:44is a lot less complicated than the parser in the item view controller because here,
04:48really, we're only looking for a couple of things.
04:50The delegation pattern used by NSXML parser and also used by a lot of the Cocoa framework
04:55is flexible enough that we can really just pay attention to the parts that matter, giving
04:59us the simplicity where we need it or the complexity where we might need that.
05:04
Collapse this transcript
Delegating back to the parent view
00:00Now that we're parsing the feed header, we need to send data back to the FeedsTableViewController for processing.
00:06Remember, the AddViewController object is a modal dialog.
00:09What we want to do is little processing as possible there.
00:11We created a small delegate protocol for communicating with the FeedsTableViewController, and now
00:16we're going to use it.
00:17So, let's start by making a working copy of addView-04, and I'm going to use my -done version.
00:24You can use the one that you worked on in the last movie if you like, if you've been following along.
00:29And I'm just going to call this addView-05, and I'm going to open it in Xcode by double-clicking
00:35on the Xcode project file.
00:37Now, if we notice in our addView.h file, we have this protocol that we define, this RSSAddViewControllerDelegate
00:45protocol. And it has three methods in it, and those methods are actually going to be
00:50run in the FeedsTableViewController.
00:52So, the FeedsTableViewController is going to be the delegate for this delegate protocol.
00:58And you'll notice right here we have this property which is called delegate, which is
01:01of type id with this delegate protocol.
01:05And you'll notice, back here in our haveFeed method, we actually call haveAddViewRecord,
01:14which is one of our delegate methods, haveAddViewRecord on that delegate.
01:19So, I'm going to uncomment this, and I'm going to uncomment this to dismiss the view controller.
01:24And now we need to set this delegate property here, and that gets set from the FeedsTableViewController.
01:30Now, in the FeedsTableViewController, this is going to be a set in our segue, because
01:37our segue is what happens when we press on that Plus button. Then we get the segue to
01:41the AddViewModelController and the model controller, it slides up the screen with that animation.
01:47It covers the entire screen.
01:49And before we can start handling this in the segue, we need to know about it, so we're
01:53going to come in here to our controller.h, and I'm going to import our AddViewController
01:59header. And I'm going to come down here to our interface which defines the class type
02:05and the parent class type.
02:06I'm going to declare this protocol type as well.
02:09So, this is our RSSAddViewControllerDelegate.
02:11So, I'll save here, and I'm going to come back over here to the end file, and now we
02:18can handle this other segue.
02:20Now, if you remember, we come over here to the iPhone storyboard--and I'm just going
02:25to display this right side real quick.
02:31So, this is the segue here, and it has the segue identifier, SegueToAddView, so I'm just
02:38going to copy that so that I can paste it in and know that I have spelled it correctly.
02:43Over here, I'm going to say else if (segue. identifier isEqualToString:@"SegueToAddView"), and then
02:54I'm going to declare a pointer to the BWRSS AddViewController class. And that's our destinationViewController
03:04in the segue, so I can just say destinationViewController.
03:09Now that we have a pointer to that destinationViewController, I can set its delegate to this FeedsTableViewController.
03:18Now, when the AddViewController calls something on its delegate, it's going to be calling
03:23it on this controller, the BWRSS FeedsTableViewController.
03:27This controller is declared to handle that protocol.
03:32You notice up here it says that our protocol is not implemented yet.
03:36That's because we haven't yet added those methods. And so I'm going to add those methods
03:42right here before the database methods. And we'll come out here to the Finder, and we'll
03:45open our 05-methods.txt file, and there they are. I'm going to select all and copy and come
03:54back into Xcode and paste them in right there. Command+S to save.
03:59So now, our AddViewController, when it has a feed, it's going to call this haveAddViewRecord
04:04with the feedRecord.
04:06Here in our FeedsTableViewController, here it is, and it's going to get that record,
04:10it's going to sign it to this new feed variable. And so we need to do one more thing.
04:14When that gets assigned, we need to come back up here in our view stuff, and I'm going to
04:20come down here and I'm going to declare a viewDidAppear, and if (newFeed), (self loadNewFeed).
04:33If we come down here and we see what loadNewFeed does, it goes ahead and either inserts it
04:39in the database or updates it in the database, and it does this nice animation reveal.
04:45We'll see what that looks like right now.
04:47We're going to go ahead and run this in the simulator.
04:49So now, let's go ahead and add that CNN feed-- CNN.com--and I'll press Add, and you see it
04:58has that nice little horizontal reveal.
05:01You notice it's using this UITableViewRowAnimationLeft, and it's using the same one here when it's updated.
05:08So, if I go ahead and put in that same URL, you'll notice that it comes in here and it
05:14just rotates it into place like that.
05:17So, if we come back up here to our AddViewControllerDelegate method, you'll notice here that there is
05:22URL errors and there is RSS errors.
05:25So, if I come back here to the simulator-- and let's just put in something that doesn't
05:30have a feed, like for instance music.bw.org I know that one doesn't have a feed--and it
05:36says, RSS Error did not find a feed.
05:38So, that's this haveAddViewRecord message. And for an error, if I put in a URL that just
05:44doesn't exist, like x.y, and click Add, it says, URL Error, a server with a specified host
05:50name could not be found.
05:51So, those are these two messages here.
05:54So now the feed is being properly added and updated, and it's all working quite well.
05:58The delegate protocol that we created is very easy to use, and it's also working well.
06:03This allows the modal view to do its job while passing its results back to the main
06:07view so that it can do its job. It's all very neat and tidy.
06:12
Collapse this transcript
Deleting feeds
00:00Now that we can add feeds, we should be able to delete feeds, too.
00:04Cocoa Touch has a neat UI for this.
00:06You can press an Edit button which will reveal special red delete icons, or you can swipe to delete.
00:11This interface is easy to implement, and because it's so common, it will be familiar to the user.
00:16So, we'll start by making a working copy of BWRSS-addView-05, and we'll rename it as 06.
00:22So, I'm going to use the done version here. And you can use the done version or you can
00:28use the version that you created in the last movie if you've been following along.
00:33And I'm going to open this in Xcode by double-clicking on the Xcode project file. And we're going
00:39to come back out here to the Finder and I'm going to open this 06-methods.txt file.
00:47And it just has this one method in it, and I'm going to copy that and come over in to Xcode and we'll paste it in.
00:54We're going to put this right at the end of the tableView section.
01:00We'll go ahead and delete all of this, and we'll just paste it in right there.
01:05This method is called tableView commitEditingStyle forRowAtIndexPath, and it passes this editingStyle,
01:12and if the editingStyle is the ViewCellEditingStyleDelete, then we go ahead and implement the delete.
01:19So, this is really very simple, and if we go ahead and run this in the iPhone Simulator,
01:26we see we have the CNN.com Top Stories that we added in the last movie.
01:30I'm just going to press this Edit button and you'll notice there I get these little red Delete icons.
01:34If I select the one next to CNN.com Top Stories, I get a Delete button, and I can press that,
01:40and it deletes it, and I can press Done, and it's gone. And that's all what we've just implemented here.
01:46It actually deleted it from the database and it loaded the FeedIDs again and displayed
01:51them again, and it calls this deleteRowsAtIndexPath with RowAnimation to animate the delete, and
01:58we're using this fade method.
02:00We can change this, and there's a number of different methods available. We could use
02:03one called Left. I need to stop it and run it again. And I'll go ahead and I'll add
02:11CNN again, and then we delete it.
02:15We will go ahead and this time we'll do the swipe gesture for delete, and when we do the
02:18swipe gesture, we get the same little Delete button, and you'll notice this time it's swiped
02:22off to the left for the delete.
02:24So, we have left, we have right, we have top, we have middle, and we have automatic, as well
02:30as the fade that we started with.
02:33The middle one is a little bit interesting.
02:34It might not show up well on the screen, but if you try this on your computer--
02:38I'm going to go ahead and run this again, and we'll add that same feed again, and we'll
02:46go ahead and delete it--
02:47you see that it folds over when I press this, and it deletes it that way.
02:52So, I'm just going to return this to the fade version, and we'll save that I'm going to press Command+.
02:57to stop it running on the simulator.
03:00So, that's really all there is to it.
03:02Cocoa Touch makes this really easy to implement and all the heavy lifting is done for you.
03:06All you need to do is implement the proper delegate method, and it works just fine.
03:11
Collapse this transcript
6. The Web View Controller
Creating the web view class
00:01In order to display pages in the WebView, we need to create a class for the WebView
00:05delegate methods, and we need to create the view in the storyboard.
00:09So, we'll start by making a working copy of the BWRSS-webView-start. That's in chapter
00:156 in our exercise files. And I'm just going to drag it here with the Option key pressed
00:22and rename it to BWRSS-webView-01. And we'll go ahead and open this in Xcode by double-
00:30clicking on the Xcode project file. And I'm just going to do a couple things here to get situated.
00:37I'm going to make sure there are iPhone Simulator selected.
00:40I'm going to open a couple of these disclosure triangles, and we're going to start by creating a new class.
00:47So, I can either select File > New > File here, or I can just right-click on the BWRSS
00:55group and say New File.
00:57This is going to be a Cocoa Touch Objective-C class.
01:01Press Next. And it's going to be called BWRSSWebViewController. And it's a subclass of ViewController, so
01:10if you have TableViewController or something else selected, you want to make it a subclass
01:14of ViewController. And leave both of these unchecked.
01:17It's not targeted for iPad, and it's not using a NIB file, so we say Next. And it will be
01:24in the BWRSS group and with the BWRSS Target checked, and this is the correct folder for it.
01:32So, that's all good. We select Create, and there it is.
01:36You notice it drops it in down here at the end because it's kind of alphabetical.
01:41I'm just going to move it up in there. And I'm going to open up the .h file and come
01:46back out here to our finder, and you see here we have the 01-header.text file there.
01:54I'm going to open that up in my text editor.
01:57I'm just going to select all of that and come back in here to Xcode, and if I select this
02:03and replace this line with all of that, it actually comes out right.
02:07You'll notice--I'm going to minimize this Utilities bar over here.
02:11You'll notice we're implementing the WebViewDelegate protocol, and we have an IBAction for something
02:19called an actionButton. We'll see what that is in a little bit here. And we have IBOutlets
02:24for the webView and a backButton and a forwardButton, and a property for feedItem that gets passed
02:31from the Items View Controller when this view is launched.
02:33So, I'm going to press Command+S here to safe.
02:35I'm going to move over here to the .m file. And all we really need to do in here, and
02:40you see because this is just based on the View Controller, it's pretty lightweight here.
02:45It doesn't have a lot of stuff in the template.
02:47Also, you notice this little exclamation point. It says, "Incomplete implementation," That's
02:51because in our .h file, we have this IBAction method, and it's not defined in here,
02:57so we're going to go ahead and define that.
02:58We're just going to put that down here. And it looks like that, and we're just going to
03:05put a little NSLog in here for now.
03:09And what's that's going to do is when this button is pressed, it's going to display in
03:15the log the name or signature of it's function, which will look kind of like that, and the
03:21URL that's been passed from the Items view, and that just will let us know that this button
03:26is working when we press this particular button.
03:29So, I'm going to press Command+S to save this, and we're going to come over here now to our
03:32iPhone storyboard--that's this one here-- and we're going to create our WebView.
03:39Now, I'm going to bring this Utilities panel back out.
03:44I'm going to scroll back over.
03:46This is a little bit complicated to do with the limited real estate here.
03:49Zoom out, I'm going to grab us a new View Controller, and that's going to go over here in some place.
03:56Try and align that up a little bit. And it's going to insist that I scroll in to do this next part.
04:03I'm going to create a segue.
04:05Now, when I create a segue, I'm going to hold down the Control key and I'm going to drag
04:09from this prototype cell, and that will create the segue.
04:13I'm going to select Push.
04:14Now you'll notice that one of the things that it does here is it adds that disclosure arrow
04:19back into the prototype cell, and it sets this accessory property here to Disclosure Indicator,
04:25so I have to set it back to None if I don't want that.
04:28So now, we have this new view.
04:31And in this new view, we want to have a WebView and we want to have a toolbar.
04:35So, we're going to start with the toolbar because it actually make sense, because then
04:40the WebView will snap into the right place.
04:42So, I'm going to grab this toolbar here and I'm just going to drop it into the bottom,
04:46and I'm going to grab a Web View now, and that's in Data Views.
04:51And you'll notice that it just kind of fills that remaining space just nicely.
04:56And then I'm going to come down here and I'm going to set the class of the View Controller.
05:02So, I'm selecting the identity inspector, and I'm going to select our Web View Controller for that.
05:09Now, whenever I hover over that, it says Web View Controller.
05:12I'm going to make sure that our segue is named properly, so I'm going to select the segue
05:17here and come back over to the Attributes Inspector. And I'm going to type in SegueToWebView and press Enter.
05:27Now, our segue is named properly.
05:29Now, I want to add some buttons to our button bar down here, but before I do that I want
05:33to show you the buttons.
05:34A couple of these buttons I've had to create them myself, and I used PhotoShop.
05:38You can use whatever application you want to.
05:40I'm going to press Command+S to save here and come back out to the Finder.
05:43And here, in this Assets folder, you'll see four PNG files. And if I bring these up in
05:50Preview, see there's one called back-arrow.png, and it looks like that, and there's back-arrow@2x.png,
05:58and it's the same thing, just a little larger, forward-arrow and forward-arrow@2x.
06:06The thing that these images is these are going to go on a toolbar, and the way that these
06:11work is that the only thing that's actually used in the toolbar is the transparency mask of the PNG file.
06:18So, what color it is, what image is in there, any of that is completely discarded, and all
06:24that's used is the transparency mask.
06:26So, I just make them black on transparent, and that works out just fine.
06:31So, I'm going to take these images and I'm going to drag them into our Supporting Files
06:36folder here, and you'll notice that we get this nice little dialog box.
06:41I'll make sure that copy items is checked. Create groups, there aren't any groups so
06:45that's fine, and Add to target this BWRSS.
06:48So, I select Finish, and there is our four graphics there.
06:54Now, when we come over here to our toolbar-- and I'm going to just select this item.
06:59You notice the toolbar starts with one item on it. And I'm going to say that it's plain.
07:04It doesn't have a border, and I'm going to select an image for it.
07:06You'll notice that our graphics are here.
07:09I don't want to select one of the @2X ones. That happens automatically.
07:13If I select the back-arrow, for the retina displays, the @2x, the larger-size one, will
07:18automatically be used.
07:20So now, we have a back-arrow.png there, and you'll notice that it displays just as you
07:25would expect it to.
07:26It's just using the transparency mask to find the boundaries of the image.
07:30So, that's pretty nice, and that works great.
07:32I'm going to come back over here to Windows & Bars, and I'm going to grab the Flexible Space.
07:38What we're going to do is we're going to put five buttons out here and flexible space in
07:42between all of them.
07:42So, that's four flexible spaces.
07:44I'm just going to drop all of those in place right now because it's convenient and easy
07:48to do it this way.
07:50And then I'm going to come back up here and I'm going to get Bar button Item, and I'm
07:53going to get four more of those.
07:55We've got one already. And I'm going to drop all of those in between the flexible spaces.
08:00So, that lays it out just perfectly, like that.
08:03And then for each of these, I'm going to make them Plain.
08:06And this first one, this will be the right-arrow image, the forward-arrow image, and this next one, Plain.
08:13This next one is going to be the Refresh image.
08:18That's one of the stock ones.
08:19This one is going to be the stop image, so Stop.
08:24That's got that X to it. And you see how they just resize and that flexible space in between
08:28just works to hold them all exactly the same space apart.
08:32It works really nicely.
08:33And this last one is one that is called Action, and that's the one that's going to get that action method.
08:40That's for, when you press that it will load the web page up in Safari. It will move away from
08:45this app and open it up in Safari for those times when you want to load a web page in Safari.
08:49Of course, these flexible spaces won't actually show up on the app, but it's all going to
08:54look really nice like that.
08:56And now we're going to hook things up.
08:58We can come over here to our Web View Controller, and we're going to select the Connection Inspector
09:04here, and you'll notice that we have this Web View Property.
09:07Remember in our WebViewController.h, we had this WebView IBOutlet, and that's what that is.
09:15And so we're going to grab that, and we're going to hook it up to our WebView.
09:18And these Back button and Forward button items, these are the IBOutlets that we declared for
09:22those. And that actually allows us, not so much to intercept these, but to refer to them
09:29so that we can gray them out and inactivate them when they're not valid.
09:33And we'll see how to do that later in this chapter.
09:37This Action button, that's what we can intercept that action.
09:41And then we're going to select the WebView, and the WebView itself has some actions that
09:46we can hook up to these buttons so that all of these buttons automatically work with the WebView.
09:50We've got the Go Back button, which go to our left arrow;
09:54and our Go Forward button, which will go to our forward arrow;
09:57reload, which will go to the Refresh button; and Stop Loading, which will go to the Stop button.
10:04So that's all based on the WebView itself.
10:06Okay, so I can save this.
10:08And in order for this to work, we need to go back here into the ItemsViewController
10:13and hook it up to the segue.
10:15So, in order to use this class from here, we need to import its header file.
10:21So, I'm going to come back out here to the Finder now, and I'm going to grab this ItemsTableViewController-01methods.txt
10:28file, and that has our segue delegate for calling up our WebView.
10:34So, I'm going to come back into Xcode, and I'll just drop that in right here before the
10:42Table view data source part.
10:45And it looks for the Segue identifier, SegueToWebView, and I'm going to press Command+S to save.
10:50We'll go back into our iPhone storyboard, and we'll take a look at this segue, and we
10:57see that's SequeToWebView. So, that's right.
11:02It creates a WebViewController, a pointer to that object. From our destinationViewController,
11:11it grabs the IndexPath for the selected row, and it uses that to find their correct item
11:17record from the database, and it passes that item record into the feedItem property in
11:21the WebViewController.
11:22So, this should all be familiar at this point.
11:24We've done this several times before in this course.
11:27Now, if we come back in here to our WebViewController, we can see we don't have any of the view methods
11:33set up yet, so we'll just get a blank WebView. But what will happen is when we press that
11:37Action button, we should get a little NSlog here that shows our feedItem URL, and that
11:42will tell us that everything is working properly.
11:45So, I'll make sure the iPhone Simulator is selected and press Run, and it builds with no issues.
11:52Now, it will launch the iPhone Simulator.
11:56And there it is. And if I bring up one of these items from the blog for example, there
12:02is our WebView, and there is all our buttons.
12:05They look nice and they're perfectly spaced. And if I clicked on this one on the right,
12:09we should get a log item down here, and we do. And there is that function signature,
12:16and there's the URL.
12:17So, these are the steps you will follow to create most any view over the storyboard.
12:22Now that we have the WebView working and we're calling it successfully from the Items View,
12:27now it's time to code the rest of the class, and we'll start with that in the next movie.
12:32
Collapse this transcript
Coding the web view
00:01At this point, we have a working WebView, and it's being called from the Item View when
00:05the user selects an item.
00:07Now, let's fill in the details in the class.
00:09Let's make a working copy of our webView-01, and you can use your results from the last
00:17exercise, or I'm going to use the done version.
00:21You can do that too as well. I'll rename this webView-02 and open it in Xcode by double-clicking
00:28on the Xcode project file.
00:30And we're going to back out here to Finder and grab these methods in this methods.txt file.
00:39I'm just going to copy everything from right up there all the way down to the end of that
00:44section and come into Xcode and just place that down here before the end. And we can
00:53take a look at these.
00:56You'll notice the viewDidLoad has a little red exclamation point. That's because it's a duplicate.
01:02There was a stub already in here, so I'm just going to delete that stub and actually get
01:08rid of our little red bang there.
01:11So, viewDidLoad is called the after the view is loaded and so it sets the title with the
01:17title from the feedItem, and it does some scaling and then it loads the request in the
01:23webView, and you notice it's using the webView property which in the .h file is actually an IBoutlet.
01:30So, that's already been hooked up in our storyboard.
01:33So, that will load the request, and it's going to want to call back the delegate methods,
01:38and we'll load those up here in a minute.
01:40ViewDidUnload, we just clear out our properties.
01:44When view is loaded again later, that just prevents the same web page from showing up
01:47again, which probably won't happen anymore anyway.
01:50Some earlier versions of iOS, this was necessary.
01:53viewWillAppear, it sets the delegate for the webView to ourselves.
01:58And viewWillDisappear, it stops loading if the webView is still loading content, and
02:04it clears out the delegate.
02:05It also sets the networkActivityIndicator to off.
02:09Now, let's come back out here to TextWrangler and load up the WebViewDelegate methods.
02:21When the webView starts loading, this gets called back, and we set our networkActivityIndicator to on,
02:28we also set the status of the our back button and forward button, whether they are enabled
02:33or disabled, to a property from the webView, which tells us whether or not it's possible
02:39to go backwards or forward.
02:40So, this makes our buttons work right, and I'll show you that one when we load this up.
02:45When it's done loading, we set the networkActivityIndicator to no, which turns it off, and we set the
02:54title in our title bar to this document title which we grabbed from JavaScript, from the webView.
03:02So, whatever the document title is set to in the document itself, that will become the title.
03:09So initially, we loaded the title up here from our feedItem title, and now after the
03:16page is loaded, we update the title to whatever the document title is.
03:20And in the event there is an error, we have a little error document here which is just
03:26literal strings, which says that we had an error fetching the web page, and it fills
03:32it in with the localized description from the error object.
03:34So, that's all really straightforward, and I'm going to save all of this, and we're going
03:39to go ahead and run it in the simulator.
03:40Make sure the iPhone Simulator is selected and press the Run button.
03:45Now, we'll just go ahead and load something from the lynda blog here.
03:51And you see, there is our networkActivityIndicator, and here is the document.
03:57You see, we have our reload button.
03:58If I press that, it reloads the page.
04:00There's our network activity spinner, and we have a stop button.
04:03So, if I start the reload and press stop right away, it stops it.
04:08We have our action button, which still isn't hooked up.
04:12That will just display a log entry.
04:13And you notice these back and forward buttons. Those are grayed out.
04:17I can't actually press them.
04:20They're inactive but if I were to click on a link inside of here--there's our networkActivityIndicator--
04:26we've brought up a new page.
04:28So, sometimes the back button doesn't light up, even though it's supposed to, and if you
04:31press the reload button, it makes it work. And this is just a bug in the webView.
04:36So now I can press this back button, and you see there's our networkActivityIndicator,
04:40and it's going back to the previous page.
04:42And now, the forward button is lit up because that is now active, and it's now possible for that to work.
04:49So, if I press that, we'll go forward.
04:50I press that, we go back.
04:52So now, we have a working webview.
04:55Again, using the Cocoa Touch classes has made this very easy.
04:58Most RSS feed items point to a web page, so this solution makes it easier for us to display
05:03that rich data without a lot of coding.
05:05While our webView does display the content nicely and has a few useful features for navigation,
05:11it's not a full web browser.
05:12So, we have a button for passing control of the content to Safari.
05:17When I press this button, of course right now all we got is this log entry.
05:21So, our remaining task is to implement that button.
05:26
Collapse this transcript
Viewing pages in Safari
00:00Now, we have a working webView and we'd like to be able to pass pages off to Safari as
00:05a full-featured mobile web browser.
00:07Let's see how we do that.
00:09We'll navigate here to Chapter 6 of our exercise files, and we're going to make a working copy of our webView-02.
00:16I'm using the -done version.
00:18You can use the version that you created if you've been following along with the exercises.
00:22I'm going to rename that to -03 and open it up in Xcode by double-clicking on the Xcode
00:30project file here in the project folder.
00:33So, I'm going to minimize that and come back up here to our actionButton method. And this
00:42our actionButton that gets called whenever we press that button. It has an NSLog right now.
00:47So, if I run this in the iPhone Simulator, and I'll bring up a page here, and you'll
00:58notice when I press this button, instead of launching Safari, it just displays this log
01:02message that says the URL that's been called.
01:07And so I'll come back here in Xcode. I'm going to press Command+. to stop the simulator.
01:12I'm going to minimize that down there, and we're just going to replace this line with
01:17the line of code that will actually call Safari.
01:20And that looks like this.
01:22It's a method call on an object.
01:24So, I'm going to type in UIApplication.sharedApplication and openURL.
01:37And for the URL itself, I'm going to call self.webView.request.URL.
01:47And so the webView itself keeps a copy of the URL for the current request that is being displayed.
01:54And so that gives us the URL.
01:56This openURL method is called on UIApplication.sharedApplication.
02:00So, UIApplication is a centralized point of control for all iOS applications.
02:07It provides access to system resources. sharedApplication is a property that gives the application instance,
02:14the individual application that you are using.
02:17So, you call methods on the sharedApplication property within UIApplication.
02:22openURL is the system entry point for opening a URL resource with the associated application.
02:29Our HTTP or HTTPS applications will open in Safari.
02:33So, let's go ahead and run this in the Simulator, pressing Command+S to save and clicking on
02:40the run button here.
02:42And now, when I bring this web page up and I press this button here, it will load up
02:50Safari with that URL.
02:53So now, we have a complete working webView.
02:57It's really a very simple task.
02:59Cocoa Touch provides a simple delegate-based webView that's powerful, flexible, and easy
03:04to implement, and it works very well.
03:09
Collapse this transcript
7. Creating a Preferences Pane
Understanding the iOS preferences system
00:00The Settings app in iOS is the interface for application preferences, like the Preferences app in OS X.
00:07When you scroll down in its table view, you'll see a list of installed apps that have preference settings available.
00:14When you tap on one, you'll get the settings pane for that application.
00:19The settings for the application are coded with a normal plist.
00:22Let's take a look and see what that looks like.
00:26This file here is a Settings bundle, and if I right-click or Control Click on this, I
00:31can say Show Package Contents, and you'll see that here's a Root.plist.
00:36That file name cannot be changed--well, it can be, but it won't work anymore.
00:40We've opened this file in a text editor here. You can see this is TextWrangler.
00:46You'll notice that this looks very much like a normal XML file, and that's exactly what it is.
00:53So a plist is a simple XML file, but it's not very easy to edit this way.
00:58This is the same file.
00:59You can see it highlighted down here being edited in Xcode.
01:04This Property List Editor used to be a stand-alone application, and now it's integrated into Xcode.
01:09It provides a Simple Editing Environment for the settings plist.
01:13The plist is easily created and edited in Xcode, and in the remainder of this chapter
01:18we will create a settings bundle for application and learn how to use it.
Collapse this transcript
Creating the preferences plist in Xcode
00:00Oftentimes an application needs a simple way of allowing users to choose some default values for settings.
00:07You can do this with a modal dialog if you have enough of a settings requirement to justify
00:11the coding in UI investment.
00:13The simple solution, however, is to use the iOS settings interface.
00:17Here, we have our BW RSS application so far, running on the iOS Simulator.
00:24And because again, the small screen that I'm working on the iOS simulator has no border,
00:30and it has no Home button.
00:31So, if I want to press the Home button, I press Shift+Command+H on my keyboard.
00:36So if I want to change the settings, I need to press the Home button and run the Settings
00:42application and scroll down here till we see our BW RSS application, and there's the Settings.
00:51So, I can set the maximum items per feed, and I can see the version number.
00:56This is a very simple usage of the settings.
00:59So, if you have just a few things to set, or if you want to display a version number
01:03or something like that, Settings is a common way to do this.
01:07So, I'm going to quit the simulator for now, and we're going to come in here to our BWRSS-preferences-start,
01:14and I'm going to make a working copy, and I'm just going to rename this to BWRSS preferences.
01:21We're not going to have a separate version for a later movie.
01:25And I'm going to launch it in Xcode by double-clicking on the Xcode project file.
01:31So, I'm going to go ahead and open up this disclosure triangle, and I'm going to set the iPhone Simulator.
01:39Under Supporting Files here, we don't yet have it, but we're going to create a settings bundle.
01:45So, I'm going to right click on Supporting Files, and I'm going to say New File and under
01:53iOS, Resource, I'm going to select Settings Bundle and press Next.
02:00Now, you want to leave this default name because that's important.
02:05It won't work if it's named something else, and you wanted in the Supporting Files Group
02:09and in your BWRSS targets.
02:11So I'll press Create, and now we have our settings bundle.
02:15So, I'm going to go ahead and open that disclosure triangle there, and I'm going to select the
02:19Root.plist, and that's where we actually are able to set the preferences.
02:26You'll notice that there's a disclosure triangle here next to this thing called Preference Items,
02:31and there is four items in there and those are just examples, and we're not actually going to use those.
02:38You see, this interface is really weird.
02:41When you click on stuff, stuff happens, and you sometimes have to press Escape.
02:44So, I clicked on that and then I pressed Escape.
02:46I'm going to press my Delete Key here on the keyboard and just delete those three items
02:51and then I'm going to come back up here to Item 0 (Group - Group), and I'm going to open
02:55it up and under Title, I'm going to call this, Feed Settings.
03:00So, I'll select this over here, and I'll type Feed Settings, and we're going to leave that
03:08one as group as Type for this Item 0. That fills out Item 0.
03:13Item 0 has a type of group, and it has a title of Feed Settings.
03:18And then with this closed, I'm going to press the Enter key, and it will create a new item.
03:23I'm going to press Escape, and I'm going to press Enter again, I'm going to do that several
03:28times until I get four items here.
03:30So, I have three new items under Item 0 Group, and we're going to fill these in.
03:35The first one, Item 1, its type is going to be Multi Value.
03:39So, under Type, you'll notice that the arrow is way over here.
03:43I can select that and say Multi Value and its title, I'll double-click in that space
03:49there for the title is Max Items Per Feed, like that.
03:57It also gets an Identifier, and that's going to be max_items_per_feed, and you notice it's an identifier.
04:05It's going to be referenced from the code, so I don't want spaces in, and I'm using underscores.
04:10It's going to get a few more things, so I'm clicking over here on the left because that
04:14seems to be a fairly safe place to click, and I'm going to press the Enter Key, and I get a new item.
04:20This item is going to be a default value so that's correct, and its type is going to be a number.
04:27And over here, I'm going to double-click on that number it'll allow me to edit it, and
04:30that's going to be 50. So, it's going to have a default value of 50.
04:34And when I press Enter, this editor is just really weird for these types of items,
04:39so you have to bear with it a little bit. So, that's default value.
04:43And then we're going to have a new item called Titles, and I'm just going to close that real
04:47quick and make another one and a new item called, Values.
04:50So, it actually defaults to the correct thing here, and if it doesn't, you can always press
04:54that little arrow to the right of the field that you want to change, and you get an opportunity to change it.
04:59So under Titles, there's going to be four items.
05:02Again, cursor jumps around, two, three, and four. Under values, there's going to be four items.
05:14So, I open that up, and I have one, two, three, and four.
05:20All of these values are going to be type Number.
05:23So we'll just go ahead and change those right now.
05:29And their values are going to be 25, 50, 100, and 250.
05:37And then the titles for each of these items are going to be Strings and they're just going
05:45to say the same thing, 25. I guess I could spell it out if I wanted to.
05:49So, these will be the labels that will be next to each of these values, 250.
05:53We'll see how these looks like in the Settings app in a little bit here.
05:58So, there is our titles and our values, and that's Item 1 Multi Value.
06:03Item 2 is really just a spacer. It creates an empty space.
06:09So, its Type is a Group and its Title is blank, and there is no key, so I'm just going to delete that one.
06:20Item 3, its Type is Title, and its Title is Version, its Identifier is BWRSS_Version
06:31like that with an underscore, and it's going to have a Default Value, and we'll just
06:38give it a version value here, 3.1.0, and there, we're done.
06:43So, I'm going to press Command+S to save this.
06:47Now again, to press the Home button, I'm pressing Shift+Command+H, and I'm going to come out here to the Settings.
06:56I'm going to scroll down here, and there is our BWRSS, and there we have our Max Items
07:01Per Feed, which we can change, and we have our Version, which when we click on this, nothing happens.
07:07And you see our title there, it says Feed Settings.
07:09So, that's all of these things here.
07:10So now that we have a working settings bundle, we need to be able to read these values in our code.
07:16And we'll take a look at how to do that in the next lesson.
Collapse this transcript
Reading preferences in your application
00:00Now, we have a working settings bundle.
00:02We need to be able to read the values in our code.
00:05In this movie we'll look at how that is done.
00:07We'll go ahead and open the BWRSS-preferences that I created in the last movie.
00:12I'm going to open that in Xcode by double-clicking on the .xcode project file.
00:18So, this is the version that has these preferences Root.plist in it.
00:24I'm going to come up here into RSSDB and open the RSSDB.m.
00:31So, this is our data base routines, and I just closed the Utilities panel because we
00:38don't need that, it's taking up space here.
00:40If we look down here at the deleteOldItems, we'll see rather along SQL Query it takes up two strings.
00:48Two strings right next to each other in C or C++ or in Objective-C concatenates these two strings together.
00:57Objective-C has borrowed this even with its NSString literals.
01:00So, this is really all one string delete from blah, blah, blah, all the way up to this closing quote here.
01:07Now, what we have here is a subquery. Everything in the parenthesis is a subquery.
01:12So, it's selecting items from the items table and ordering them by publication date with
01:19a limit of getMaxItemsPerFeed and then it's deleting everything that is not in that list.
01:26It's taking the newest so many items, and it's deleting everything else.
01:31So, this getMaxItemsPerFeed is the number of items that's being retained when we delete old items.
01:38So, where is that defined?
01:40So, getMaxItemsPerFeed is up here, and this is actually reading from the user default.
01:49NSUserDefaults grabs our UserDefaults, and we can get our MaxItemsPerFeed by using objectForKey
01:57and using this string max_items_per_feed, and if we remember, down here in our Settings
02:02Bundle, our identifier MaxItemsPerFeed is used for that Multi Value where we select
02:11either 25, 50, 100 or 250.
02:15You'll also notice that if we don't have a MaxItemsPerFeed, we set it to a default value,
02:20and that kDefault, that's defined in our header file and the default is 50.
02:26So let's run a little experiment here.
02:28I'm going to grab the MaxItemsPerFeed value, and I'm going to display it with NSlog.
02:34And I'm also going to display it after we've tested it for default.
02:43Press Command+S to save.
02:44I'm going to go ahead and run this in the simulator.
02:47It's an interesting test because it's going to show one of the limitations of this settings interface.
02:53Now, the first thing I'm going to do when I run this in the simulator, I'm going to
02:56come over here to our iOS Simulator menu, and I'm going to say Reset Contents and Setting,
03:01and I'm going to press this Reset button.
03:04That resets my simulator to its default as if it's a brand-new phone out of the box,
03:08and you'll notice that it's also finish running and so I have to run it again.
03:13Now, we're running this fresh having never gone to the settings before.
03:19When I select one of these feeds, this MaxItemsPerFeed gets called, and you'll notice that the value
03:28from the settings is null and after the test for default is 50.
03:32So, we get a null the first time we call it.
03:35Until you've actually gone to the settings app and selected something, you're not going
03:39to get a value and so you have to have a default value and set it to that default value, in
03:45case what you get from your settings is actually null.
03:48Now, when I come out here to my settings-- I'm going to press the Home button here.
03:51I'm pressing Shift+Command+H on my keyboard for the Home button because my screen doesn't
03:56have one because this is getting scaled down.
03:59I'm going to slide over here and grab the settings app and come over here to BW RSS.
04:05If I select 50 again, and I double tap my Home button and come back to my BW RSS app,
04:11and I'll select this again, you'll see that I'm still getting that null, but if I come
04:18out here to my settings app, and I select a different value.
04:21I'll select 100 and press, double tap my Home button and come out here and select my Feed again.
04:29Now, you'll notice that I'm getting that 100 value from the settings and after the test
04:34because it's not null, I go ahead and I leave that value alone.
04:38So, when you run your app, you're not going to actually get values from your settings
04:43until somebody goes to the settings app and actually changes something.
04:47Even just looking at the value or selecting the default value again, doesn't change something.
04:52Now, when I bring it back to 50 again, now I'll pick up that 50.
04:58So, there we have the 50 before and after the test.
05:02So, we'll go ahead and delete my NSLog items here.
05:07Now, we can see that using the iOS Setting Interface is really quite easy, you just create
05:13the settings bundle, you put it in your settings, and you use the NSUserDefaults class to read those values.
Collapse this transcript
8. Adding a Feature
Adding pull-to-refresh functionality
00:00In this chapter, we're going to talk about the process of adding a new feature to our working code.
00:05After writing this application and submitting it to the App Store, I decided that I wanted to add a feature.
00:10I noticed that when I use the app, I would sometimes leave it for a while with the item
00:15view displayed, and after an hour so I would return, and I'd want to refresh the list to
00:20see what was new in that feed without having to return to the review and select the feed again.
00:25So, I decided to add a feature that would refresh the item view on demand.
00:29The first task when adding a feature is to think about how the user will use it.
00:33What will the interface look like?
00:35One of the things I like about BW RSS is the interface is simple and uncluttered.
00:40I didn't want to add a button, especially on the iPhone platform with its limited screen space.
00:45Before iOS 6, there was no accepted gesture for reloading a page, so I opted to use the shake gesture.
00:51I'd seen it's done before, and I liked how it works, a gentle shake of the phone and the feed refreshes.
00:57Beginning with iOS 6, however, iOS now provides a pull to refresh feature, which is perfect for this purpose.
01:05So here it is already implemented in the emulator.
01:08When I select a feed, I can pull and I get this little icon, and when I let go it refreshes.
01:15Well, there's nothing there. So I'm going to add a feed.
01:19This is a test feed that I've created. It's cleverly called Test Feed.
01:24It's at ios.bw.org/testfeed, and you're welcome to use this.
01:30In this feed, every time it gets called, it gives you five new items.
01:35So when I refresh, I'll get five new items and these are random items.
01:40The source code for this feed is in Libraries, and it's in testfeed.py.
01:45It's a Python script, and this is the implementation of this test feed.
01:51It's not a very long script.
01:52It's about 150 lines long, and you're welcome to use it.
01:56Certainly, if you're going to be using this a lot, I'd rather that you would run it on
01:59your own server than on mine, but if you're just going to use it occasionally,
02:03you're welcome to run it on my server.
02:05And there's a lines.txt file here, which is used, has a bunch of little random disclaimers
02:10in it that I collected at one time in my life. Those are the headlines of these feeds.
02:17Batteries not included, Penalty for private use, Some assembly required, et cetera.
02:23So that's the pull gesture. When you pull on it, it refreshes.
02:28And in the next movie, I'll show you how to implement the pull to refresh feature for iOS 6.
Collapse this transcript
Implementing the pull-to-refresh gesture for iOS 6
00:00Now let's take a look at how to implement the iOS 6 pull to refresh feature.
00:04I'm going to create a working copy of our BWRSS-features-start, and I'm going to rename
00:14that as -02, and we'll open in Xcode by double clicking on the Xcode project file.
00:24We're going to be working in the ItemsTableViewController, and we notice up here at the top in our interface
00:31section, this is the private members or the instance variables for this class.
00:36You'll notice there's a BOOL variable called canRefresh, and that gets set in -viewDidLoad.
00:41If I come down to -viewDidLoad, and we're going to come out to our Finder and load up this
00:49methods.txt file, and here is our new -viewDidLoad.
00:53I'm going to just copy that and come over here in to Xcode and I will paste that in place.
01:00So, you'll notice here I used the respondsToSelector method to check if our TableViewController
01:08response to the selector called refreshControl, and if it does, then I know that we can use
01:14Refresh so I can set this canRefresh equals true, or Yes in the case of Objective-C.
01:19And I initialize our refreshControl with the UIRefreshControl and then I call addTarget
01:25on it to add the target, it is refreshInvoked:forState method, and it will be set for the control
01:34events, UIControlEventValueChanged.
01:37It looks a little bit complicated, and I guess it is, but this is just how you do it, and
01:42you'll pretty much always do it exactly this way.
01:44So, we're going to come back out here to our text editor, and I'm going to grab all of
01:48this support for reload gestures stuff here, and I'm going to come back into Xcode, and
01:55I'm going to paste it in right about here. Here is how this works.
02:02Here's our refreshInvoked forState, and you'll remember that's the selector that we set as
02:08our target for the refreshControl event, right?
02:12So, when that gets called we reload our RSSFeed, and we send endRefreshing message to the RefreshControl, as simple as that.
02:22In order for that to happen, we have to be the first responder and so our class gets
02:27called with canBecomeFirstResponder to test whether or not we have that capability and
02:32so we use this canRefresh flag to return there.
02:35When viewDidAppear, we're going to call becomeFirstResponder, and when view will disappear we resignFirstResponder.
02:44So that's all there is to it.
02:46When I save this and run it in the iPhone Simulator--I'm going to go ahead and add my
02:52test feed here so that's at ios.bw.org/testfeed, and I'll bring that up.
03:01There is five entries, and when I pull you see there is that little icon, and I pull
03:07it far enough, and it goes ahead it calls this rerefreshInvoked which reloads the feed and
03:14ends the refreshing, and there it is again.
03:18So, we've now successfully added the pull to refresh feature to our app.
03:23This was easy for a number of reasons.
03:25First of all, Cocoa Touch Framework is really very well written and easy to code to then
03:30reloading the RSS Feed was also easy because our code is well-organized.
03:34If you do a good job of keeping your code clear and concise, then changing and modifying
03:38your code will always be a lot easier.
Collapse this transcript
9. Creating a Universal Application
Understanding split view
00:00When the iPad was first introduced, a number of people made comparisons to a giant iPhone
00:05that couldn't make telephone calls.
00:07The reality turned out to be something quite a bit more brilliant.
00:11And as a result, well, the iPad has become very popular, selling many millions of units in these first few years.
00:17The beauty of the iPad interface is in its large screen area.
00:22The SplitViewController is an excellent example of this.
00:25It combines two views, the master view, often a table view and the display view, in this case a webView.
00:32In landscape mode the master view is usually on the left side occupying roughly a third
00:37of the screen, and the display view is on the right using the remainder of the screen.
00:42In Portrait mode the display view may command the entire screen and the master view is accessed with a pop-up controller.
00:49This is all accomplished with a programming interface that's consistent with the rest
00:53of the Cocoa Framework, making it very easy to implement, especially if you have experience
00:58writing iPhone or Cocoa Applications or even another event driven architecture.
Collapse this transcript
Coding the table views
00:00At this point we have a complete iOS Application that's targeted for the iPhone form factor.
00:05In order to take advantage of the iPad, we will implement a separate storyboard and a
00:10few additional classes for the iPad platform.
00:13This application was started as a universal app with the intention of supporting the iPad platform.
00:19We can use most of our existing code on the iPad.
00:22We will need some new code to support the split view and a few other features, but mostly
00:26we will just be sub-classing our existing classes and overriding a few methods.
00:31Let's start by making a working copy of BWRSS split view start.
00:36I'm going to rename this to splitview-02, and I'm going to open it in Xcode by double-clicking
00:43on the Xcode project file.
00:46Now let's take a quick look at the iPad storyboard, and you notice that I really need to zoom
00:54this out on this small screen to be able to really see it.
00:59Here we have the SplitViewController--and I'll zoom in a little bit more here so you could see that.
01:07So there we have the SplitViewController with the MasterViewController on the left and the
01:11DetailViewController on the right, and it connects to two navigation controllers, one
01:17for the master and then another one down here for the DetailViewController.
01:22Then we have the view controller themselves as the DetailViewController, and for the MasterViewController
01:29it's been renamed, and it was renamed in one of our movies to be a FeedsTableViewController,
01:36but it's still not set up in the story.
01:38Down here in the DetailViewController, this is where we are going to put our webView,
01:43and for the left side, we'll mostly leave the left side alone.
01:47Most of what we need to do is to update the WebViewController to work as a detailed view.
01:51So let's go ahead and create a class. I am going to come up here to File > New File.
01:57Under iOS > Cocoa Touch > Objective-C class, and I'm going to press Next, and this is going
02:02to be BWRSSDetailViewController, and it's going to be subclass of BWRSSWebViewController.
02:14It's right there, and we're going to ahead and leave these alone for now, because we're
02:17going to filling that in from some results.
02:20It gets stored in here and its group is right and its target is right, and that's all correct.
02:26So I'm just going to press Create, and there are our files.
02:32Now I'm going to come out here to our Finder, and I'm going to open BWRSS-detailview-02-header.
02:40I'm just going to grab these two lines here and copy them, and I'll just close that and
02:45come back out here to Xcode and come into the header file, and I'm just going to replace
02:50this one line with those two.
02:52So basically what we have here is that DetailViewController subclass of the WebViewController, and it
02:59implements these protocols of UIPopupControllerDelegate and UISplitViewControllerDelegate.
03:06And there's one property detail item.
03:08Actually, it's going to get filled in from the item's table view controller, but that'll
03:12happen later on in this chapter.
03:13We're going to come back out here to Finder, and I'm going to open this detailview methods.txt,
03:20and there's just a little bit of code here that we want to put in the .m files.
03:24So I'm going to Command+C, copy that, and close my text editor, come back out here to Xcode,
03:30and go into the methods file, and I'm just going to replace these two lines with all of that.
03:38So here we have a couple instance variables, and we have this property for the Toolbar
03:43and a property for webTitle. In fact, these are IBOutlets.
03:47This webTitle one, it's not actually used in this implementation, but it's there because
03:52it's referenced in some of the code.
03:55That's all we need to do for right now in these files.
03:58We'll get back to them later on this chapter.
04:00I want to come back out here now to the iPad storyboard and get this set up for the iPad
04:06side of our universal application.
04:09We're going to start with our navigation controller.
04:11I'm just going to select that.
04:12I'm going to bring up the properties over here and in the Attributes Inspector under
04:18Simulated Matrix where it says Top Bar we are going to say None, and that will get rid
04:24of this top navigation bar, because we're going to create our own, and that way we can
04:28put buttons on it, and we can make it also our navigation bar for the web view.
04:33We're going to come out here to our Objects, and we're going to grab a toolbar, and we're
04:39going to drag it up here to the top of--it looks like I need to zoom in in order for that to work.
04:44I'm going to drop that up here at the top.
04:51This is our DetailViewController, and that's this one at the end of the chain there on
04:58the bottom, and I'm also going to grab a web view.
05:06I'm going to drop that in right here, and I'm going to have it fill up the rest of this space, and there we go.
05:18So now we have web view, and we have the tool bar.
05:20Now we can go ahead and add some buttons to our tool bar.
05:25There's already one button up there.
05:26There's going to be five buttons, and this time there's going to be spaces on either
05:31side of the buttons as well.
05:32So we're actually going to have six of these flexible spaces.
05:34I'm going to start by putting this flexible space there and another one there and then
05:42three, four, five, and six.
05:48Then I'm going to put in some more buttons two, three, four, five, and you'll see in
05:58a little while why it is that we do it this way.
06:00But the bottom line is that another button will be dropped in here programatically so
06:06that when it's in portrait we can still bring in that table view on the left side as a pop-over,
06:12and that button will automatically be added and removed, and this actually makes all of that look right.
06:18Now we'll go ahead and we'll style buttons so each of them is going to be playing and
06:22these are the buttons for web view so already know what goes in them, because we did that
06:26before earlier in the course.
06:28This first one here is going to be the Back Arrow, and this next one is going to be the Forward Arrow.
06:41Then this one here is going to be the Refresh button and then this one will be the Stop
06:50button, and this one here will be the Action button.
06:54So I have to click this a few times in order for it to select that Action button.
07:00Now we see that our toolbar looks exactly how we want it to look.
07:03So we come down here to the controller itself and over to the Identity Inspector, and that's
07:11correct BWRSSDetailViewControllers. So that's exactly what we want there.
07:16Then we're going to come over here to the Connections Inspector, and you see one here
07:21that says detail description, and it's got an exclamation point next to that, because
07:27there isn't one in this DetailViewController, so that's okay.
07:30We're just going to delete that, and you see we have this web view outlet, and it connect
07:35that to our web view, and we have a Toolbar outlet, so we're going to connect that to our toolbar.
07:41While we are at here we've got Back button.
07:44We can select our Back button item and our Forward button, select our Forward button item.
07:50If we scroll all the way down here, we'll see our Action button item.
07:54We can connect to that one up.
07:56Then we select the web view which I'm just going to tap on it here, and that will give
08:00us a whole new selection of buttons, and this connects them to the web view so that if they're
08:04connected up to the web view, we don't have to do them programatically.
08:08So that's the Go Back button and the Go Forward button and the Reload button, and the Stop Loading button.
08:18Those are all now hooked up as well.
08:20We can scroll up, and we can work on our FeedsTableViewController a little.
08:25So if I select that and come up here to the top of it, and you see it says Master.
08:31I'm just going to double-click there, and I'm going to change that to--I'm going say BWRSS.
08:36That will make it consistent, BWRSS.
08:38And I'm going to select the Prototype Cell and come over here to the Attributes inspector
08:46and the Identifier is going to be FeedsCell and press Enter there.
08:56The style is Subtitle, and you'll notice Accessories says None, but that's going to change when
09:02I create a segue from it. So we'll have to update it again.
09:06Now we have this FeedsTableViewController set up properly, and it's time for us to create
09:12our ItemsTableViewController.
09:14So we're going to grab another TableViewController here, and I'm going drop it in right there,
09:21and it's going to create this whole giant thing, and it's just unfortunate the way that
09:26it does this especially on a small screen.
09:28So I'm just going to set it over to the side here and what's going to happen is when I
09:32create this segue, that will resize the correct size. So watch this.
09:37I'm going to Control click on this Prototype Cell over there in the FeedsTableViewController,
09:44and I'm going to drag it over here and let go and select Push segue and notice that it
09:50now resizes properly, because it's inheriting that from the view that that's being connected
09:57to it, from its parent view.
10:00You will also notice that this Prototype Cell over here got changed to have little disclosure indicator.
10:05So I'm going to select that back to none and press Command+S to save.
10:11Now our new TableViewController, we are here in the Identity Inspector, that's going to
10:16become our ItemsTableViewController and our segue is going to get an identifier to SegueToItemTableView.
10:30And I'm going to come over here to our Prototype Cell and make that a Subtitle and our Reuse
10:36Identifier is going to be ItemCell. ItemCell like that.
10:43Now that we've got all this set up, I'm going to press Command+S to save, and we'll go ahead
10:48and we'll run it in the iPad Emulator. So you can see we have that error.
10:57I press Command+Left Arrow to rotate it, and now we can see our Table Views are working.
11:04So this is pretty much how we expect it to work at this point.
11:08We've done very, very little coding. All we've really done is set up the storyboards.
11:12So we have the Split View hooked up in the storyboard.
11:16This is the foundation for the rest of our work for the iPad side of our app.
11:20The next step is to plug in the code so it shows pages in the web view.
Collapse this transcript
Implementing the iPad detail view
00:00Now that we have the feed and item views running, it's time to implement the Web view.
00:05For the iPad version, we're using the Detail View controller for the Web view.
00:11Let's make a working copy of BWRSS-splitview-02. I'm going to use the done version here.
00:17You can use what you completed in the last movie if you like.
00:22I'm going to call this BWRSS-splitview-03, and I'm going to open it in Xcode by double-clicking
00:29on this Xcode project file.
00:31Now, here in our BWRSSDetailViewController--I'm going to expand this a little bit so we can see that--
00:37see that we have our local instance variables and properties here, and we have just three
00:45little methods inside of this implementation. I'm actually going to delete all of that.
00:50And then I'm going to come back out here to the Finder, and here, we have our detailview-03-methods.txt
00:57file and grab that, and I'm just going to select the whole thing.
01:00You can see there's a lot of typing here, and we'll go through it, and I'll explain in a little bit.
01:04I'm going to select all of that and press Command+C to copy and come in here to Xcode,
01:10and right there with the cursor just before the end marker, I'm going to press Command+V
01:14to paste it all in there.
01:15So, there are a few interesting things going on here.
01:19You'll notice in this section called set up the view when called, there's a method
01:25called setDetailItem, and this is an Objective-C convention.
01:29When you have a property called detailItem-- you see it's a property with the @property--
01:34the compiler will create a setDetailItem and getDetailItem methods.
01:41And here, I'm overwriting that setDetailItem method, so when another object assigns something
01:48to that variable, to that property, the setDetailItem gets called.
01:53And by overloading it, it allows me to do some other things during the process of setting that value.
02:00So here I just set the value at the top, and then I call configureView which is this method
02:05above there, and I dismiss the pop-over if there is one.
02:09And so, what I know is that when that variable is getting set, somebody has tapped on something
02:14because it's in that Items View Controller, and we'll set this up in a moment where that
02:19property is getting set, and so that's where this is being called.
02:22So that allows me to intercept that action.
02:25So it calls configureView which then sets up our NSURLRequest and calls the webView with that URL.
02:35So, the URL is getting passed in this newDetailItem, and that's getting assigned to feedItem up
02:41here, and feedItem is being used to load the webView.
02:46Then down here, we have some what I call split view support.
02:50When the left view is hidden, that means that we're in Portrait mode.
02:54We grab our button bar, and we add a button to it on the left, and we use that to control
02:59the popoverController.
03:01When the left view is shown again, we undo that.
03:05This is the setPopoverButton and clearPopoverButton methods that are being called by those.
03:11So, I'm going to press Command+S here, and I'm going to come back out to TextWrangler,
03:15and I'm going to close that, and come out to finder, and I'm going to load up our ItemsTableViewController-03-methods,
03:24and there's really just a couple of things in here.
03:26So we'll come back over to Xcode, and we'll select our ItemsTableViewController.m file.
03:32First thing I want to do is I want to grab this import, copy and paste.
03:37And that's for our DetailViewController because we're going to be setting a property on that object.
03:43We'll come back out here. And here's our didSelectRowAtIndexPath.
03:47This is what gets called when you touch a row on a table, and that's selecting it.
03:54And if I come up here, we can find that, there it is didSelectRowAtIndexPath.
03:59I'm just going to take this whole method, and I'm going to select the whole thing and
04:04press Command+V to paste in what we've copied out of that text file, and Command+S to save.
04:10So, this is really simple, if (haveSplitViewController), and we set that up above in either viewDidLoad or viewWillAppear.
04:22Here it is, viewWillAppear.
04:24If we have a SplitViewController, then we have a SplitViewController.
04:28We're setting that flag.
04:30And that flag is declared up here as a BOOL in our private members.
04:38So if we have a SplitViewController, that means that we're on an iPad.
04:42Now, I could have tested it for the iPad idiom.
04:44But really, what I'm concerned with here is do we have a SplitViewController?
04:47Because if we're on an iPad, and we don't have a SplitViewController for some reason, then this is moot.
04:53So, if we have a SplitViewController, then we go ahead and we get the DetailViewController,
04:59and we get the WebViewController from our viewControllers array.
05:03And in our WebViewController, we assign to this detailed item, and you remember, that's
05:08going to call our setDetailItem method that we looked at a few minutes ago.
05:13We're going to pass it that itemRecord, and that will make everything work.
05:16So now I'm going to save this, and we select our iPad Simulator.
05:20We're going to go ahead and run it. So now we're in Portrait mode.
05:24I'm going to press Command+Left Arrow, and that will put us in Landscape mode.
05:27And now we have our master control over here, our table views.
05:32And over on the right, we have our detailController.
05:34And so, if I select one of these, and I select one of these, you see our little spinner running
05:39up there, and there's our web page and our WebView and our DetailViewController.
05:43Now, here's the interesting thing.
05:45If I go ahead and just select a different item here, you notice we get a different page,
05:49and now this Back button is lit up.
05:51So I can press that and get back to the previous page.
05:54Unlike the iPhone form factor, this webView is in a separate pane here, and so it's visible all the time.
06:01So there is no reason to clear it out anymore.
06:05If I come over here, and I load up something from the lynda blog, there it is, I can go
06:10back to the previous page that I was at.
06:13So these Back and Forward buttons, they're active more often than they are in the iPhone form factor.
06:20Now the webView is working and so the app is mostly functional.
06:23It's really a straightforward process when you know the ins and outs of it.
06:26Subclassing the existing webView makes it especially easy.
06:30The next step is to implement the AddView modal dialog box, and then we'll be done.
Collapse this transcript
Implementing the iPad modal view
00:00Now that we have a working groupView, itemView, and webView, it's time to implement our addView.
00:06The tactic is pretty simple.
00:08We're going to create the controller in the storyboard, connect it to the BWRSSAddViewController class,
00:13and set up the form elements.
00:17Let's start by making a working copy of BWRSS- splitview-03, and I'm just using this done version, you
00:24can use the version that you created in the last lesson if you're following along.
00:28I'm just going to rename it to BWRSS-splitview-04, and I'm going to open it in Xcode by double-clicking
00:35on this Xcode project file.
00:38So now we're going to come up to the iPad storyboard, which is right up there, and I'm
00:45going to open up our Utilities View and scroll over here.
00:51You see we have the Items Table View Controller right there, and right under it I'm going
00:56to go ahead and put our Add View Controller.
00:59So, the first thing I'm going to do is I'm going to add that button up here on our Feeds Table View Controller.
01:07So, come over here to Objects and Windows & Bars and grab a Bar button Item and just
01:15drop it right there and call it an Add button so it gets that little Plus and Command+S to save.
01:23Now, under our Items View Controller, I'm just going to scroll on over here, and I'm
01:27going to create a new controller.
01:30This is just a plain View Controller, so I'm going to drop it in right here and its size
01:37is going to be Form Sheet so that makes it manageable right there and drag it down over here.
01:47The Transition Style will say Cover Vertical. The Presentation will say Form Sheet.
01:54And then we're going to set our controller to the BWRSSAddViewController, and I'm pressing Command+S to save.
02:02Now, I'll scroll down here so we can see a little bit more of it, and under Data Views
02:09I'm going to grab a Scroll View, and I'm going to drop that right here on this controller like that.
02:19Get it all nice and lined up, and over here, in the Attributes Inspector, let's scroll
02:26down and give it a background of Scroll View Textured Background Color.
02:34Now, the rest of this is going to be very much like what we did when we first created
02:38the addView controller for the iPhone. We can go ahead and populate this view.
02:44I'm going to start with a text label up here at the top, and I'll stretch that out to sides
02:52using these handy dandy guides that the Interface Builder gives us.
02:56I'm going to make it centered and make it the System Bold Font 17 size.
03:07It's going to say Add RSS Feed, like that, and then I'm going to make it white.
03:15This background is actually dark. It doesn't look like it's dark, there it is.
03:21But you'll see when we run it in the Emulator that it actually is dark.
03:25Now we can grab another text label and put it right under this one, and we're going to
03:29leave this one left flush, and this is our Status Label, and it's going to say Enter a URL.
03:42This one is going to be Size 12, and it's also going to be white.
03:47Now, we're going to grab a text field and put that right under that other text label
03:53and bring that over to the sides and the text in there will say http://, and we're going
04:02to scroll down here and set some properties here, Capitalization: None, Correction: No,
04:08Keyboard: URL, Appearance: Default, and Return Key: Done.
04:12So, now I'm going to grab a couple of buttons here, Round Rectangle Buttons, and I'm going
04:18to drag them over here and align them up.
04:21This little technique for doing this, and I'm going to grab them both and center them,
04:27and then the button on the left will be called Cancel, and the button on the right will be called Add.
04:35Now, we're going to connect our segue, and that will be a little bit challenging with
04:40this being zoomed in like this.
04:43Let's see if we can do this with it zoomed out. I'm not sure that it will let me.
04:47I'm going to Ctrl-click on this button and drag it over here.
04:52For Action Segue, I'm going to select Modal, and then I'm going to select our Segue like
04:57this and the Identifier is SegueToAddView, like that.
05:08Presentation is just Default, Transition is also Default.
05:15Style is Modal, that's great.
05:17Now, we're going to come down here where we're going to connect our Controller.
05:20I need to zoom back in apparently.
05:22So, I'm going to Ctrl-drag from here down to the Add View Controller, and we'll select
05:28addAction and the cancelAction, and do the same thing again and select cancelAction. That works.
05:35Now, when I select this controller, we should see those hooked up properly, they are, excellent.
05:43The URL text field should come over here and the Status Label will come over to this one here.
05:54You can almost see that it's the second one. It's not the top one, it's the second one.
05:58And then finally, we want to drag this text field, we want to drag it down into our
06:06ViewController and where it says the Outlet Delegate, we need to connect that up.
06:10So, here we have our delegate outlet on the text field is set to the Add View Controller,
06:19and if we come down to the Add View Controller, we see that our delegate is that text field.
06:25So now, this should all be hooked up properly, I'm going to press Command+S to Save, and
06:30we're going to go ahead and run it in the iPad Simulator.
06:34I'm going to go ahead and put us in Landscape mode.
06:39We see there's our Plus button, I'll press that button, and there is our Add RSS Feed Controller.
06:45We can just type something in here, I'll put in wired.com and press the Add button, and
06:52there is our Wired Feed, and you see that's all working.
06:57I can come back here again, I can add another one say arstechnica.com, and I can press the Done button.
07:05All of this works exactly like it does now in the iPhone version, and you notice we did
07:10no coding at all for this.
07:12All we did was hook up this new View Controller to the exact same code.
07:17So, this is a lot less work because we're able to leverage most of the work we've already
07:22done for the iPhone Form Factor.
07:25The Universal application model allows us to take advantage of two different platforms,
07:29two different sizes of screens, two different UIs, all with the same code base.
07:34We now have a working storyboard interface that we can use for the Modal dialog box.
07:39With storyboard, this whole process becomes a whole lot easier.
07:43All we really need to do is set up the View Controller in the storyboard and connect it
07:47to our existing classes and then it just works.
07:50So, congratulations. You now have a fully-functional RSS Reader that runs in both the phone and tablet form factors.
Collapse this transcript
Conclusion
Goodbye
00:00Thank you for watching iOS SDK and SQLite: Building Data-Driven Applications.
00:05It has been a great experience for me putting this course together, and I hope you've gained
00:09some useful techniques for building your own data-driven applications in iOS.
00:13For more about the SQLite database engine we used in this application, please see my
00:18course SQLite 3 with PHP Essential Training here on the lynda.com online training library.
00:24If you need more information on programming for the iOS SDK, check out iOS SDK Essential Training with Simon Allardice.
00:31I look forward to seeing your apps out there on the App Store.
Collapse this transcript


Suggested courses to watch next:

iOS SDK Essential Training (2012) (6h 26m)
Simon Allardice


Core Data for iOS and OS X (4h 29m)
Simon Allardice


Are you sure you want to delete this bookmark?

cancel

Bookmark this Tutorial

Name

Description

{0} characters left

Tags

Separate tags with a space. Use quotes around multi-word tags. Suggested Tags:
loading
cancel

bookmark this course

{0} characters left Separate tags with a space. Use quotes around multi-word tags. Suggested Tags:
loading

Error:

go to playlists »

Create new playlist

name:
description:
save cancel

You must be a lynda.com member to watch this video.

Every course in the lynda.com library contains free videos that let you assess the quality of our tutorials before you subscribe—just click on the blue links to watch them. Become a member to access all 104,141 instructional videos.

get started learn more

If you are already an active lynda.com member, please log in to access the lynda.com library.

Get access to all lynda.com videos

You are currently signed into your admin account, which doesn't let you view lynda.com videos. For full access to the lynda.com library, log in through iplogin.lynda.com, or sign in through your organization's portal. You may also request a user account by calling 1 1 (888) 335-9632 or emailing us at cs@lynda.com.

Get access to all lynda.com videos

You are currently signed into your admin account, which doesn't let you view lynda.com videos. For full access to the lynda.com library, log in through iplogin.lynda.com, or sign in through your organization's portal. You may also request a user account by calling 1 1 (888) 335-9632 or emailing us at cs@lynda.com.

Access to lynda.com videos

Your organization has a limited access membership to the lynda.com library that allows access to only a specific, limited selection of courses.

You don't have access to this video.

You're logged in as an account administrator, but your membership is not active.

Contact a Training Solutions Advisor at 1 (888) 335-9632.

How to access this video.

If this course is one of your five classes, then your class currently isn't in session.

If you want to watch this video and it is not part of your class, upgrade your membership for unlimited access to the full library of 2,025 courses anytime, anywhere.

learn more upgrade

You can always watch the free content included in every course.

Questions? Call Customer Service at 1 1 (888) 335-9632 or email cs@lynda.com.

You don't have access to this video.

You're logged in as an account administrator, but your membership is no longer active. You can still access reports and account information.

To reactivate your account, contact a Training Solutions Advisor at 1 1 (888) 335-9632.

Need help accessing this video?

You can't access this video from your master administrator account.

Call Customer Service at 1 1 (888) 335-9632 or email cs@lynda.com for help accessing this video.

preview image of new course page

Try our new course pages

Explore our redesigned course pages, and tell us about your experience.

If you want to switch back to the old view, change your site preferences from the my account menu.

Try the new pages No, thanks

site feedback

Thanks for signing up.

We’ll send you a confirmation email shortly.


By signing up, you’ll receive about four emails per month, including

We’ll only use your email address to send you these mailings.

Here’s our privacy policy with more details about how we handle your information.

Keep up with news, tips, and latest courses with emails from lynda.com.

By signing up, you’ll receive about four emails per month, including

We’ll only use your email address to send you these mailings.

Here’s our privacy policy with more details about how we handle your information.

   
submit Lightbox submit clicked