Sunday, October 2, 2011

Local Notifications (iOS 4)

With the coming of iPhone OS 3, push notifications were introduced which enables an application to alert user while the application isn't running. Push notifications solved many of the issues associated with background processing. For example, when quitting the Facebook application, the server could keep you logged in and send you a push notification when a new message arrived. You could then tap on a View button that would launch the app.
This solution is great and all, but it still requires that you have an active internet connection. As of iOS4, Apple has introduced a new type of notification that can be scheduled to fire within the device itself. It requires no complicated server programming. These are known as Local Notifications.

Local notifications can be scheduled on the user’s device to fire at any given time; you can even set them to be recurring. Today, we will explore these notifications and go through a simple example of how to schedule, view, and handle local notifications.

The project will allow a user to schedule a location notification to fire off at a given date. Using the text field, they are also able to specify some text for the notification. The table view below displays a list of all of the currently scheduled location notifications within the application.

Step 1
Create a View Based Applicatin and name it LocalNotifier.

Step 2

Create all properties and dummy IBActions. Copy the code below in your .h file
@interface LocalNotifierViewController : UIViewController {
IBOutlet UITableView *tableview;
IBOutlet UIDatePicker *datePicker;
IBOutlet UITextField *eventText;
}

@property (nonatomic, retain) IBOutlet UITableView *tableview;
@property (nonatomic, retain) IBOutlet UIDatePicker *datePicker;
@property (nonatomic, retain) IBOutlet UITextField *eventText;

- (IBAction) scheduleAlarm:(id) sender;

@end


We have defined three fields, one is a TableView to dipslay all the scheduled notifications, another is a TextField where use enters the event description of any new notification to be scheduled and the last field is datePicker from where user picks the date when he wants to schedule the new notification or wants to see all notifications for that day.

Next, setup the .m file of your viewController.
@synthesize datePicker,tableview, eventText;

- (IBAction) scheduleAlarm:(id) sender {

}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}

- (void)viewDidUnload {
datePicker = nil;
tableview = nil;
eventText = nil;
}

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


Now it’s time to build our interface. Open Interface builder and construct an interface like this.



Step 3: Implement UITableViewDelegate and UITableViewDataSource Delegate methods to List Currently Scheduled Local Notifications

Add the following code in your .m file


- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// We only have one section
return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of notifications
return [[[UIApplication sharedApplication] scheduledLocalNotifications] count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}

// Get list of local notifications
NSArray *notificationArray = [[UIApplication sharedApplication] scheduledLocalNotifications];
UILocalNotification *notif = [notificationArray objectAtIndex:indexPath.row];

// Display notification info
[cell.textLabel setText:notif.alertBody];
[cell.detailTextLabel setText:[notif.fireDate description]];

return cell;
}


So, the new code here is dealing with retrieving a list of scheduled notifications. Calling the scheduledLocalNotifications method of UIApplication will return an NSArray of all notifications scheduled by the current app. We just index into this array and grab each notification.

Finally, we are displaying the alertBody (text that displays when the notification fires) and the fireDate (date and time when the notification will display) in the tableview cell.

Step 4: Scheduling Notifications
Update your .m file to contain the following code.


- (IBAction) scheduleAlarm:(id) sender {
[eventText resignFirstResponder];

NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];

// Get the current date
NSDate *pickerDate = [self.datePicker date];

// Break the date up into components
NSDateComponents *dateComponents = [calendar components:( NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit )
fromDate:pickerDate];
NSDateComponents *timeComponents = [calendar components:( NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit )
fromDate:pickerDate];
// Set up the fire time
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
[dateComps setDay:[dateComponents day]];
[dateComps setMonth:[dateComponents month]];
[dateComps setYear:[dateComponents year]];
[dateComps setHour:[timeComponents hour]];
// Notification will fire in one minute
[dateComps setMinute:[timeComponents minute]];
[dateComps setSecond:[timeComponents second]];
NSDate *itemDate = [calendar dateFromComponents:dateComps];
[dateComps release];

UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif == nil)
return;
localNotif.fireDate = itemDate;
localNotif.timeZone = [NSTimeZone defaultTimeZone];

// Notification details
localNotif.alertBody = [eventText text];
// Set the action button
localNotif.alertAction = @"View";

localNotif.soundName = UILocalNotificationDefaultSoundName;
localNotif.applicationIconBadgeNumber = 1;

// Specify custom data for the notification
NSDictionary *infoDict = [NSDictionary dictionaryWithObject:@"someValue" forKey:@"someKey"];
localNotif.userInfo = infoDict;

// Schedule the notification
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
[localNotif release];

[self.tableview reloadData];
}


We just use the NSCalendar object to break up the date into components. Note: This demo does not require that we break the date up into components. You could have just as easily fed the date from the date picker into the notification fireDate. The reason that I’m showing you how to break it down is, you may have some sort of custom date logic to work with and this makes things much easier in the future.
Another important bit of code is where we set the alertBody or the notification. In this example we set it to the text that the user entered into the text field. You can set this to whatever you like.
The other thing I want to mention is the infoDict in the code. This dictionary is your chance to associate some additional information with the alert. For example, if you are using this alert in a game like We Rule to notify you when a crop is ready. You might want to set a key and value that contains the id of the crop that has completed. For now, we just set some arbitrary values and you can ignore them if you like.
After actually scheduling the notification, we just reload the tableview to get it to display immediately.

Step 5: Handling Notifications After They Fire
The last piece of this puzzle is determining what to do when a notification fires. Fortunately, this step is very easy and handled inside of the appDelegate. When a notification fires, there are one of two situations. 1. The app is running and 2. The app is not running (or running in the “background”) .

Open up your app delegate .m file and add the following code.


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

// Override point for customization after application launch.

// Add the view controller's view to the window and display.
[window addSubview:viewController.view];
[window makeKeyAndVisible];

application.applicationIconBadgeNumber = 0;

// Handle launching from a notification
UILocalNotification *localNotif =
[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotif) {
NSString *reminderText = [notification.userInfo
objectForKey:@"someKey"];
NSLog(@"Recieved Notification %@",localNotif);
}

return YES;
}

- (void)application:(UIApplication *)app didReceiveLocalNotification:(UILocalNotification *)notif {
// Handle the notificaton when the app is running
NSLog(@"Recieved Notification %@",notif);
}


The first thing we see here is the application badge number is getting set to 0. Whenever a notification fires, it will increase the badge count on the application. Next, we handle the case when the application launches from a notification. This happens when the user presses the view button on the notification. For now, we just NSLog the data, but you should handle the notification how you see fit for your app.

Finally, we implement the didReceiveLocalNotification method. This method is required if you want to handle notifications at all in your app. You will see this method fire when the app is running and you receive a local notification. When the app is running, you will not see the UIAlertView show up with the notification data. Also keep a note the method - (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
is only called upon when the application is not running and if the application is running in background or foreground, only this methhod gets called: - (void)application:(UIApplication *)application
didReceiveLocalNotification:(UILocalNotification *)notification


And there you have it! The complete lifecycle of a local notification.

Saturday, August 27, 2011

An Introduction to iOS Categories

Have you ever wished that you could add one, or a couple, additional functions to an Objective-C core class?

Well Apple has thought of this, and they provide a way without extended the class! The way to do this is called a category. A category is a way to enhance an existing class, by adding additional functions to it. The difference between this and extending a class is that when you extend a class, you can add additional functions, as well as variables. In a category, you can only add additional functions. The benefit of a category though is that you don’t have to use the extended class to get the benefits of the added additional functions. All you have to do is include the header file of the category, and the additional functions of that class are available to you.

A simple NSDate Example
Say we have an NSDate object, and we know that we want it to always be formatted in a customized way. You can create an NSDate category, with an additional function called getFormattedString, that will always return an NSString * with the current date formatted a certain way.

Starting with programming
Categories typically have the convention of ClassName+OurText.m, so we create a new file of subclass NSObject, called NSDate+FormatString.m, make sure to check “Also create NSDate+FormatString.h”. After creating those files, we need to make some minor changes to them to actually have them be treated as categories. In the header file, change
@interface NSDate_FormattedDate : NSObject { } @end
to
@interface NSDate (FormattedDate) @end
making sure to remove the brackets, in the header file. The reason for this is that a category can not add variables, only functions.
In the implementation file, change
@implementation NSDate_FormattedDtae
to
@implementation NSDate (FormattedDate)

We have now created a category! This of course doesn’t do anything yet, so lets add some meat to it.
// In NSDate+FormattedDate.h, after @interface add
- (NSString *)getFormattedString: (NSString *)desiredFormat;
// And in NSDate+FormattedDate.m, after @implementation add - (NSString *)getFormattedString: (NSString *)desiredFormat { NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:desiredFormat];//@"MM/dd/yyyy h:mm a"]; NSString *returnDate = [formatter stringFromDate:self]; [formatter release]; return returnDate; }

Now to use this category, all we have to do is add
#import "NSDate+FormattedDate.h"
to any file where we have an NSDate, and we will be able to call
NSDate *today = [NSDate date]; //get the current date NSLog(@"The current date is: %@", [today getFormattedString:@"MM/dd/yyyy h:mm a"]);

This will print out today’s date all nicely formatted for you!

Of course this is just a very basic example of using a Category but it will get you started easily.
Get the sample files from github.

Update:
There is an additional step for compiling and making an universal static library which can work on both simulator and device.
Compile your library twice. Once using the device SDK, and again using the Simulator SDK.
Then use the lipo command line tool to create a "fat" library.
lipo -create libdevice.a libsimulator.a -output libcombined.a

Friday, June 17, 2011

Monetizing your iOS app (iAd integration)

With iOS SDK 4, Apple has given a new way to integrate third-party ads and earn more revenue from your iOS application.
In this tutorial I will show how to integrate iAd and supporting both portrait and landscape ad into your app.

Here is what we will get working after this tutorial


Step 1: Base SDK vs Deployment Target
The first step to use iAd is to make sure our project has the right Base SDK and iPhone OS Deployment Target selected.

For those of you confused about the difference between the Base SDK and Deployment Target (like I was for quite some time!), here’s what they mean:

* The Base SDK is the version of the SDK you are linking against. Your app can use any classes or functions available in the version of the SDK you choose here – as long as they are available on the actual device the code runs on.
* The Deployment Target is the earliest possible version of the SDK your code can run on. This can be an earlier version than the Base SDK – in fact you often want to set it to be earlier to ensure that as many different versions of the OS can run your code as possible!

The tricky bit is what happens when you want to use a class, function, or framework available in one version of the OS if it’s available, but still work on the old version of the OS if it isn’t.

For this tutorial, we will stick on using iOS 4 (or later) as target SDK since iAd was introduced after this version only.

But as a side note, lets also explain the case where we want to set things up so that our code can use stuff available in iOS 4.0 (such as iAd), but still run on as many devices as reasonable (3.0+). Just a few more steps are involved in it.

So first let’s set iOs 4.0(or later) as the base SDK. Then, let’s set iPhone OS 3.0 as the iPhone OS Deployment Target.



You should now be able to compile and run your app (use the iPhone simulator), and try it out on an iPhone 4 simulator. But if you try to run it on iPhone 3 simulator, your app will crash. Lets fix it up.

Linking Against the iAd Framework
The next thing we need to do is add the iAd framework to the project. You can do this by right clicking on Frameworks, choosing “Add\Existing Frameworks…”, and choosing “iAd.framework” (for Xcode 3) or adding "iAd.framework" under Build Phases of your applicatin Target module.



The problem is, if that is all we do our code will break on older devices that don’t have the iAd framework.
To fix this, we need to weak link against the iAd framework. Expand the Targets directory, right click on PortMe, and choose “Get Info”. Click the Build tab, make sure “All Configurations” is selected, and navigate to Linking\Other Linker Flags. Double click on that entry, click the “+” button, and type “-weak_framework iAd”.
Click OK, and then try your app on the iPad simulator again and viola – it should work!

Step 2: Start iAd integration programmatically (.h file)

First make the changes in your View Controller .h file to look like this.



We first include the iAd headers and mark the view controller as implementing the ADBannerViewDelegate. This way, we can receive events as ads become available or not.
We then declare the ADBannerView which will be your view holding and displaying the ads.We also declare a variable (bannerIsVisible) to keep track of our iAd banner view, and whether or not it’s currently visible.

Step 3: Some memory management in .m file



Fist synthesize your variable bannerIsVisible. Then do some memory management stuff by releasing your ADBannerView's instanceadView in dealloc method.

Step 4: Main 4 delegate methods doing all heavy-lifting for iAd integration



The first method is called up when the Banner View is loaded for the first time and ads become available for display. Here we set the variable bannerIsVisible to YES.
- (void)bannerViewDidLoadAd:(ADBannerView *)banner


The second method is called upon the failure to load the Ad View due to any reason (no internet connection or other..)
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error


Thisd method is called up when user taps on the iAd and the full-screen iAd gets loaded up. We should pause our main application at this point as the user is interating with the ad this whole time and we free-up maximum resources as our app does not needs it at that time.
- (BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave


The last method is called when user closes the iAd. Here we should resume our application processes again.
- (void)bannerViewActionDidFinish:(ADBannerView *)banner


Step 5: Initialize iAd in viewDidLoad Method

We need to initialize the ADBannerView in our viewDidLoad method ie; when our view gets loaded. Here we set all the required variables of ADBannerView (like frame, contentSize etc.) and add this view as a subview to our main ViewController's view.



Now, Build and Run the code, you should get your app up and running and iAd getting displayed on the screen.

Step 6: Support for multiple orientations

Till now we are able to integrate iAd into our application but it supports only portrait mode. Lets get it supported in all modes.



First we enable our application's support for all orientations and then we call a method
- (void)fixupAdView:(UIInterfaceOrientation)toInterfaceOrientation
whenever the orientation of the device gets changed.

fixupAdView:


- (void)fixupAdView:(UIInterfaceOrientation)toInterfaceOrientation {
if (adView != nil) {
if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) {
[adView setCurrentContentSizeIdentifier:ADBannerContentSizeIdentifierLandscape];
} else {
[adView setCurrentContentSizeIdentifier:ADBannerContentSizeIdentifierPortrait];
}
[adView setFrame:CGRectOffset([adView frame], 0, -[self getBannerHeight:toInterfaceOrientation])];
}
}


And here's the method which gives the Banner height depending on device's current orientation


- (int)getBannerHeight:(UIDeviceOrientation)orientation {
if (UIInterfaceOrientationIsLandscape(orientation)) {
return 32;
} else {
return 50;
}
}


That's all required to make iAd support multiple orientation.

The best feature of this code is that it could be used for any iOS application (iPhone as well as iPad app) without any change.

Get the final code (and more polished one) from here.

You must now have a complete overview of integrating iAd into your next app. So get started!

Tuesday, June 7, 2011

Glimpse of iOS 5

Apple's WWDC 2011 is going on and it has showcased three exciting products in this year's conference - OS X Lion, iCloud & iOS 5. Lets have a quick look into some prominent new features added in iOS 5.

#1 Notifications
A single place which combined all of your notifcations. iPhone, iPad, iPod touch. Swipe finger down from the top.
Swiping across any notification on the lock screen puts you directly in that application.






#2 Newsstand
Newsstand is a unified place in the app store where all subscription magazines are placed; download any of them, and they're placed in the newsstand app. Also, each subscription app will do background downloads.




#3 Twitter
"We want to make it even easier for all our customers to use Twitter in our iOS products." - Steve Jobs.

Now single sign-on. Any app you download, it will just ask you for twitter credential permission. No need to re login.

We've included it in many of our apps - like camera and photos. You can tweet articles from safari, videos from Youtube, etc. It's all in there pretty deep.




#4 Safari
Reading List. easy way to read a story later. Syncs with all iOS devices and Safari on Mac and Windows. (like Instapaper)
Tab Browsing support... FINALLY




#5 Reminders
Apple states - "You can store dates... and, this is really cool, locations"
"You can set a reminder that says 'Remind me to call my wife when I leave the convention center today'"




#6 Camera
Use volume up button to take a photo now!
You can now pinch to zoom within camera
You can also now edit photos (cropping, rotating, red eye reduction) right on iPhone or iPad.




#7 Mail
Revamped completely with a new look. Even better, adding rich-text formatting. Control indentation. Draggable addresses. Support for flagging. Search entire message (entire contents).
New variant of the keyboard. Split the keyboard to type with thumbs.






#8 PC Free
Set up and activate device right on the device. And you're ready to go. It's that easy. Software updates are now over the air... no wires, no cables, no hassle.
No need to plug-in just to update. And they're now Delta updates. You don't download whole OS - just what has changed.




#9 Game Center
Adding photos. Compare yourself to friends with achievements points. See friend of friends. And get recommended friends. And game recommendations. Purchase and download right from Game Center.




#10 iMessage
Apple's own free messagging serving between all iOS devices. Text, photos, videos, contacts -- everything you've come to expect. and delivery receipts. option read receipts. typing indications.
works over 3G and WiFi. Everything sent encrypted.




"These are just TEN of the features in iOS 5. There are over 200!". Check them out here.

Saturday, June 4, 2011

International Dialing OUT codes

A while ago, I have posted a tutorial of how to launch your own application via a custom URL (link). While working with the option to provide calling functionality in our application, many developers come across the problem of handling international dialing codes.

As an example, consider the case where user has a number and wants to dial those number via the app. So far so good .. The problem is that say the number is in the UK then the number is prefixed with +44
So if user is in Tunisia and tapped the phone number the code would be:

00 44

If user is in the US it would be

011 44

Handling such international dialing isn't a big problem. The solution lies here:
Make sure you remove any brackets from phone number and prefix it with +. That's it

NSURL *phoneNumberURL = [NSURL URLWithString:[NSString stringWithFormat:@"tel:+%@, thePhoneNumber]];

[[UIApplication sharedApplication] openUrl:phoneNumberURL];


Remember it will only work if you have the dial code for the country in question already appended with the phone number e.g. 44 for the UK.

And if you don't know (or don't care to find a way) to remove brackets and blank spaces from the phone number, here is the method for it.
NSMutableString *phone = [[phone_number mutableCopy] autorelease];
[phone replaceOccurrencesOfString:@" "
withString:@""
options:NSLiteralSearch
range:NSMakeRange(0, [phone length])];
[phone replaceOccurrencesOfString:@"("
withString:@""
options:NSLiteralSearch
range:NSMakeRange(0, [phone length])];
[phone replaceOccurrencesOfString:@")"
withString:@""
options:NSLiteralSearch
range:NSMakeRange(0, [phone length])];

Tuesday, May 24, 2011

Code Snippet: Word Filter

In objective-C, you are not provide with any method to filter our any specific word from a string. Today we will see the implementation of a method which could be used for such filtering of words or replacing them with another word.
Our word filter will be pretty simple. We will create an NSDictionary where the keys will be swear words and the values will be their replacements. We will then enumerate over the keys of the dictionary and replace them in display text with their values.

To do so, just call the following method once you have a string entered inside the UITextField.
-(IBAction) filterWord:(id)sender {
UITextField * textField = (UITextField *) sender;

NSDictionary * filteredWords = [NSDictionary dictionaryWithObjectsAndKeys:
@"fecal",@"poop",
@"batato",@"butt",
@"Worst band ever",@"Nickelback",
@"hot dog",@"douche bag",nil];
NSString * newString = textField.text;

for(NSString * naughtyWord in filteredWords.allKeys) {
NSString * goodWord = [filteredWords objectForKey:naughtyWord];
NSLog(@"replacing %@ ",naughtyWord);
newString = [newString stringByReplacingOccurrencesOfString:naughtyWord
withString:goodWord];
}

NSLog(@"New string -> %s", newString);
}


This way you could replace all the occurrences of any word/phrase with another one.

Tuesday, March 1, 2011

Code Snippet: Character Counter

Many of us had a need to display an editable UITextView/UITextField in which only certain number of characters could be entered. It could be assumed something similar to Twitter clients as maximum length of any tweet cannot exceed by 140 characters limit. Today, we will implement this functionality in our application.

Step 1:
Let's define a UITextField where user will enter the text and a UITextView where the remaining characters will be displayed. Declare the following in your controller.h file
@interface RemainingCharacterViewController : UIViewController {
IBOutlet UITextView * remainingTextView;
}

@property (nonatomic, retain) IBOutlet UITextView * remainingTextView;

-(void)textFieldDidUpdate:(id)sender;


The above code is pretty straight forward. We first declare an IBOutlet for the UITextView that we will be updating. It will be used to show our characters remaining. Next, we declare an IBAction that will be called every time the user types a character in the UITextField. Now that our properties and actions have been set up, it’s time to create our interface. We won't need to declare the IBOutlet for UITextField which user will be editing as we could identify it by the (id)sender parameter.

Step 2:
Open up the Interface Builder and add a UITextView and connect the remainingTextView outlet to this element. Next, you will need to connect the textFieldDidUpdate IBOutlet to the Editing Changed action of the UITextField. Thus, whenever the text inside this textField is changed, it will fire the textFieldDidUpdate method.

Step 3:
textFieldDidUpdate is the method where we will put up all our code. Open the viewController.m file and add the following code;
@synthesize remainingTextView;

-(IBAction) textFieldDidUpdate:(id)sender {
UITextField * textField = (UITextField *) sender;
int maxChars = 140;
int charsLeft = maxChars - [textField.text length];

if(charsLeft == 0) {
UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"No more characters"
message:[NSString stringWithFormat:@"You have reached the character limit of %d.",maxChars]
delegate:nil
cancelButtonTitle:@"Ok"
otherButtonTitles:nil];
[alert show];
[alert release];
}

remainingTextView.text = [NSString stringWithFormat:@"%d characters remaining.",charsLeft];
}

- (void)viewDidUnload {
remainingTextView = nil;
}

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


First, we keep the maximum character limit to be 140 characters. Then we find the difference between this max. character limit and the characters entered in the textField. If this difference is 0 then we have reached our maximum limit, hence notify the user with a pretty alert message.
Now you are all done with the implementation of character counter.

Thursday, February 10, 2011

Sending In-App SMS

With the release of iPhone OS 3, a new feature to allow sending of in-app email was introduced. And now in iOS 4, a similar way of sending in-app SMS is introduced.

Prior to iOS 4, developers have to depend on:
[[UIApplication sharedApplication] openURL: @"sms:99999999"];


It has various limitations. First, it just closes your app (or sends it in background) and opens the default SMS application. Secondly, there was no way to specify the body content of the SMS. Then, it also restricts you to send the SMS to only one person.

However, with the new MessageUI SMS Controller, users can send SMS without quitting the app.

Step 1
Import the MessageUI Framework into your project and #import the header file into the “.h” file of your controller where you want to open the In-App SMS sheet.

Step 2
You would need a button handler IBAction where you want to send the SMS. If you don't have it, create a Button on your XIB file and write IBActions for it.

Step 3
Now connect the above button to this method to fire this action on "On Touch Up" event.
-(IBAction) sendInAppSMS:(id) sender
{
MFMessageComposeViewController *controller = [[[MFMessageComposeViewController alloc] init] autorelease];
if([MFMessageComposeViewController canSendText])
{
controller.body = @"Test message for in-app SMS";
controller.recipients = [NSArray arrayWithObjects:@"98765432", @"19283746", nil];
controller.messageComposeDelegate = self;
[self presentModalViewController:controller animated:YES];
}
}


The above block of code is self-explanatory. The most important part here is the line [MFMessageComposeViewController canSendText].
Before trying to send an in-app SMS you would always need to make sure that the device is capable to do it or not. For eample, iPhone OS 3 devices and iPod touch don't have the ability to send in-app SMS.
In this case, I have used a if condition to send the SMS. Practically speaking, you should enable/disable the button the user taps to send the sms based on this. You can add the code that does this in your viewDidLoad method.

Secondly, you have to set the messageComposeDelegate to self and not delegate. If you set the controller.delegate to self, you will not get the didFinishWithResult callback and the In-App SMS sheet will not close.

Step 4
Implement Delegate Callbacks.
In your header file, implement the callbacks, MFMessageComposeViewControllerDelegate and UINavigationControllerDelegate. If you don’t you will get a warning at the line,
controller.delegate = self;


You have to handle a callback method of MFMessageComposeViewControllerDelegate so as to dismiss the modal view controller.
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
{
switch (result) {
case MessageComposeResultCancelled:
NSLog(@"Cancelled");
break;
case MessageComposeResultFailed:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"IN-app SMS" message:@"Some Error occurred"
delegate:self cancelButtonTitle:@”OK” otherButtonTitles: nil];
[alert show];
[alert release];
break;
case MessageComposeResultSent:
NSLog(@"Message sent successfully");
break;
default:
break;
}

[self dismissModalViewControllerAnimated:YES];
}


That’s it. Your app should now be able to send SMS using the new Message UI sheet.

Note: As of today, the MFMessageComposeViewController doesn't support sending MMS. The controller.body is a NSString and setting a NSData pointer obviously crashes the app. Hopefully, one day, Apple will allow sending In-App MMS. Happy Coding till then...