Tuesday, December 18, 2012

A Table View based app for iPhone (Part 1)

Table Views are a great way to present lists of information in iOS. In this series of three blogs, we’ll show you how to create a table view application from scratch, how to populate the table with custom cells, how to add and delete information from the table, and how to save and load the table’s data to a file.

In this first blog, we’ll be creating the framework for the application. The source code for the application is located [link to source] here, so let’s get started!

Start Xcode, Choose “Create a new Xcode project,” select the “Empty Application” template, and click Next. Name the product “Friends” and choose options as shown here:

iphone app development

Click Next, choose a location to save the project, and click Create.

In order for a table view to load a new view when a particular cell in the table is touched, the table view needs to be embedded in a navigation controller. We’ll create a new UITableViewController object (with a xib file) to hold our content, and a new UINavigationController that we can push and pop views onto.

First, create a new UITableViewController by right – clicking in the navigator and selecting New File…:

In the resulting window, select the Objective C Class template from the Cocoa Touch group under iOS, and click Next. Name the class FriendsViewController and make sure that it is a subclass of UITableViewController and that we also create a XIB file:

Click Next, and create the class in the default project location by clicking Create.

Open AppDelegate.h and make the following changes:

#import <UIKit/UIKit.h>
#import "FriendsViewController.h"

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) UINavigationController *navController;
@property (strong, nonatomic) FriendsViewController *friendsViewController;

@end

The friendsViewController will be created in the .m file, then made the navController object’s root view controller in AppDelegate.m:

#import "AppDelegate.h"

@implementation AppDelegate

@synthesize navController = _navController;
@synthesize friendsViewController = _friendsViewController;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:
                    (NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.friendsViewController = [[FriendsViewController alloc] initWithStyle:UITableViewStylePlain];
    self.navController = [[UINavigationController alloc] initWithRootViewController:self.friendsViewController];
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window setRootViewController:self.navController];
    [self.window makeKeyAndVisible];
    return YES;
}

Note that we’re using the UITableViewStylePlain style to initialize the table view. The options are UITableViewStylePlain and UITableViewStyleGrouped, which allows grouping of the table into various sections. In this part of the blog, we’ll present the friends list in one contiguous section. Later, we’ll group it alphabetically.

Note also that we send the setRootViewController: message to self.window rather than the older style using [self.window addSubview:self.navController.view]. In iOS 6, the compiler will give a warning if an application launches without an explicitly set rootViewController (the app will still run using the old style, but the warning will persist).

We’ll also need a class to represent the model – in this case, the list of friends we want to present and manipulate in the table view. Let’s add this class by right – clicking in the navigator, and selecting New File…, selecting Objective C class from the template list, and defining the Friends class as a subclass of NSObject:

Again, click Next, and save the class in the default project location by clicking Create.

The Friends class will contain a single property, and (for now) two instance methods, declared in Friends.h:

#import <Foundation/Foundation.h>

@interface Friends : NSObject

@property (nonatomic, strong) NSDictionary *friendsDictionary;

- (void) saveFriendsToPlist:(NSString *) filename;
- (void) loadFriendsFromPlist:(NSString *) filename;

@end

Our Friends.m file should look like this:

#import "Friends.h"

@implementation Friends

@synthesize friendsDictionary;

- (void) saveFriendsToPlist:(NSString *) filename
{
    NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
                         NSUserDomainMask, YES) objectAtIndex:0];
    NSString *plistPath = [docPath stringByAppendingPathComponent:filename];
    [self.friendsDictionary writeToFile:plistPath atomically:YES];
}

- (void) loadFriendsFromPlist:(NSString *) filename
{
    NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
                         NSUserDomainMask, YES) objectAtIndex:0];
    NSString *plistPath = [docPath stringByAppendingPathComponent:filename];
    self.friendsDictionary = [NSDictionary dictionaryWithContentsOfFile:plistPath];
}

@end

Finally, let’s define a simple plist file containing a single entry. Create a new plist file in the Supporting Files folder by right – clicking the folder, then selecting New File. Choose the Property List template under the Resources Group to add a plist:

Click Next, name the file “friends,” (the .plist extension will be added for us), and click Create to save the file in the default project.

Open the friends.plist file by left clicking it in the navigator view. A plist is just an .xml file using a plist document type. Change the view to Source View by right – clicking the plist file, and selecting Open As > Source Code:

(You can choose to work with plists using a graphical interface as well, but sometimes it is easier to work directly in the XML.) Make the following changes to friends.plist:

<?xml version = "1.0" encoding = "UTF-8"?>
< !DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version = "1.0">
<dict>
        <key>Andy Andrews< /key>
        <array>
                <string>a.andrews@somedomain.com< /string>
                <string> 555 - 444 - 3333< /string>
        < /array>
< /dict>
< /plist>

The beauty of the plist format is that we can use the file as a mapping into a “plistable” object: in this case, an NSDictionary consisting of NSArrays of NSStrings. The keys of the dictionary will be the names of our friends, and the values will each be an array containing two strings: the email address and the phone number.

Save the plist. We need to copy this plist now into the documents directory on the simulator. This is found under your user name at ../Library/Application Support/iPhone Simulator/6.0/Applications. In the Applications folder, there will be a list of folders each having a unique identifier; you will have to browse around to find the right one. Locate the folder having the Friends application. In that folder will be a Documents folder. Copy the friends.plist file from the project to this folder:

If you cannot find the Library folder under your username, you may need to show hidden folders in your system. To do this, create and run the following short script in Automator:

(To re-hide hidden files, change the value TRUE to FALSE in the above script.)

Now that the plist is located in the documents directory, we can proceed to hook everything up. Open FriendsViewController.h and make these changes:

#import <UIKit/UIKit.h>
#import "Friends.h"

@interface FriendsViewController : UITableViewController

@property (nonatomic, strong) Friends *friends;

@end

Now make these changes to FriendsViewController.m:

#import "FriendsViewController.h"

@interface FriendsViewController ()

@end

@implementation FriendsViewController

@synthesize friends;

- (id)initWithStyle:(UITableViewStyle)style
{
    self = [super initWithStyle:style];
    if (self) {
        // Custom initialization
        [self.friends loadFriendsFromPlist:@"friends.plist"];
    }
    return self;
}

#pragma mark – Lazy Instantiation:

- (Friends *)friends
{
    if (!friends) {
        friends = [[Friends alloc] init];
    }
    return friends;
}

#pragma mark – UIViewController Delegate Methods:

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;
 
    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark – Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    // Return the number of sections.
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Return the number of rows in the section.
    return [[self.friends.friendsDictionary allKeys] count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
   
    // Configure the cell…
    cell.textLabel.text = [[self.friends.friendsDictionary allKeys] objectAtIndex:indexPath.row];
   
    return cell;
}

(Don’t change anything below these lines, for now just leave the code as it is.) After synthesizing the friends object, we load the plist from it within the table view controller’s initWithStyle: method. The friends object is lazily instantiated: we do this by overriding the getter method for the friends object.

In the datasource delegate methods, we take the information from the friends object’s dictionary. The number of sections in the table view is 1, the number of rows in the section is equal to the number of keys in the dictionary. In this implementation, we use the value of the keys to populate the cells’ titleLable. Since there is only one key (currently) in the dictionary, only one cell will be populated.

Running the app gives the following result:

In the next part of the blog, we’ll look at how to make a custom table view cell that shows all of the information in each record. Stay tuned!


Source : edumobile[dot]org

0 comments:

Post a Comment