Thursday, February 17, 2011

Objective C: Terminate App when pushing the Home button on iPhone/iPad

To make sure your iPhone or iPad App does not keep running in the background after you used the Home button, this is the way to go. Terminating the app helps saving resources on your device.

1. Open your project in Xcode.


2. Find the Info-iPhone.plist or Info-iPad.plist file.


3. Left-click once on it to see the Key Value pairs.


4. Right-click on one of the entries and select Add Row.


5. As key enter UIApplicationExitsOnSuspend.


6. Right-click on the new row and select Value Type Boolean.


7. Check the value field.


Let me know if you have any trouble.

Wednesday, February 16, 2011

Objective C: alternating background color in UITableViewCell for iPhone Apps

In one of my iPhone Apps that has a UITableView I wanted to make the background color of the UITableViewCells alternating. Having two different colors in the background of the cells help to improve the readability.


As you can see in the screenshot the odd cells are grey and the even cells are white.
The changes need to be done in the DataSource method cellForRowAtIndexPath.

- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
 UITableViewCell *cell = [tv dequeueReusableCellWithIdentifier:@"cell"];
 if( nil == cell ) { 
  cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"cell"] autorelease]; 
 }
 Fruits *fruit = [fruits objectAtIndex:indexPath.row]; 
 cell.textLabel.text = fruit.fruitName; 
 
        //start of important code for background color changes
        cell.textLabel.backgroundColor = [UIColor clearColor];
 
 UIView *bgColor = [cell viewWithTag:100];
 if (!bgColor) {
  CGRect frame = CGRectMake(0, 0, 320, 44);
  bgColor = [[UIView alloc] initWithFrame:frame];
  bgColor.tag = 100; //tag id to access the view later
  [cell addSubview:bgColor];
  [cell sendSubviewToBack:bgColor];
  [bgColor release];
 }
 
 if (indexPath.row % 2 == 0){
  bgColor.backgroundColor = [UIColor colorWithRed:233.0/255.0
                green:233.0/255.0
                blue:233.0/255.0
                alpha:1.0];
 } else {
  bgColor.backgroundColor = [UIColor clearColor];
 }
 //end of important code

 return cell;
} 

Above is the whole method with all the additional code you need to get a white/grey background color alternation.

Lets go through the main changes in detail:

Make sure the cell text has a transparent background

cell.textLabel.backgroundColor = [UIColor clearColor]; 
This line makes sure your cell text has an transparent background, otherwise you end up with a result like in the screenshot below.

Create a view that holds the new background color

UIView *bgColor = [cell viewWithTag:100];
if (!bgColor) {
 CGRect frame = CGRectMake(0, 0, 320, 44);
 bgColor = [[UIView alloc] initWithFrame:frame];
 bgColor.tag = 100; //tag id to access the view later
 [cell addSubview:bgColor];
 [cell sendSubviewToBack:bgColor];
 [bgColor release];
}
First we check if the cell has already a view with tag id 100. If not, create a new view with the size of the cell(standard 320x44). Then the view gets add to the cell and send to the background.
If the view exists we don't need to create it again.

Set the color for odd and even cells

if (indexPath.row % 2 == 0){
 bgColor.backgroundColor = [UIColor colorWithRed:233.0/255.0
        green:233.0/255.0
        blue:233.0/255.0
        alpha:1.0];
} else {
 bgColor.backgroundColor = [UIColor clearColor];
}
If the cell index is even (0, 2, 4, etc.) the background color of the background color view is set to grey. Else it is set to clear (white).
If you want it to be the other way around use:
if (indexPath.row % 2 == 0){
...

Hope that helps. Please let me know if you have any problems or questions.

Monday, February 7, 2011

Objective C: Use Network Activity Indicator in iPhone Apps with GTMHTTPFetcher

The Google Toolbox HTTP Fetcher (GTMHTTPFetcher) allows you to send synchronous and asynchronous HTTP request in iPhone/iPad Apps using Objective C/Xcode.

Pretty common in those Apps is to display the network activity indicator during the request process.

The below instructions should also work for other HTTP libraries, you just need to replace the observer names accordingly.


This is how you can do it. The example tutorial below shows how to add this functionality to the RootViewController, but it could be added to any ViewController.

In the RootViewController.h


// RootViewController.h

#import <UIKit/UIKit.h>

@class GTMHTTPFetcher;

@interface RootViewController : UIViewController <UINavigationControllerDelegate> {

 int networkActivityCounter;
        ...
}

- (void)startFetchingData;
- (void)fetchData:(GTMHTTPFetcher *)fetcher finishedWithData:(NSData *)retrievedData error:(NSError *)error;

@end

Important here is the networkActivityCounter that will later hold the number of requests that are currently running.

In the RootViewController.m


// RootViewController.m

- (void)viewDidLoad{
 //add observer for fetcher start and stop events
 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
 [nc addObserver:self selector:@selector(incrementNetworkActivity:) name:kGTMHTTPFetcherStartedNotification object:nil];
 [nc addObserver:self selector:@selector(decrementNetworkActivity:) name:kGTMHTTPFetcherStoppedNotification object:nil];
 
 ...
 
}

First add the observers for the fetch start and stop events in the viewDidLoad method.

#pragma mark Network activity

- (void)incrementNetworkActivity:(NSNotification *)notify {
  ++networkActivityCounter;
  if (1 == networkActivityCounter) {
    UIApplication *app = [UIApplication sharedApplication];
    [app setNetworkActivityIndicatorVisible:YES];
  }
}

- (void)decrementNetworkActivity:(NSNotification *)notify {
  --networkActivityCounter;
  if (0 == networkActivityCounter) {
    UIApplication *app = [UIApplication sharedApplication];
    [app setNetworkActivityIndicatorVisible:NO];
  }
}

The increaseNetworkActivity is called when a fetch requested started, when the counter is at 1 the indicator gets displayed. After when the counter gets increased it doesn't need to be activated anymore, its still running.

Each time a fetch request has stopped the activity gets decreased, at 0 activity the indicator gets invisible.

- (void)dealloc {
 //remove the observer
 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
 [nc removeObserver:self];
 ...
 
 [super dealloc];
}

Don't forget to remove the observer when not needed anymore.