iPhone – iPad

iOS 5 Core Location

The following tutorial explains the use of Core Location Framework from iOS 5.

This application demonstrates use of
1) Core Location to track the location of the iphone
2) Map kit to visualize the location of the iphone
3) It places waypoints on the map after every 10 seconds and
4) Joins those waypoints using a black colored line.

Note : It is suggested to try out the application on the actual device as you cannot simulate location changes on the simulator

The Screenshots below explain how to
1) Create an xcode project using Xcode 4
2) Adding frameworks to the project (Mapkit and Core Location Framework)
3) Adding Delegates (MKMapViewDelegate, CLLocationManagerDelegate, UITextFieldDelegate)
4) Adding the basic UI elements using Interface builder

After this, i have included the header file which contains the properties and IBOutlets for the interface elements.

// iosViewController.h
// Tracker
// Created by Pratik Hande.
// Copyright (c) 2012. All rights reserved.

#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>

@interface iosViewController : UIViewController <MKMapViewDelegate, CLLocationManagerDelegate, UITextFieldDelegate>{
    // IBOutlets for the results of core location updates to be displayed
    IBOutlet UITextField *latitudeLongitude;
    IBOutlet UITextField *time;
    IBOutlet UITextField *speed;
    IBOutlet UITextField *distance;

    // Core Location Manager for managing location updates
    CLLocationManager *locationManager;

    // Map View for displaying results to a map
    IBOutlet MKMapView *map;

    // An array of way points where pins would be dropped on the map
    NSMutableArray *wayPoints;

    // Timer elements for timing location updates
    NSTimer *stopTimer;
    NSDate *stopTime;
    NSDate *startTime;

    // Total distance form the starting location
    float totalDistance;

    // Location instances to save inetermediate locations
    CLLocation *tempNewLocation, *tempOldLocation;

    // To draw the connecting line between waypoints
    MKPolyline * routeLine;
}

@property(nonatomic,retain) IBOutlet UITextField *latitudeLongitude;
@property(nonatomic,retain) IBOutlet UITextField *time;
@property(nonatomic,retain) IBOutlet UITextField *speed;
@property(nonatomic,retain) IBOutlet UITextField *distance;
@property(nonatomic, retain) CLLocationManager *locationManager;
@property(nonatomic, retain) IBOutlet MKMapView *map;
@property(nonatomic, retain) MKPolyline *routeLine;

@end

Implementation explained
In viewDidLoad()
1) We first create an instance of CLLocationManager and provide a delegate for it which is self. 2) We set the desiredAccuracy to 6.0 which indicates the accuracy desired on location horizontally.
3) We set the distanceFilter, which indicates the distance change after which a location update is received.
4) We call startUpdatingLocation method to start receiving location updates.
5) We assign a delegate for map view to self.
6) The setShowsUserLocation:YES shows a blue marker on the map view indicating the current location.
7) The call to setUserTrackingMode:MKUserTrackingModeFollow animated:YES allows the tracking of location on the map in an animated manner.
8) We also initialize an array for waypoints which would hold the locations on the map which have been marked.
9) Next we create, stop timer for based on a 10 second interval.

//
//  iosViewController.m
//  Tracker
//
//  Created by Pratik Hande.
//  Copyright (c) 2012. All rights reserved.
//

#import "iosViewController.h"

@implementation iosViewController

@synthesize latitudeLongitude, time, speed, distance, locationManager, map, routeLine;

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];

    locationManager = [[CLLocationManager alloc] init];
    locationManager.delegate = self;
    locationManager.desiredAccuracy = 6.0;
    locationManager.distanceFilter = 6.0;
    [locationManager startUpdatingLocation ];

    map.delegate = self;
    [map setShowsUserLocation:YES];
    [map setUserTrackingMode:MKUserTrackingModeFollow animated:YES];

    wayPoints = [[NSMutableArray alloc] initWithCapacity:30];
    totalDistance = 0.0;

    stopTime = [NSDate dateWithTimeIntervalSinceNow:140];
    startTime = [NSDate date];

    SEL sel = @selector(timerTargetMethod);
    NSInvocation* inv = [NSInvocation invocationWithMethodSignature:
                         [self methodSignatureForSelector:sel]];
    [inv setTarget:self];
    [inv setSelector:sel];

    stopTimer = [NSTimer scheduledTimerWithTimeInterval:10 invocation:inv repeats:true];
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
}

- (void)viewWillDisappear:(BOOL)animated
{
	[super viewWillDisappear:animated];
}

- (void)viewDidDisappear:(BOOL)animated
{
	[super viewDidDisappear:animated];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
    if(newLocation != nil && oldLocation != newLocation)
    {
        tempNewLocation = newLocation;
        tempOldLocation = oldLocation;
    }
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{

}

- (void)mapView:(MKMapView *)mv didAddAnnotationViews:(NSArray *)views
{
    MKAnnotationView *annotationView = [views objectAtIndex:0];
    id mp = [annotationView annotation];
    MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([mp coordinate] ,250,250);

    [mv setRegion:region animated:YES];
}

// MKMapViewDelegate
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id )overlay
{
    MKOverlayView* overlayView = nil;
    MKPolylineView  * routeLineView = [[MKPolylineView alloc] initWithPolyline:self.routeLine];
    routeLineView.fillColor = [UIColor colorWithRed:0.0-1.0 green:0.0-1.0 blue:0.0-1.0 alpha:1.0f];
    routeLineView.strokeColor = [UIColor colorWithRed:0.0-1.0 green:0.0-1.0 blue:0.0-1.0 alpha:1.0f];
    routeLineView.lineWidth = 10;
    routeLineView.lineCap = kCGLineCapSquare;
    overlayView = routeLineView;
    return overlayView;

}

//define the targetmethod
-(void) timerTargetMethod
{

    if([[NSDate date] timeIntervalSinceDate:startTime] >= 140)
    {
        [stopTimer invalidate];
        [locationManager stopUpdatingLocation];
        NSLog(@"Time started at %@", startTime);
        NSLog(@"Time up at %@", stopTime);
    }
    else if (tempOldLocation.coordinate.latitude == tempNewLocation.coordinate.latitude   && tempNewLocation.coordinate.longitude == tempOldLocation.coordinate.longitude)
    {
        NSLog(@" Fix location found ");
    }
    else if( [[NSDate date] timeIntervalSinceDate:startTime] >= 19 )
    {
        if(roundf([[NSDate date] timeIntervalSinceDate:startTime]) == 20)
        {
            NSLog(@"First Time Location Update");
            latitudeLongitude.text = [[ NSString alloc] initWithFormat:@"%g , %g", tempNewLocation.coordinate.latitude, tempNewLocation.coordinate.longitude];

            float interval = [[NSDate date] timeIntervalSinceDate:startTime];
            int okInterval = roundf(interval);
            NSLog(@"Interval 1 , %d", okInterval );
            time.text = [[ NSString alloc] initWithFormat:@"%d", okInterval  - 20];
            speed.text = @"0";
            totalDistance =  0;
            distance.text = @"0 meters";
        }
        else
        {
            latitudeLongitude.text = [[ NSString alloc] initWithFormat:@"%g , %g", tempNewLocation.coordinate.latitude, tempNewLocation.coordinate.longitude];

            float interval = [[NSDate date] timeIntervalSinceDate:startTime];
            int okInterval = roundf(interval);
            time.text = [[ NSString alloc] initWithFormat:@"%d", okInterval  - 20];
            NSLog(@"Interval 2 , %d , %f", okInterval , interval);
            if((tempNewLocation.coordinate.latitude == tempOldLocation.coordinate.latitude && tempNewLocation.coordinate.longitude == tempOldLocation.coordinate.longitude) || tempNewLocation.speed = 0)
                totalDistance +=  [tempNewLocation distanceFromLocation:tempOldLocation] - (tempNewLocation.horizontalAccuracy / 2);
            else
                totalDistance +=  [tempNewLocation distanceFromLocation:tempOldLocation];

            if (totalDistance < 0)
                distance.text = @"0 meters";
            else
                distance.text = [[ NSString alloc] initWithFormat:@"%g meters", totalDistance];
        }

        MKPointAnnotation *pa = [[MKPointAnnotation alloc] init];
        pa.coordinate = tempNewLocation.coordinate;
        [map addAnnotation:pa];
        [wayPoints addObject:tempNewLocation];

        MKMapPoint * pointsArray =
        malloc(sizeof(CLLocationCoordinate2D)*2);

        pointsArray[0]= MKMapPointForCoordinate(tempOldLocation.coordinate);
        pointsArray[1]= MKMapPointForCoordinate(tempNewLocation.coordinate);

        routeLine = [MKPolyline polylineWithPoints:pointsArray count:2];
        free(pointsArray);

        if (tempNewLocation.coordinate.latitude - tempOldLocation.coordinate.latitude < 1) {
            [map addOverlay:routeLine];
        }
    }
}

@end

Here is the source code for the project. Tracker Source Code

Key points UI designers should know when designing for iPad

Here are some points UI designers must keep in mind while developing UI for iPAD apps.

1. iPad’s screen size: 1024px x 768px

2. Status bar height: 20px

3. Screen Space available for the app when running in

1. Portrait Mode: 768px x 1004px
2. Landscape Mode: 1024px x 748px

4. iPad Screen PPI: 132

5. iPad Launch Image Names and Sizes

Filename Dimensions
Default-Portrait.png 768px x 1004px
Default-Landscape.png 1024px x 748px
Default-PortraitUpsideDown.png 768px x 1004px
Default-LandscapeLeft.png 1024px x 748px
Default-LandscapeRight.png 1024px x 748px

6. iPad app icon sizes

Application icon (required for all apps) 72px x 72px
App Store icon (required for all apps) 512px x 512px
for Spotlight search results 50px x 50px
for Settings 29px x 29px
Toolbar and navigation bar icons Approximately 20px x 20px
Tab bar icons Approximately 30px x 30px

7. Photoshop PSD and Vector Templates to get started with:

iPad GUI PSD – Version 2

iPad vector GUI elements: tabs buttons menus icons

iPad GUI Kit in PSD Format

iPhone / iPad icon PSD template

8. Most important : It’s going to be used with touch (fingers not mouse pointer). Hence all UI elements must have at least 30px x 30px room so that they are comfortably touchable.

Also on touch devices, there is no “mouse over” effect.

9. Must read: iOS Human Interface Guidelines

Pricing Strategies for iOS / Android apps

Mobisoft had a top paid app in a revenue-share model with client. App scaled to # 21 in lifestyle category. Naturally, we were excited to know the numbers – downloads, paid/free, adv hits etc. Although we made it great in terms of popularity, the earnings were less than expected.

The main reason was not having effective strategy for pricing model of app’s inApp & subscription purchases. What we realized is that “It could have been great to work on pricing strategy while developing the app” i.e. Monetization of app.

Why Monetize?

  • Generate money

How?

  • Compulsion Loops, there are ways to draw user back into the app
  • Engagement, does it have engagement elements that could be monetized, i.e. virtual currency?
  • Value, is it worth your users’ time?

Models

1. In-app purchases

2. Subscription

3. Ads

4. Location-based offerings

5. Social media sharing and aggregation

To do

1. Try various in-app models to find the combination that maximize your revenues

Games: Subscription based casual gaming package + premium payment for sending best scores

E-books for kids: read once for free. Pay to read again

Security: free trial (e.g. 30 days) . Paid license for 1 year period

• Video: pay per gallery

2. Freemium strategy

  • Strongest marketing play Risk reduction
  • Developers should be focused on finding consumers who are willing to pay, not trying to completely satisfy free-rider consumers

In-App single purchase

Pros:

• This is probably the easiest path to implementation and launch and it’s straightforward and proven

• Virtual goods/currency through In-App

Cons:

• No ongoing revenue stream No access to user data – makes selling advertising difficult.

• One potential workaround is to build in-app surveys, which pushes data back.

Subscription – I

Pros:

  • Revenue is sustainable
  • Renew just as other web based subscriptions
  • Easy extendable as an add-on

Cons:

  • Requires user management solution
  • Requires users to leave the app and visit the publisher’s website to subscribe
  • Conversion rate lower than in-app purchases
  • Success : lifetime value of a subscriber > revenue lost from lower conversion

Subscription – II

Apple’s subscription policy for publishers:

  • Apple still gets a 30% cut of any subscription a reader signs up for inside the App Store.
  • Publishers can now offer an app subscription for a different price than what they might sell their app for in the App Store.
  • Publishers can’t link to an external-to-Apple location that sells a subscription within the app.

Advertising

Apple: iAd platform – Adv as an app

Third party : adMob, Medialets etc

Pros:

  • Easier to command advertising premiums and less pressure to live up to metrics

Cons:

  • Mobile budgets just aren’t well-defined
  • Apple changes strategic decision with third party ad integration

Location Based Offerings

Pros:

  • Awesome mobile offerings into a high-fidelity advertising environment

Cons:

  • Complexity in integrating these systems
  • Requires the device be connected to the internet

Social, Sharing & Aggregation

Pros:

  • Cost-effective
  • Viral marketing
  • Better user engagement

Cons:

Getting advertiser support on a product as nebulous as this is challenging

Other payment integrations

  • Paypal API integrations
  • Carrier billing option – Very easy for users to pay
  • Virtual credits
  • Google Checkout

Other billing platforms

1 MoVend payment platform

  • Easy integration – Supports Android, BlackBerry, Windows Phone7
  • Sales Track Better user engagement

2 Bango

Supports all mobile platforms including Operator billing

Mobisoft Infotech recommend to work with clients as partners and provide various pricing strategies to monetize their app. It will be certainly helpful to clients to get pricing strategies correctly integrated while the app is being developed rather than working on monetization after app is live.

Thank you.

Key inputs to avoid Apple’s iOS app rejection

An app idea or product app takes much of time and money investment to get into app world existence. The major hurdle to it’s success could be Apple’s review process. There can be numerous reasons for Apple’s rejections for your app. With our superior knowledge of iOS apps development since the day Apple launched their SDK, we are able to gain valuable insights into Apple’s review process.

This will help:

1. Developers to save their precious time and efforts.

2. Let you plan for a better user experience which is the key reason behind all the app store guidelines.

There are few key points which every iPhone/iPad developer should know when developing an app for Apple devices.

Key things to avoid Apple’s app rejection:

1. Bugs/Crashes- The most common reason for any app to get rejected are freezing and frequent crashes. Make sure you test it on multiple devices, different OS versions and specifically under varying network conditions. Peer-to-peer reviews/testing done by developers would certainly help. If your app crashes or doesn’t respond during the app review by Apple’s testing team then it will definitely be rejected.

2. Code Download- You cannot create an app that downloads and executes code that was not present in the app bundle submitted to Apple.

3. Similar Icons- The app store 512×512 icon should be same as the app’s 57×57 icon. Even though there is no such direct rule in contract/agreement with Apple, its their store and they make the rules for reviews. If your app’s icon on phone and app store icon do not match, Apple will state having un-matching icons to reject the app.

4. Network Connectivity- You must notify the user if network is unavailable. Just having the spinning busy icon display and a message saying “trying to connect” is against the guidelines. Proper message is needed at all the screens to convey clear message if network is not available after certain period of time. Many developers put their connectivity checks on Apple’s Reachability code, which is using that sample code for the wrong purpose. If you need to get data from a specific server, then try to download some data from that domain.

5. “Free+Paid” apps- Apple reported to few developers that app may get rejected, if it contains visually disabled buttons, prompting the user to upgrade for the full version or displaying the price of full version in the Free version. So, iPhone developers must ensure that they follow all the rules.

6. Consistent Button Images- If an iPhone developer wants to use Apple’s existing image for his button then see that functions are identical because you can use a standard button in a non-standard way if your app is providing a “immersive environment” so it is better to create your own button. If there are any variations with function then again Apple might reject the app.

It is always advisable for an iPhone developer to use their own custom buttons in the app

7. iOS version support- If you plan on submitting and app which runs with 3.0 and higher versions, you should be sure that it works perfectly on all the versions from the iOS 3.0 to the most current version. Apple will test it with the latest version to see the potential of the app but if the app fails to prove itself Apple will definitely rejected your app.

8. Transactions outside The App Store-

Apple do not allow developers to conduct any transaction/business outside the app store. In App purchases are the recommended way to implement these transaction. Recent announcement to allow outside payment transaction with certain restriction and Apple’s percentage take from money for the same is trickier and would take more time to settle down in business plan of apps sale.

9. Private API:s

Apple strictly reject apps which are implementing programs using Private APIs. Apple has scripts that can scan your app codes for violations. If you want to prevent app rejection from app store make sure you read the developer guidelines carefully before implementing any API marked private by Apple.

10. Popovers-

It is definitely not recommended to launch one popover from within another popover. The iPad Human Interface Guidelines clearly provides this information that only one popover element should be shown onscreen at a time.

There can be many more reasons behind Apple’s rejection of any iOS app. However, the list provides very obvious ones.

Mobisoft Infotech sincerely wish this post is helpful to all our developer community and prestigious clients to achieve great success with iOS apps launch.

If you have any suggestions/feedback, please send your inputs to info@mobisoftinfotech.com

& for business enquiries : business@mobisoftinfotech.com

Thank you

iPhone Local Notifications

Local notifications :

Local notifications are used to notify user that application is having some updates,

while application is not running in foreground. We can display an alert message or badge on application icon. Local notifications can play sound when alert message or badge is shown.

We can use local notification to remind our daily or monthly tasks at particular time like water plants, pay electricity bill, attend seminar , prepare for presentation etc. In these cases we can use local notification.

Create notification :

- (void)scheduleNotification {

  [[UIApplication sharedApplication] cancelAllLocalNotifications];
	
UILocalNotification notif = [[cls alloc] init];

notif.fireDate = [datePicker date];
notif.timeZone = [NSTimeZone defaultTimeZone];

notif.alertBody = @"Reminder for you";
notif.alertAction = @"Show";
notif.soundName = UILocalNotificationDefaultSoundName;
notif.applicationIconBadgeNumber = 1;

NSDictionary *userDict = [NSDictionary dictionaryWithObject:@"Notification 	  text" forKey:kRemindMeNotificationDataKey];

notif.userInfo = userDict;

[[UIApplication sharedApplication] scheduleLocalNotification:notif];
[notif release];
}

Cancel any exiting local notification

[[UIApplication sharedApplication] cancelAllLocalNotifications];

Allocate and initialize UILocalNotification object

UILocalNotification *notif = [[cls alloc] init];

Set fire date and timezone. Fire date is date and time when system should deliver the notification. Date is calculated depending on timezone specified.If we do not specify timezone then it will take GMT as default time zone.

 notif.fireDate = [datePicker date]; 

notif.timeZone = [NSTimeZone defaultTimeZone];

We can control alert message displayed when notification is delivered by setting alertBody and alert action by setting alertAction.

notif.alertBody = @"Reminder for you"; 

notif.alertAction = @"Show";

We can also specify sound to be played when notification is delivered by setting soundName and also specify badge number on application icon by setting applicationIconBadgeNumber.

 notif.soundName = UILocalNotificationDefaultSoundName; 

notif.applicationIconBadgeNumber = 1;

We can also pass custom data with notification by adding it into dictionary. We can add dictionary to notification using userInfo property.

NSDictionary *userDict = [NSDictionary dictionaryWithObject:@"Notification text" forKey:kRemindMeNotificationDataKey];

notif.userInfo = userDict;

Here we are passing notification text as custom data.

In case if we want to increase icon badge number we can get current badge number by using.

[[UIApplication sharedApplication] applicationIconBadgeNumber ];

If you want to repeat notification then you can set following property to required calendar unit.

notif.repeatInterval = NSMinuteCalendarUnit;

OR

notif.repeatInterval = NSHourCalendarUnit;

OR

notif.repeatInterval = NSDayCalendarUnit;

OR

notif.repeatInterval = NSWeekCalendarUnit;

App Idea: Are you working on iPhone/iPad app similar to existing one in Store?

Now that there are 300K+ apps on AppStore, there is high possibility that your idea has been implemented and have an app on store for sale.  We are getting many requirements from clients about creating an app similar to one in AppStore and at the same time with the concern, whether they can make money out of it?

It is obvious that existing competition for an app idea means that your life is going to be harder. However, it definitely does not mean that their implementation for the app is the best it could be. If you can add something to the already existing idea that can improve the app or make it more appealing, Go ahead!!

In such scenario, you need smart companies well-versed in market research to figure out whether it would be worth the competition. “We are here for you” :)

Ask yourself these basic questions:

  • Are users who purchased the app happy with the existing app?
  • There are chances in the sea of app world that they are not happy about it , find out the roots.
  • It can be price structure of the app that users are not happy about. Is it wrongly priced? e.g. Unnecessary in-app purchases at regular intervals of app usage, multi-level unlocking of features with payments, prices are not justified for what they offer etc.
  • Can you offer better pricing model?
  • Do you have list of superior features including ‘must-have’?
  • Do you have enough resources and money to compete with existing app?

Lets DISCOVER the potential of your idea together and have a refreshing app experience for 125 Million iOS users.

Team

Mobisoft Infotech

iPad GUI PSD file

The fine folks at teehanlax.com have created a nice GUI template for iPad, which can be customized in Photoshop. You can download it from here.

And if you can bear some ads then this blog post has a nice list of 7 such GUI packs.

iPhone UITableView Tutorial: Grouped Table

Grouped table view is an extension of the normal table view in iPhone. It displayes the data in several sectioned lists. Each section has a header and number of rows associated with it. Examples of grouped table are the ‘contacts’ list, a dictionary,etc. In this tutorial, we will create a grouped table using a dictionary, to create a names list,unlike the plain table in which we had used an array. So lets get started!

Step 1: Create a view based application and name it ‘GroupedTable’.

Step 2: Put the following code in ‘GroupedTableViewController.h’

#import <UIKit/UIKit.h>

@interface GroupedTableViewController : UIViewController {
	NSDictionary *tableContents;
	NSArray *sortedKeys;
}

@property (nonatomic,retain) NSDictionary *tableContents;
@property (nonatomic,retain) NSArray *sortedKeys;
@end

Here, we have declared a dictionary to hold the section headers and their respective row contents. And an array to hold the sorted keys of the dictionary.

Step 3: Now, open ‘GroupedTableViewController.m’ file and put the following code in it.

#import "GroupedTableViewController.h"

@implementation GroupedTableViewController
@synthesize tableContents;
@synthesize sortedKeys;

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
	NSArray *arrTemp1 = [[NSArray alloc]
                        initWithObjects:@"Andrew",@"Aubrey",@"Alice",nil];
	NSArray *arrTemp2 = [[NSArray alloc]
                        initWithObjects:@"Bob",@"Bill",@"Bianca",nil];
	NSArray *arrTemp3 = [[NSArray alloc]
                        initWithObjects:@"Candice",@"Clint",@"Chris",nil];
	NSDictionary *temp =[[NSDictionary alloc]
               initWithObjectsAndKeys:arrTemp1,@"A",arrTemp2,
                                                       @"B",arrTemp3,@"C",nil];
	self.tableContents =temp;
	[temp release];
	self.sortedKeys =[[self.tableContents allKeys]
                              sortedArrayUsingSelector:@selector(compare:)];
	[arrTemp1 release];
	[arrTemp2 release];
	[arrTemp3 release];
       [super viewDidLoad];
}

- (void)dealloc {
	[tableContents release];
	[sortedKeys release];
        [super dealloc];
}

#pragma mark Table Methods

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    return [self.sortedKeys count];
}

- (NSString *)tableView:(UITableView *)tableView
 titleForHeaderInSection:(NSInteger)section
{
	return [self.sortedKeys objectAtIndex:section];
}

- (NSInteger)tableView:(UITableView *)table
numberOfRowsInSection:(NSInteger)section {
	NSArray *listData =[self.tableContents objectForKey:
                                 [self.sortedKeys objectAtIndex:section]];
	return [listData count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView
		 cellForRowAtIndexPath:(NSIndexPath *)indexPath {
	static NSString *SimpleTableIdentifier = @"SimpleTableIdentifier";

	NSArray *listData =[self.tableContents objectForKey:
                     [self.sortedKeys objectAtIndex:[indexPath section]]];

	UITableViewCell * cell = [tableView
	          dequeueReusableCellWithIdentifier: SimpleTableIdentifier];

	if(cell == nil) {

		 cell = [[[UITableViewCell alloc]
		 initWithStyle:UITableViewCellStyleDefault
		 reuseIdentifier:SimpleTableIdentifier] autorelease];

		/*cell = [[[UITableViewCell alloc]
				 initWithStyle:UITableViewCellStyleSubtitle
				 reuseIdentifier:SimpleTableIdentifier] autorelease];
		*/
	}

	NSUInteger row = [indexPath row];
	cell.textLabel.text = [listData objectAtIndex:row];

	return cell;
}

- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
	NSArray *listData =[self.tableContents objectForKey:
                    [self.sortedKeys objectAtIndex:[indexPath section]]];
	NSUInteger row = [indexPath row];
	NSString *rowValue = [listData objectAtIndex:row];

	NSString *message = [[NSString alloc] initWithFormat:rowValue];
	UIAlertView *alert = [[UIAlertView alloc]
						  initWithTitle:@"You selected"
						  message:message delegate:nil
						  cancelButtonTitle:@"OK"
						  otherButtonTitles:nil];
	[alert show];
	[alert release];
	[message release];
	[tableView deselectRowAtIndexPath:indexPath animated:YES];
}

@end

viewdidLoad: Here, we populate the dictionary using three arrays of names as objects and alphabets as keys. Then we sort the array ‘allKeys’ of the dictionary and put it in sortedKeys.

Table Methods

numberOfSectionsInTableView : Returns the count of keys in the dictionary.

titleForHeaderInSection : Returns the value of key for that particular section.

cellForRowAtIndexPath : Here, listdata is an array which is assigned the value for the key corresponding to the respective section. For every section, the contents of listdata are displayed.

didSelectRowAtIndexPath : In this method, we display an alert view when a row is selected.

Step 4 : Open the ‘GroupedTableViewController.xib’. Drag and drop a table view on it. Select the table view and open its Attributes Inspector (command+1). Change the table style from ‘Plain’ to ‘Grouped’.

Step 5 : Open the Connections Inspector (command+2) for the table and link its datasource and delegate to the file’s owner.


Step 6 : You can download the source code here.Save,build and run the project. The output will be as follows:

iPhone TabBar: UITabBarController Tutorial

A Tab Bar Controller helps to organize an application along functional lines.It is used to switch between multiple pages in an application. Each tab of a tab bar controller interface is associated with a view controller.Whenever a tab is tapped by a user,the tab bar controller object selects the particular tab and displays the corresponding view associated with the tab.This blog will assist you on how to create applications using tab bar controller.

Step 1 : Start Xcode and create a new project by selecting Window- Based Application.

Step 2 : Open “PrjTabBarControllerAppDelegate.h” and put following code in it.

#import <UIKit/UIKit.h>

@interface PrjTabBarControllerAppDelegate:NSObject
<UIApplicationDelegate> {

	   UIWindow *window;
	   UITabBarController *tcTabBar;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet *tcTabBar;
@end

Here ‘”tcTabBar” is an instance variable of type UITabBarController. We have created an outlet, so that we can relate our instance ‘tcTabBar’ with TabBarController.

Step 3 : Open “PrjTabBarControllerAppDelegate.m” and put following code in it. In the ‘applicationDidFinishLaunching’ method we have added the Tab Bar Controller as a sub view to the existing window. Save the project using (command + S).

#import "PrjTabBarControllerAppDelegate.h"

@implementation PrjTabBarControllerAppDelegate

@synthesize window;
@synthesize tcTabBar;

- (void)applicationDidFinishLaunching:(UIApplication *)application {

	// Override point for customization after application launch
	[window addSubview:tcTabBar.view];
	[window makeKeyAndVisible];
}

- (void)dealloc {
	[tcTabBar release];
 	[window release];
  	[super dealloc];
}

@end

Step 4 : Open the Interface Builder by double clicking on MainWindow.xib file. Drag & Drop a Tab Bar Controller from the Library(shift + command + L.). Make sure that the Tab Bar Controller is dropped on the MainWindow.xib since it is not allowed to be placed on the View Controller.We will see a Tab Controller with two bar items created for us. Add one more tab item to it from the library.

As we can see a Tab Bar Item has ‘Title’ & ‘Image’ associated with it. Double Click on Item 1. Open the ‘Attributes Inspector’ (command + 1).In the ‘Atrributes Inspector’ we can set the title & image for Tab Bar Item. The image that we are adding should be present in the Project folder.To add an image to Project right click on ‘Resources’ -> Add -> Existing Files and select the image.

Step 5 : Now connect the Tab Bar Controller to PrjTabBarControllerAppDelegate. Open the ‘Connection Inspector’ (command + 2). Connect “tcTabBar” in the File’s Owner to Tab Bar Controller.

Step 6 : Right click on ‘Classes’ in Group & Files Explorer & add UIViewController subclass file. Select the option ‘With XIB for user interface’. The files added should be equal to number of Tab Bar items present.Here, we add three UIViewController so name them as View1ViewController, View2ViewController, View3ViewController.

Step 7 : Open the View2ViewController.xib by double clicking on it. Set the color of the view from the ‘Attribute Inspector’.Save & Close the .xib file. Similarly set the colours for other views.

Step 8 : Now we need to specify which views should be there in each tab of TabBarController. For this open ‘Interface Builder’. Open ‘Identity Inspector’ (command + 4). Set the class of each Tab Bar Item to its respective view.


Step 9 : Save,Build & Run the project.When we switch the tabs you will observe the views .

You can download the source code here.

Output:

iPhone UIButton tutorial: Radio Buttons

Radio buttons is a set of buttons out of which only one can be set at a time. For example: Selecting the time format out of 12-hr and 24-hr in a clock application.They are often required in iPhone UIs. Unfortunately, they are not included in the iPhone sdk. In this tutorial, we will learn how to create custom radio buttons.

Step 1: Create a window based application in Xcode and name it “MIRadioButtonGroup”.

Step 2: Create new “MIRadioButtonGroup.h” and “MIRadioButtonGroup.m” files which extend from UIView.
(Classes >> Add >> New File >> Objective C Class. Select UIView in the “subclass of” list.)

Step 3: Create a new group in the Classes folder and name it “MIRadioButtonGroup”. Drag the “MIRadioButtonGroup .h” and “MIRadioButtonGroup .m” files into the group.Now, add the images “radio-on.png” and “radio-off.png” to the group.

Step 4: Open the “MIRadioButtonGroup.h” file and make the following changes in it.

@interface MIRadioButtonGroup : UIView {
NSMutableArray *radioButtons;
}

@property (nonatomic,retain) NSMutableArray *radioButtons;

- (id)initWithFrame:(CGRect)frame andOptions:(NSArray *)options
          andColumns:(int)columns;
-(IBAction) radioButtonClicked:(UIButton *) sender;
-(void) removeButtonAtIndex:(int)index;
-(void) setSelected:(int) index;
-(void)clearAll;
@end

Here, we have declared a mutable array “radioButtons” which will hold all the buttons that we add to the radio button group.

The methods declared are:
initWithFrame – It is a constructor used to initialize the group. It takes the frame for the entire group,an array holding the titles of the buttons and the number of columns in which the buttons are to be arranged as input parameters.

radioButtonClicked – This method is used to set the button which is clicked.

removeButtonAtIndex – This method is used to remove a radio button at a particular index from the group.

setSelected – This method is used to set the button at the specified index.

clearAll – This method clears all the buttons including the currently set button.

Step 5: Open the “MIRadioButtonGroup.m” file and put the following code in it.

#import "MIRadioButtonGroup.h"

@implementation MIRadioButtonGroup
@synthesize radioButtons;

- (id)initWithFrame:(CGRect)frame andOptions:(NSArray *)options
      andColumns:(int)columns{

               NSMutableArray *arrTemp =[[NSMutableArray alloc]init];
               self.radioButtons =arrTemp;
               [arrTemp release];
              if (self = [super initWithFrame:frame]) {
                      // Initialization code
                      int framex =0;
                      framex= frame.size.width/columns;
                      int framey = 0;
                      framey =frame.size.height/([options count]/(columns));
                      int rem =[options count]%columns;
                      if(rem !=0){
                             framey =frame.size.height/(([options  count]
                                            /columns)+1);
            }
            int k = 0;
            for(int i=0;i&lt;([options count]/columns);i++){
                 for(int j=0;j<columns;j++){

                          int x = framex*0.25;
                          int y = framey*0.25;
                          UIButton *btTemp = [[UIButton alloc]
                           initWithFrame:CGRectMake(framex*j+x, framey*i+y,
                           framex/2+x, framey/2+y)];
                           [btTemp addTarget:self action:
                           @selector(radioButtonClicked:)
                            forControlEvents:UIControlEventTouchUpInside];
                            btTemp.contentHorizontalAlignment =
                             UIControlContentHorizontalAlignmentLeft;
                           [btTemp setImage:[UIImage imageNamed:
                           @"radio-off.png"] forState:UIControlStateNormal];
                           [btTemp setTitleColor:[UIColor blackColor]
                            forState:UIControlStateNormal];
                           btTemp.titleLabel.font =[UIFont systemFontOfSize:14.f];
                         [btTemp setTitle:[options objectAtIndex:k]
                                 forState:UIControlStateNormal];
                         [self.radioButtons addObject:btTemp];
                         [self addSubview:btTemp];
                         [btTemp release];
                         k++;

               }
        }

        for(int j=0;j<rem;j++){

                int x = framex*0.25;
                int y = framey*0.25;
                UIButton *btTemp = [[UIButton   alloc]
                   initWithFrame:CGRectMake(framex*j+x,
                   framey* ([options count]/columns),
                                                framex/2+x,framey/2+y)];
                [btTemp addTarget:self action:@selector(radioButtonClicked:)
                   forControlEvents:UIControlEventTouchUpInside];
                btTemp.contentHorizontalAlignment =
                     UIControlContentHorizontalAlignmentLeft;
               [btTemp setImage:[UIImage imageNamed:@"radio-off.png"]
                                  forState:UIControlStateNormal];
               [btTemp setTitleColor:[UIColor blackColor]
                                    forState:UIControlStateNormal];
               btTemp.titleLabel.font =[UIFont systemFontOfSize:14.f];
               [btTemp setTitle:[options objectAtIndex:k]
                                        forState:UIControlStateNormal];
               [self.radioButtons addObject:btTemp];
               [self addSubview:btTemp];
               [btTemp release];
               k++;

        }

    }
       return self;
}

- (void)dealloc {
         [radioButtons release];
         [super dealloc];
}

-(IBAction) radioButtonClicked:(UIButton *) sender{

           for(int i=0;i&lt;[self.radioButtons count];i++){
                   [[self.radioButtons objectAtIndex:i] setImage:[UIImage
                               imageNamed:@"radio-off.png"]
                                    forState:UIControlStateNormal];
           }
           [sender setImage:[UIImage imageNamed:@"radio-on.png"]
                                 forState:UIControlStateNormal];

}

-(void) removeButtonAtIndex:(int)index{
           [[self.radioButtons objectAtIndex:index] removeFromSuperview];
}

-(void) setSelected:(int) index{
        for(int i=0;i&lt;[self.radioButtons count];i++){
             [[self.radioButtons objectAtIndex:i] setImage:[UIImage
           imageNamed:@"radio-off.png"] forState:UIControlStateNormal];

         }
         [[self.radioButtons objectAtIndex:index] setImage:[UIImage
          imageNamed:@"radio-on.png"] forState:UIControlStateNormal];

}

-(void)clearAll{
          for(int i=0;i&lt;[self.radioButtons count];i++){
                     [[self.radioButtons objectAtIndex:i] setImage:[UIImage
                                                 imageNamed:@"radio-off.png"]
                                                 forState:UIControlStateNormal];
            }
}

@end

initWithFrame – In this method, we first divide the frame into n number of boxes with width framex and height framey, where n =([options count]/columns)*columns. Then we check to see if there is any remainder for ([options count]/columns). The reason for this will be explained later.
In the proceeding nested “for” loops, we set the frames of the buttons so that each button occupies 50% space of each of the n boxes. After that we link the button programmatically to the “radioButtonClicked” method. We set the alignment of the content(radio button image and title) to left. Then we set the image for the button, configure its font color and font size and set its title.

This code works fine when the number of buttons is perfectly divisible by columns, but when it is not, the remaining buttons are not printed.
Now, the remainder comes in picture. What we do is, if there is a non-zero remainder, we add 1 to the divisor in framey equation,so that there is space for an extra row in the frame. In the next “for” loop, we insert that extra row and hence, cover the missing buttons.

radioButtonClicked – Here, we first clear all the buttons in the “radioButtons” array by setting their images to “radio-off.png”. Then, we set only the sender button by setting its image to “radio-off”.

removeButtonAtIndex – In this method, we remove the button at the specified index with the “removeFromSuperview” method.

setSelected – This method is similar to the “radioButtonClicked” method. The difference is we set the button at the specified index in the “radioButtons” array.

clearAll – In this method, we clear all the radio buttons by setting the images of the buttons in “radioButton” to “radio-off.png”.

Step 6: Now that we have created the “MIRadioButtonGroup” files, put the following code in the “MIRadioButtonGroupAppDelegate.m” file so that we can test them.

#import "MIRadioButtonGroupAppDelegate.h"
#import "MIRadioButtonGroup.h"

@implementation MIRadioButtonGroupAppDelegate
@synthesize window;

- (void)applicationDidFinishLaunching:(UIApplication *)application {

         // Override point for customization after application launch
         NSArray *options =[[NSArray alloc]
                        initWithObjects:@"1",@"2",@"3",@"4",@"5",@"6",nil];
         MIRadioButtonGroup *group =[[MIRadioButtonGroup alloc]
                                   initWithFrame:CGRectMake(0, 20, 320, 75)
                                             andOptions:options andColumns:4];
          [options release];
          [window addSubview:group];
          //[group setSelected:1];
         //[group clearAll];
        //[group removeButtonAtIndex:2];
        [window makeKeyAndVisible];
}

- (void)dealloc {
         [window release];
         [super dealloc];
}

@end

Step 7: Save, build and run the project. The output will be Output1. Now uncomment the commented lines one by one and observe the output. It will be Output 2, Output 3 and Output 1 respectively.

You can download the source code here.