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...

Saturday, November 20, 2010

Sorting NSMutableArray of NSDictionary

NSString * NAME = @"name";
NSString * ADDRESS = @"address";
NSString * FREQUENCY = @"frequency";
NSString * TYPE = @"type";

NSMutableArray * array = [NSMutableArray array];

NSDictionary * dict;

dict = [NSDictionary dictionaryWithObjectsAndKeys:
@"Alehandro", NAME, @"Sydney", ADDRESS,
[NSNumber numberWithInt:100], FREQUENCY,
@"T", TYPE, nil];
[array addObject:dict];

dict = [NSDictionary dictionaryWithObjectsAndKeys:
@"Xentro", NAME, @"Melbourne", ADDRESS,
[NSNumber numberWithInt:50], FREQUENCY,
@"X", TYPE, nil];
[array addObject:dict];

dict = [NSDictionary dictionaryWithObjectsAndKeys:
@"John", NAME, @"Perth", ADDRESS,
[NSNumber numberWithInt:75],
FREQUENCY, @"A", TYPE, nil];
[array addObject:dict];

dict = [NSDictionary dictionaryWithObjectsAndKeys:
@"Fjord", NAME, @"Brisbane", ADDRESS,
[NSNumber numberWithInt:20], FREQUENCY,
@"B", TYPE, nil];
[array addObject:dict];


Sorting part using descriptors with the Frequency field which is NSNumber:

NSSortDescriptor * frequencyDescriptor =
[[[NSSortDescriptor alloc] initWithKey:FREQUENCY
ascending:YES] autorelease];

id obj;
NSEnumerator * enumerator = [array objectEnumerator];
while ((obj = [enumerator nextObject])) NSLog(@"%@", obj);

NSArray * descriptors =
[NSArray arrayWithObjects:frequencyDescriptor, nil];
NSArray * sortedArray =
[array sortedArrayUsingDescriptors:descriptors];

NSLog(@"\nSorted Array ..");

enumerator = [sortedArray objectEnumerator];
while ((obj = [enumerator nextObject])) NSLog(@"%@", obj);


OUTPUT - sorted by Frequency field
2009-12-04 x[1] {address = Sydney; frequency = 100; name = Alehandro; type = T; }
x[1] {address = Melbourne; frequency = 50; name = Xentro; type = X; }
x[1] {address = Perth; frequency = 75; name = John; type = A; }
x[1] {address = Brisbane; frequency = 20; name = Fjord; type = B; }
Sorted Array ..
x[1] {address = Brisbane; frequency = 20; name = Fjord; type = B; }
x[1] {address = Melbourne; frequency = 50; name = Xentro; type = X; }
x[1] {address = Perth; frequency = 75; name = John; type = A; }
x[1] {address = Sydney; frequency = 100; name = Alehandro; type = T; }

Friday, November 5, 2010

Launching Your Own Application via a Custom URL Scheme

How to open other applications like phone dialer, SMS, Safari, Google Maps, iTunes or AppStore or any other iPhone application?

“openURL” is the API to use to achieve any of the above and many more.
Examples of some of the key applications that you can launch via URL are:
1. Launch the Browser
2. Launch Google Maps
3. Dial a Phone Number
4. Launch the SMS Application
5. Launch Apple Mail
6. Launch the AppStore

Launch the Browser
Here is a simple example of how to open Safari with a specific URL:
NSURL *url = [NSURL URLWithString:@"http://anuragsolanki.com"];
[[UIApplication sharedApplication] openURL:url];


Launch Google Maps
The URL string for launching Google Maps with a particular keyword follows this structure:
http://maps.google.com/maps?q=${QUERY_STRING}

The only trick to this is to ensure that the value for the ${QUERY_STRING} is properly URL encoded. Here is a quick example of how you would launch Google Maps for a specific address:
// Create your query ...
NSString* searchQuery = @"1 Infinite Loop, Cupertino, CA 95014";

// Be careful to always URL encode things like spaces and other symbols that aren't URL friendly
searchQuery = [addressText stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];

// Now create the URL string ...
NSString* urlString = [NSString stringWithFormat:@"http://maps.google.com/maps?q=%@", searchQuery];

// An the final magic ... openURL!
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlText]];


Dial a Phone Number (available in iPhone only)
You can use openURL: to dial a phone number. One advantage this has over other URLs that launch applications, is that the dialer will return control back to the application when the user hits the “End Call” button.
The URL scheme for this is:
tel://${PHONE_NUMBER}

Here is an example of how we would dial the number (800) 846-6802:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"tel://8008466802"]];


NOTE: Country code also needs to be including while dialing an international number

Launch the SMS Application (iPhone only)
It provides the ability to quickly setup the SMS client so that your users can quickly send a text message.

The format looks like this:
sms:${PHONENUMBER_OR_SHORTCODE}

Here is an example which shows to send an SMS. Note that an SMS url doesn't use the "//" syntax.
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"sms:55555"]];


Launch Apple Mail
Also very useful, is the ability to enable a user to quickly send an email by launching the email client in compose mode and the address already filled out. The format of this URI should be familiar to anyone that has done any work with HTML and looks like this:

mailto://${EMAIL_ADDRESS}

For example, here we are opening the email application and filling the “to:” address with anurag@apple.com :
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"mailto://anurag@apple.com"]];


Launching the AppStore
Initially, it is worth noting that you can launch the AppStore and have the "buy" page of a specific application appear. To do this, there is no special URL scheme. All you need to do is open up iTunes to the application you want to launch; right-click on the application icon at the top left of the page; and select Copy iTunes Store URL.

The URL will look something like this:
http://itunes.apple.com/in/app/mystockcomp/id358765855?mt=8

Launching the AppStore URL is exactly the same as you would launch the browser. Using the link above, here is an example of how we would launch the AppStore:
NSURL *appStoreUrl = [NSURL URLWithString:@"http://itunes.apple.com/in/app/mystockcomp/id358765855?mt=8"];
[[UIApplication sharedApplication] openURL:appStoreUrl];

Friday, October 29, 2010

Code Snippet: Prevent The iPhone From Sleeping

The code below will prevent the iPhone from dimming its screen and ultimately going to sleep. Use it wisely as you don’t want your application becoming notorious for being a battery hog

[UIApplication sharedApplication].idleTimerDisabled = YES;