Monday, December 17, 2012

Table Search Display Tutorial

This is what we want to achieve in this tutorial:

A table list with a search bar on top, and when we type on the search bar, the table updates its list.

Prerequisite in learning this tutorial is a knowledge in creating table views. If you still don't know how to make table views, refer to the old tutorials.  (http://iosmadesimple.blogspot.com/2012/10/adding-uitableview-tutorial.html)

1. Create a New Xcode project, choose a Single View Application template.

I'm using the latest Xcode up to date, so you may see a longer UIView in our xib file (for iPhone 5 devices). But if you want the old UIView size, you may change it by choosing Retina 3.5 Full Screen on the Simulated Metrics (right panel of the image above).

2. Look for "Search Bar and Search Display Controller" in Objects Library and drag it to our UIView.


3. Set up the table, the list of items, implementation of the delegate and datasource methods of tableview and everything else. If you have no idea how, follow this tutorial about adding UITableView. (http://iosmadesimple.blogspot.com/2012/10/adding-uitableview-tutorial.html)

4. Add this to your interface header, together with your UITableViewDataSourceUITableViewDelegate:

UISearchDisplayDelegate, UISearchBarDelegate

5. We need to add two more variables:
A boolean variable that will tell us if the user is currently searching;
and a mutable array where we can put the filtered list when the user is searching.

BOOL isSearching;

NSMutableArray *filteredList;

6. Set the boolean variable to NO, and allocate and initialize the filteredList in our viewDidLoad function:
isSearching = NO;
filteredList = [[NSMutableArray alloc] init];

7. Create a method that will add an object to our filteredList according to the string typed by the user.

- (void)filterListForSearchText:(NSString *)searchText
{
    [filteredList removeAllObjects]; //clears the array from all the string objects it might contain from the previous searches
    
    for (NSString *title in list) {
        NSRange nameRange = [title rangeOfString:searchText options:NSCaseInsensitiveSearch];
        if (nameRange.location != NSNotFound) {
            [filteredList addObject:title];
        }
    }
}


8. Implement the search display delegate methods.
#pragma mark - UISearchDisplayControllerDelegate

- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
//When the user taps the search bar, this means that the controller will begin searching.
    isSearching = YES;
}

- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller {
//When the user taps the Cancel Button, or anywhere aside from the view.
    isSearching = NO;
}

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
    [self filterListForSearchText:searchString]; // The method we made in step 7
    
    // Return YES to cause the search result table view to be reloaded.
    return YES;
}

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption
{
    [self filterListForSearchText:[self.searchDisplayController.searchBar text]]; // The method we made in step 7
    
    // Return YES to cause the search result table view to be reloaded.
    return YES;
}

9. Update our tableview method numOfRows: and cellForRow:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Return the number of rows in the section.
    if (isSearching) { 
        //If the user is searching, use the list in our filteredList array.
        return [filteredList count];
    } else {
        return [list count];
    }

- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    
    UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
    }
    
    // Configure the cell...
    NSString *title;
    if (isSearching && [filteredList count]) {
        //If the user is searching, use the list in our filteredList array.
        title = [filteredList objectAtIndex:indexPath.row];
    } else {
        title = [list objectAtIndex:indexPath.row];
    }
    
    cell.textLabel.text = title;
    
    return cell;
}

10. Hit Run and your search display controller is done!

Thursday, November 22, 2012

Interface and Implementation

The Interface

We are all very familiar with these lines of code, right? They are found in our .h files.

@interface  ClassA:NSObject {
           dataType variable1;
}
-(returnType)method1;
@end

The purpose of interface:

The methods and the variables inside our interface are the methods and variables that can be accessed by the other classes.

The variables we put inside our curly braces are INSTANCE variables.


@interface ClassA:NSObject {
           dataType variable1;
}


A lot of people (even me) misunderstood these variables as CLASS variables.

What are Instance Variables?

"When a number of objects are created from the same class blueprint, they each have their own distinct copies of instance variables." (Source Link)
This means that every time we instantiate a class, each of these instantiations or (alloc, in our part) will have their own set of instance variables.


What are Class Variables?

"Sometimes, you want to have variables that are common to all objects. This is accomplished with the static modifier. Fields that have the static modifier in their declaration are called static fields or class variables. They are associated with the class, rather than with any object. Every instance of the class shares a class variable, which is in one fixed location in memory. Any object can change the value of a class variable, but class variables can also be manipulated without creating an instance of the class." (Source Link)
This means that a particular variable will have the same value to all the other objects that instantiated that class.


Now where will you put those methods that you want to be only accessible within the class?

The Implementation

Categories and Class Extensions

Categories are very useful in adding methods to an existing class; it allows us to EXTEND the functionalities of a class without subclassing it. For example, we have Class A. Class A has method1 and method2. I also have Class B, Class B imports Class A, but I wanted to add a method in Class A without subclassing it. So I make a Category.

//Inside Implementation file of ClassB
#import "ClassA.h"
@interface ClassA(ClassA+newMethod)  <- This is a category
-(returnType)newMethod;
@end

@implementation ClassB
//implementing method in our category 'ClassA+newMethod'
-(returnType)newMethod {
}
//other methods
@end

Now, Class Extensions (or private categories) are like anonymous categories. We add methods to our class that only that method can be accessible within the class and that these methods must be implemented in our class.

//Inside Interface file of Class A
@interface  ClassA:NSObject {
           dataType variable1;
}
-(returnType)method1;
@end

//Inside Implementation file of Class A
@interface  ClassA() <- This is a class extension
{
           dataType variable2;
}
-(returnType)privateMethod;

@implementation ClassA
-(returnType)method1 {
     [self privateMethod];
}
-(returnType)privateMethod {
}
@end

With the class extension, variable2 and privateMethod can only be used inside ClassA. As we can see from the example, method1 is calling privateMethod. Class B can never see privateMethod() even if it imported and instantiated ClassA.

So, why not use @private if we only want to hide our iVars?

We already know what an instance variable is, right? @private means that our instance variables can be accessed from an instance of the class; it protects ivars from access of an instance of any other class. As for using an anonymous category, the variables can never be accessed nor seen from another class (even if it instantiated that class).
@private does not really hide our variables (example, in Class A) from any other class, example, Class B if somewhere inside Class B's codes instantiated Class A, Class B will still be able to access the private variables using the accessor methods or through the getters and setters.



Wednesday, October 31, 2012

UITableViewCell Using Interface Builder

Creating your own tableview cell could be such a hassle when you do it programmatically. To be able to follow this tutorial, you need to know how to add a tableview first. Refer to the previous tutorial on how to add a tableview if you still don't know how to add it yet.
Link: http://iosmadesimple.blogspot.com/2012/10/adding-uitableview-tutorial.html

Let's start!


1. Add a new file of subclass UITableViewCell.


2. After adding a new UITableViewCell class, only .h and .m files are created. So, let's add another file, an empty Interface Builder Document (xib file). Name it with the same name with our .h and .m files (to avoid confusion).

You should have these files in your project navigator.

3. Drag a tableview cell to your xib file, and change its class to SampleTableCell (the one we added a while ago).

4. Start customizing your cell. Here in my example, I want to make a feed cell (One with profile pictures, name, status, date <-- something like that):

  1. I changed the height of my cell to 90 (instead of the default cell height which is 44).
  2. I wanted to put a background image to my cell, so I added a UIImageView with size same with my cell. (I added an image to the project for my cell background.)
  3. All the other UIs are placed on top of the UIImageView (cell background). I added another UIImageView for the profile pictures. 

  4. Added a UILabel for the name, status and date.

My customized cell currently looks like this. Nice thing of doing it here in Interface Builder is that you can easily manipulate the positions, and other attributes of your objects.

3. Make an IBOutlet property of the objects that might change dynamically. In our example, our profilePicture object may change dynamically, depends on who posted what, the Name, Status, DatePosted. But the background image doesn't really change no matter who posted what, so we don't have to make an IBOutlet property of the background UIImage. And remember to synthesize these objects.
//Inside .h file

@property (nonatomic, strong) IBOutlet UIImageView *profilePicture;
@property (nonatomicstrongIBOutlet UILabel *name;
@property (nonatomicstrongIBOutlet UILabel *status;
@property (nonatomicstrongIBOutlet UILabel *datePosted;

//Inside .m file
@synthesize profilePicture;
@synthesize name;
@synthesize status;
@synthesize datePosted;


4. Connect these outlets to your objects in your xib file.

5. Create a new File, subclass of NSObject. This file will serve as our "User" object. This class must hold the important information we need, like the profilePicture filename, Name, Status and DatePosted.
//User.h file

@interface User : NSObject
@property (nonatomiccopyNSString *avatarFname;
@property (nonatomiccopy) NSString *name;
@property (nonatomiccopy) NSString *status;
@property (nonatomiccopy) NSString *datePosted;
@end
//User.m file
@implementation User
@synthesize avatarFname;
@synthesize name;
@synthesize status;
@synthesize datePosted;
@end



6. Create your user objects and put them all in your items Array. (This part is found in step 7 from the tutorial link above).
//I created five users. Sample code...

    User *user1 = [[User alloc] init];
    user1.name = NSLocalizedString(@"Jennifer Eve Curativo", @"name");
    user1.status = NSLocalizedString(@"Currently addicted to Hi Fi Camp - It's a Japanese band, by the way. ;)", @"status");
    user1.datePosted = NSLocalizedString(@"October 31, 2012 5:30PM", @"date Posted");
    user1.avatarFname = @"jen.png";

//Put them all in our array list

items = [[NSArray alloc] initWithObjects: user1, user2, user3, user4, user5, nil];


7. Before we proceed, change the cell's Identifier. We need it later.

Remember the Datasource and Delegate methods of our tableView from the previous tutorial? We are going to modify/add some methods.

8. Remember that our customized cell's height was changed to 90, right? It has become taller than the usual height of our tableViewCell. Add this method so that our tableView will know that the cell's height was changed.
//If we did not change the height of our cell, we do not need to add this method.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 90.0;
}

9. Lastly, modify this method cellForRow. This is the part where we tell the tableView that we will use our custom cell.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    static NSString *CellIdentifier = @"MyFeedCell";
    SampleTableCell *cell = (SampleTableCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    
    if (cell == nil) {
        NSArray* topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"SampleTableCell" owner:self options:nil];
        for (id currentObject in topLevelObjects) {
            if ([currentObject isKindOfClass:[UITableViewCell class]]) {
                cell = (SampleTableCell *)currentObject;
                break;
            }
        }
    }
    
    // Configure the cell.
    User *user = [items objectAtIndex:indexPath.row];
    cell.profilePicture.image = [UIImage imageNamed:user.avatarFname];
    cell.name.text = user.name;
    cell.status.text = user.status;
    cell.datePosted.text = user.datePosted;
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    return cell;
}

10. Hit Run!






Tuesday, October 23, 2012

Adding a UITableView Tutorial

For beginners, this is one of the difficult views to learn, anyhow let's learn how to add a tableview in our view.
A tableView is used to show a list of objects.

Adding a TableView Using Interface Builder

1. Prepare the superview of your tableView. (Superview is the view where we would like to put our tableview.) In our example, the UIViewController's view is going to be our tableView's superview.

2. Drag a tableView UI to our View.
If you hit run, you will see your tableView on your screen. You can scroll it up and down.

3. Set the tableview datasource and delegate in your Interface file.

@interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>


4. Add an IBOutlet tableview property and synthesize it.

@property (nonatomic, strong) IBOutlet UITableView *sampleTableView
@synthesize sampleTableView; //.m file below @implementation ViewController

5. Connect your IBOutlet to our tableView in your xib file.



6. Create an array that will hold your list for you. If your items are static (will not change), use NSArray, else, if somewhere in your program, you need to change your array, use NSMutableArray.

@property (nonatomicstrong) NSArray *items;

7. In your viewDidLoad function, allocate and initialize your array with your objects. Currently, let's use simple string objects, NSString.
items = [[NSArray alloc] initWithObjects:@"Item No. 1"@"Item No. 2"@"Item No. 3"@"Item No. 4"@"Item No. 5"@"Item No. 6", nil];

8. Set our sampleTableView's datasource and delegate to its File's Owner.



9. Lastly, implement the UITableView Datasource and Delegate methods. These are necessary to manipulate our tableView.


#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.
    // Usually the number of items in your array (the one that holds your list)
    return [items count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    //Where we configure the cell in each row

    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell;
    
    cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
    // Configure the cell... setting the text of our cell's label
    cell.textLabel.text = [items objectAtIndex:indexPath.row];
    return cell;
}

/*
 // Override to support conditional editing of the table view.
 - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath{
 // Return NO if you do not want the specified item to be editable.
 return YES;
 }
 */

/*
 // Override to support editing the table view.
 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
 if (editingStyle == UITableViewCellEditingStyleDelete) {
 // Delete the row from the data source
 [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
 }
 else if (editingStyle == UITableViewCellEditingStyleInsert) {
 // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
 }
 }
 */

/*
 // Override to support rearranging the table view.
 - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
 {
 }
 */

/*
 // Override to support conditional rearranging of the table view.
 - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
 {
 // Return NO if you do not want the item to be re-orderable.
 return YES;
 }
 */

#pragma mark - Table view delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // Navigation logic may go here. Create and push another view controller.
    // If you want to push another view upon tapping one of the cells on your table.

    /*
     <#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:@"<#Nib name#>" bundle:nil];
     // ...
     // Pass the selected object to the new view controller.
     [self.navigationController pushViewController:detailViewController animated:YES];
     */
}


10. Hit Run!


Adding a TableView Programmatically

1. From the steps we had above, delete the tableView UI in our xib file, and delete the IBOutlet from our tableView property.

@property (nonatomicstrongIBOutlet UITableView *sampleTableView

2. On your viewDidLoad function (of your ViewController.m file). Follow the commented steps.

- (void)viewDidLoad {
    [super viewDidLoad];
    //Create a tableView programmatically
    self.sampleTableView = [[UITableView alloc] initWithFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.yself.view.frame.size.widthself.view.frame.size.height 2) style:UITableViewStylePlain];
    //Add the tableview as sa subview of our view ---> making "view" our superview.
    [self.view addSubview:sampleTableView];
    //From step 7 above.
    items = [[NSArray allocinitWithObjects:@"Item No. 1"@"Item No. 2"@"Item No. 3"@"Item No. 4"@"Item No. 5"@"Item No. 6"nil];
    //From the step 8 above, this is how we do that programmatically
    self.sampleTableView.delegateself;
    self.sampleTableView.dataSourceself;
}

3. Done! When you hit run, you'll see the same result.




Tuesday, October 2, 2012

Navigation Controller and a Tabbar Controller in One View

If wanted to show a Navigation Controller and a Tabbar Controller in one view, should the navigation controller be inside the tabbar controller or is it the other way around? 

Most beginners happen to do this in an INappropriate manner. The answer to my first question is that the Navigation Controller should be put inside the Tabbar Controller. And the worst part for those who do not know how to do that is that they will just put a Navigation bar at the top part of the view. Don't do this, let me help you how to do it properly.

If you could still remember how we created a Tabbed Application, do it first before following the next steps. Follow this tutorial up until Step 10. (http://iosmadesimple.blogspot.com/2012/09/tabbed-application-using-interface.html)

Let's Begin!


1. Expand the Placeholders/Objects Panel, and the Tab Bar Controller. Drag a Navigation Controller Object under the TabBar Controller.

2. Since I only want two tabs for my TabBar Controller, I will make my first tab a Navigation-Based view, so I will delete one View Controller bellow the Navigation Controller object.

For Step 1 and 2.

I edited the tint of the Navigation Bar and its Navigation Title.



Hit run and it should look like this.

3. Did you follow the tutorial above and reached step 10? If so, I'll assume that you created two view controllers already (the FirstViewController and the SecondViewController). In my FirstViewController, I added a button which will be used later on in this tutorial.


4. Import the two ViewControllers, then, go back to our MainWindow.xib, change the class of the ViewController inside the Navigation Controller. So as the ViewController inside the Tabbar Controller.


5. Create another ViewController, let's name it "ThirdViewController," put a label to indicate that it's the ThirdVC.

6. Import ThirdViewController in FirstViewController Class. Create an IBAction method that will push the ThirdVC and show it.
- (IBAction)goToThirdView:(id)sender {
    ThirdViewController *thirdVC = [[ThirdViewController alloc] init];
    [self.navigationController pushViewController:thirdVC animated:YES];
}


7. Connect the IBAction to our Button in FirstViewController.xib.


8. Hit Run, and you should be able to navigate from FirstVC to the ThirdVC and still have the TabbarController.
  








Tuesday, September 25, 2012

Tabbed Application FROM Another ViewController


WHAT IF… you wanted the very first View to be an ordinary ViewController, then when you tap a button from the first View, the secondView uses a TabBarController, how do we do it? 

This is somehow related to the things we did from our previous tutorials:
http://iosmadesimple.blogspot.com/2012/09/tabbed-application-doing-it.html OR
http://iosmadesimple.blogspot.com/2012/09/tabbed-application-using-interface.html

//I'm using the latest Xcode as of this date, Xcode 4.5, you might find the views in my xib file a bit bigger in size than the usual ones.

1. I created a New Project, having "ViewController" class as my First View. Add a label and a button for this view. And it currently looks like this:

2. Create New Files, name it FirstTabViewController and SecondTabViewController, subclass of UIViewController. Add labels so as to indicate which tabVC is which.
First Tab ViewController UI

Second Tab ViewController UI

Doing it Programmatically

3. In ViewController Class, #import FirstTabVC and SecondTabVC, create a TabBarController property, synthesize it and make an IBAction method for our button.

4. Under viewDidLoad function of ViewController Class, allocate and initialize FirstTabVC and SecondTabVC and the tabBarController;

- (void)viewDidLoad {
    [super viewDidLoad];

    FirstTabViewController *firstTab = [[FirstTabViewController alloc] init];
    SecondTabViewController *secondTab = [[SecondTabViewController allocinit];
    
    firstTab.title = @"First Tab VC"; //TabTitle
    secondTab.title = @"Second Tab VC"; //TabTitle
    
    tabController = [[UITabBarController  allocinit];
    tabController.viewControllers = [[NSArray  alloc] initWithObjects:firstTab, secondTab, nil];
}

5. Add a code in IBAction that tells it that we should show the tabbed Controller. And remember to connect this IBAction to your button in your xib file.
-(IBAction)goToTabbedView:(id)sender {
    [tabController setSelectedIndex:0];
    //[self presentModalViewController:tabController animated:YES]; //deprecated in iOS 6.0; you may use this in older versions
    [self presentViewController: tabController animated:YES completion:NULL]; //you may put completion block here if there's anything you would like it to do after this task is successful
}


6. Hit Run! 

Doint it Using Interface Builder


1. Remove or comment out all your codes (the one we created above; step 4) in viewDidLoad in ViewController Class.

2. Drag a TabBarController from the Objects Library to the Placeholder/Objects Panel.
(Photo from previous posts.)

3. Add "IBOutlet" to your UITabBarController property and synthesize it; connect whatever outlets need to be connected.

4. Expand the Placeholder/Objects Panel, and the navigationController in ViewController.xib file.
(Photo from previous posts.)

5. Click the View Controllers under UITabBarController object, change their classes to FirstTabViewController and SecondTabViewController respectively.


How to go back from our very first View Controller?

1. Add a button to any of your Tab Controllers (FirstTabViewController or SecondTabViewController). Create an IBAction and connect it to the button you added.


-(IBAction)goToFirstView:(id)sender {
    [self.tabController dismissViewControllerAnimated:YES completion:NULL];
}


Hit Run!







Download Sample Project Here!

Saturday, September 22, 2012

Tabbed Application, Using Interface Builder


If you want to create a Tabbed Application programmatically, refer to this tutorial:
http://iosmadesimple.blogspot.com/2012/09/tabbed-application-doing-it.html

Let's create a Tabbed application using Interface Builder! :D

1. Create a new empty application. Make your own MainWindow.xib file, you already know how to do this. (If not, refer to this tutorial: http://iosmadesimple.blogspot.com/2012/08/creating-our-own-mainwindowxib-for.html)

2. Go to AppDelegate.h, add a UITabBarControllerDelegate
@interface AppDelegate : UIResponder <UIApplicationDelegate, UITabBarControllerDelegate>

3. add a UITabBarController property.
@property (strong, nonatomic) UITabBarController *tabBarController;

4. Synthesize your tabBarController variable in AppDelegate.m.

5. Create at least 2 View Controllers, name it First and Second ViewController. Add UILabels and other stuff, to indicate that such UI belongs to either of the two ViewControllers.

6. Add "IBOutlet" to UIWindow and UITabBarController properties in AppDelegate.h
@property (strongnonatomicIBOutlet UIWindow *window;
@property (strongnonatomic IBOutlet UITabBarController *tabController;

7. Go to your MainWindow.xib, Search for Tab Bar Controller from Objects Library and drag it to Placeholder/Objects Panel. Make the necessary connections from your AppDelegate Object outlets to your objects UIWindow and UITabBarController.

8. Right-click Window object in your Interface Builder, connect the "rootViewController" outlet to UITabBarController object.



9. Go to AppDelegate.m, under application:didFinishLaunchingWithOptions function, comment out all the codes inside that function, but leave these codes behind:
[self.window makeKeyAndVisible];
return YES;

10. Hit Run!

Let's set our two view controllers that we created a while a go, the First and Second View Controller.

11. Import the First and Second VC to your AppDelegate class.

12. Expand the Placeholders/Objects Panel, and the  TabController.

13. Select one of the two view controllers inside the Tab Controller, and change its class to "FirstViewController."

Do the same thing with the other view controller, set its class to "SecondViewController."

Hit Run and you're done! 




Note

You may add an image or a tabTitle for every ViewController by following these steps:

Expand the Placeholder/Objects Panel, the TabBarController object, and the ViewControllers under it. Click the "Tab Bar Item." Go to Attributes Inspector, the fourth button, next to "Identity Inspector." Change the Title or the Image under the "Bar Item" Category.

For the images, you have to import those images to your project first. Right-click the folders on the Project Navigator, choose "Add Files to project_name," choose the images you want to import.




Blocks From one Class to Another

One popular scenario in using blocks is when you need to update your view after a web service call is finished.