iOS App Development Tutorial Part III: Interacting with Web Sites

Last updated on April 11, 2024

Now that we have our idea and our visual mock ups, let’s start coding. I will be using Xcode 4.6.2, it is the latest at the time of this writing

If you have never developed in Objective-C but did some other coding in C++ or C for example it should be pretty simple to catch up. I personally haven’t touched C or C++ since college, some 15 years ago. Even with knowledge of Java and C#, I was able to pick up Objective-C. I highly recommend reading iOS Programming: The Big Nerd Ranch Guide as well.

Create a blank project

newproject1Open Xcode from your dock. If it’s not on your dock, you can open it from Applications. Select “Create a new Xcode project” from the Welcome to Xcode screen. Choose “Empty Application” from “Choose a template for your new project” dialog. Fill out the options for your project.

  • Product Name: DZone RSS
  • Organization Name: <<enter your organization>>
  • Company Identifier: <<enter your company identifier>>
  • Class Prefix: <<enter the default prefix for your classes>>
  • Devices: iPhone
  • Only tick “Use Automatic Reference Counting”

When specifying a Class Prefix, I recommend coming up with your own 3-4 character prefix, especially if you plan to publish any frameworks to opensource. This is necessary as Objective-C does not have a concept C# namespace or Java package. Without a prefix, you run the risk of class name collision when 3rd party libraries. On a related note, “NS” and “UI” prefix is reserved for Apple. “NS” stands for NeXTSTEP where Objective-C was developed. It’s a holdover from when NeXTSTEP took over Apple. Yes, I said that correctly. All resemblance of Apple as we see today is the product of Steve Jobs’ vision of NeXTSTEP that was acquired by Apple.

For this initial project, we will only target iPhone. I plan to refactor this project on a separate tutorial to run on iPad. For this reason, I plan to use UICollectionViewControlller to layout the RSS article instead of the UITableViewController. This will be further discussed in Part VI: Storyboarding.

iOS Project Basics

Each project has a main.m file. Below is the application entry point.

int main(int argc, char *argv[])
{
  @autoreleasepool {
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([JSTRAppDelegate class]));
  }
}

The default pricipalClassName (3rd parameter) is UIApplication. When nil is passed, the default pricipalClassName will be used. UIApplication can be subclassed if custom UIApplication is used. The 4th parameter is the app delegate class. In our case, it’s JSTRAppDelegate. If you look at the JSTRAppDelegate.h, you’ll notice that it implements the UIApplicationDelegate protocol. All methods in UIApplicationDelegate are optional. UIApplication sends messages to delegate concerning App Launch/Termination, memory warnings, changes in orientation, and becoming the active application. As I don’t like having empty methods, I tend to remove all but the application:didFinishLaunchingWithOptions method until I’m ready to implement them.

#import "JSTRAppDelegate.h"
@implementation JSTRAppDelegate

- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor yellowColor];
[self.window makeKeyAndVisible];
return YES;
}

Click run on top left and the iPhone Simulator will launch will bring you to a yellow screen. Congrats! If you’ve never

simulator1

created an iPhone app before, you’ve successfully written and launched your first app, a yellow flashlight. If you have any plans to launch this application, don’t bother. The very first flashlight application and mirror was exactly this with white and black background respectively. Since then, Apple has banned these types of applications.

Setting up Groups

Although Objective-C has no concept of C# namespace or Java package, Xcode does have a concept of groups. This is particularly helpful in organizing your code base. However, creating a group does not create an associated folder for that group. If you do not bind you group to a particular folder, all your code will reside at the root of your project in the file system. If you want to keep you file system consistent with your Xcode groups, You may want to bind your group to a specific folder. This way, when a file is added, it will add the new file to the linked folder.

newgroup1
newgroup2

To create a new group under DZone RSS, hold the control key and click on “DZone RSS” group. On the context menu, select “New Group” and specify the name “Net”. Select this new group “Net”. On the right side of Xcode, under Identity section, click the white square next to grayed out word “None” (see screenshot). This will open up a dialog where you can create a corresponding folder for your group. Create a new folder called “Net” to match your group name then click “Choose”. Now, any new file added to this group will reside in the “Net” folder in the file system. We’re now ready to create a new class to interact with DZone RSS URL.

JSTRRSSReader class

Once again, hold the control key and click “Net” folder. On the context menu, select “New File…”. On “Choose a template for your new file”, select Cocoa Touch from left panel and Objective-C class on right panel. After clicking “Next”, specify the class name “JSTRRSSReader”. This class should be a subclass of “NSObject”. Click “Next” will open the file dialog to “Net”. Since we want this class to reside in “Net” folder, just click “Create”.

Our class needs to implement NSURLConnectionDataDelegate. This protocol describes methods that should be implemented to handle download data to memory. To hold this data into memory, we declare an instance variable _receivedData of type NSMutableData. It is also a good practice to prefix your instance variable with an underscore. We also need to expose the method in our interface so the caller can start the RSS request.

@interface JSTRRSSReader : NSObject <NSURLConnectionDataDelegate>
{
NSMutableData *_receivedData;
}

- (void) startRequest;

@end

By default, all foundation classes (i.e. NSData, NSString, NSArray, etc) are immutable. However, a handful of them do have mutable subclasses (i.e. NSMutableData, NSMutableString, NSMutableArray). Mutable subclasses inherit all capabilities of immutable base class with added mutable methods. Since we can be getting data in chunks/blocks, we will need to use the mutable counterpart to NSData, NSMutableData.

We now implement our class: our custom method startRequest and required NSURLConnectionDataDelegate methods.

#import "JSTRRSSReader.h"
@implementation JSTRRSSReader

- (void) startRequest
{
  NSURL *url = [[NSURL alloc] initWithString:@"http://feeds.dzone.com/dzone/frontpage?format=xml"];
  NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url cachePolicy:NSURLCacheStorageNotAllowed timeoutInterval:60.0f];
  NSURLConnection *conn = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:YES];
  if(conn)
  {
    _receivedData = [[NSMutableData alloc]init];
  }
}

#pragma mark - NSURLConnectionDataDelegate
- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
  NSLog(@"%@",error.description);
}

- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
  NSLog(@"received %d bytes",data.length);
  [_receivedData appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
  NSLog(@"%@", [NSString stringWithCString:[_receivedData bytes] encoding:NSUTF8StringEncoding]);
}

@end

In startRequest, we allocate an instance of NSURL to DZone RSS. The connection will initialize immediately. If an error occurs, connection:didFailWithError will log to console the error message. Otherwise, when data is received, connection:didReceiveData will be called where we append the data chunk/block to our instance variable _receivedData. When the request has completed, connectionDidFinishloading will be called. We will then log to console the complete response body.

Call JSTRRSSReader

Let’s now update our app delegate (JSTRAppDelegate) to make a call to DZone RSS.

#import "JSTRAppDelegate.h"
#import "JSTRRSSReader.h"

@implementation JSTRAppDelegate

- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
  self.window.backgroundColor = [UIColor yellowColor];
  [self.window makeKeyAndVisible];

  // make RSS call
  JSTRRSSReader *reader = [[JSTRRSSReader alloc] init];
  [reader startRequest];

  return YES;
}

On run, the body of the response will now appear on your Xcode console. Congrats! you have successfully made request to a website.

console