Wednesday, September 28, 2011

Weak link in iphone SDK


Well, there happened a case when I was using the latest iOS SDK  for the development purpose, and built an application which utilized the eventKit framework, and the framework used "eventKit" was a new addition to the framework list.

I used the eventKit on the fly and submitted to the appstore for the approval process, and as a matter the application was approved.

But, the case happened when the application was being downloaded and it used to crash at the app launch on the earlier iOS's.

Digging around the problem, I came to know about the weak link thing for a framework, and uploaded the updated build to app store.

The idea is that, If you are using a framework that is not available to all the devices that you have selected as target devices, make the framework as weak link.

This can be done as below:
* Select the project target > Right click > Get-Info.
* Go to general tab > Linked libraries.
* Select the framework and make it a weak link.



Also, keep in if you mark a framework as weak linked, be sure to check for its availability before using any of its functionally.

You can check for the existence of the class like below code sample:

Class theClass = (NSClassFromString(@"UILocalNotification"));
if(theClass){
// Class exists
}
else{
// Class does not exists
}

Saturday, September 24, 2011

List of Android emulator shortcuts

Android development is like cream, handling the emulator is on the other side.
Android emulator almost covers up the screen. In some cases you may not even see the 
'Home' button of the emulator screen, like on screens with resolution 1366 x 768.
Using android emulator shortcuts is the best way to get rid of such problems. Using shortcuts may
also increase the speed at which you work with the emulators.
Thus regardless of the screen resolution use of android emulator shortcuts is always encouraged.


Here is a list of android emulator shortcut keys:

Escape Back button
Home Home button
F2         PageUp Menu button
Shift-F2         PageDown Start button
F3         Call/Dial button
F4         Hangup/EndCall button
F5         Search button
F7         Power button
Ctrl-F3 Ctrl-KEYPAD_5 Camera button
Ctrl-F5 KEYPAD_PLUS Volume up button
Ctrl-F6 KEYPAD_MINUS Volume down button
KEYPAD_5         DPAD center
KEYPAD_4          DPAD left
KEYPAD_6          DPAD right

KEYPAD_8          DPAD up
KEYPAD_2          DPAD down
F8         Toggle cell network on/off
F9         Toggle code profiling (when -trace set)
Alt-ENTER         Toggle fullscreen mode
Ctrl-T Toggle trackball mode
Ctrl-F11, KEYPAD_7 Rotate screen orientation to previous or next layout
Ctrl-F12, KEYPAD_9 Rotate screen orientation to previous or next layout


And now, Start using the shortcuts...

Thursday, August 11, 2011

Change apple push notification view button text


We can not change the text of cancel button, but the view button text can be changed.
The payload dictionary has a field "action-loc-key", which takes the alternate text for view button.

The payload dictionary can look like,
{
    "aps": {
        "alert": {
            "body": "Bob wants to play poker",
            "action-loc-key": "PLAY"
        },
        "badge": 5,
        
    },
    "acme1": "bar",
    "acme2": [
        "bang",
        "whiz"
    ]
}

Here the text "Bob wants to play poker" will be the body of alert. and there will "cancel" and "PLAY". Here button text view will be replaced by "PLAY".

For more details on this visit apple reference document here.


Wednesday, August 10, 2011

method list in alphabetical order in xcode 4


There was an option in Xcode-3x in preference with a check box to enable or disable the alphabetical listing of methods, as seen in below picture:

(Xcode3.x option)



In Xcode-4x they have removed this option.
To list the methods alphabetically press and click on the level in the path menu, as in below picture:

(Xcode4.x, +click)


Personally I liked the new feature in Xcode4, as we can list the methods alphabetically or sequentially whenever we want unlike Xcode3 where we had to stick with the option selected in settings tab.

Tuesday, August 9, 2011

Displaying map in Facebook feed in iOS


Sharing images on Facebook feeds is desirable most of the times and can be accomplished by using the attachments in the params dictionary.

I went on a problem to post a Facebook feed that shares users current location as static map image.

The options available was to use a static image from google and use the url as value for 'picture' key in feeds parameters.
But, doing this didn't work. It didn't showed any image on the wall.

If you have a server that can cache and provide you the direct url of the static map image (generated by Microsoft Bing Map or Google Map), you can use that url for the feed purpose.

But, since I didn't had any, I had no option but to see for workarounds.

Searching for the solutions, certainly I found that Foursquare application does share the users location in feed. This foursquare proxy server url returns the static image of size 100x100 from Microsoft Bing Map. You can change the lat/long value in the url and get the desired map for your location.

It uses its proxy servers to generate and handle the map images.

The url for image is of below format,
https://foursquare.com/mapproxy/18.5163333/73.9299163/map.png

Its implementation code can look like below,


    NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                   kFacebookAppId, @"app_id",
                                   @"http://developers.facebook.com/docs/reference/dialogs/", @"link",
                                   @"https://foursquare.com/mapproxy/18.5163333/73.9299163/map.png", @"picture",
                                   @"Facebook Dialogs", @"name",
                                   @"Reference Documentation", @"caption",
                                   @"Dialogs provide a simple, consistent interface for apps to interact with users.", @"description",
                                   @"Facebook Dialogs are so easy!"@"message",
                                   nil];
    
    [facebook dialog:@"feed" andParams:params andDelegate:self];


Thanks and hope this helps.

Tuesday, August 2, 2011

How to disable Facebook Single Sign On (SSO)


Single Sign On is the desirable feature in almost all applications supporting Facebook.
However, if you tend to a scenario where you do not want this SSO feature, you can
omit the feature in a simple single step without removing any of your code during 
implementation of SSO.

To get away from SSO open Facebook.m file and replace method

- (void)authorize:(NSArray *)permissions
         delegate:(id<FBSessionDelegate>)delegate {

  [_permissions release];
  _permissions = [permissions retain];

  _sessionDelegate = delegate;

  [self authorizeWithFBAppAuth:YES safariAuth:YES];
}

with

- (void)authorize:(NSArray *)permissions
         delegate:(id<FBSessionDelegate>)delegate {

  [_permissions release];
  _permissions = [permissions retain];

  _sessionDelegate = delegate;
    [self authorizeWithFBAppAuth:NO safariAuth:NO];
}

In SSO implementation the method "authorizeWithFBAppAuth" takes parameter as "YES", which indicates Facebook to whether authorize from native Facebook application or from native Safari application.
Supplying the parameter  as "NO" signifies not to open any other application for user authentication. And the application shows its authentication dialogue within application.

Thats all you need to do, and the Facebook authentication dialogue opens within your application.

Tuesday, July 26, 2011

Difference between Copy and MutableCopy


The difference between 'copy' and 'mutableCopy' can be simply understood with polymorphism in Object Oriented Programming concepts.

We will take the example of Array in objective-C. MutableArray is the extension of NSArray class. Therefore, all the methods available in NSArray is available in NSMutableArray, but the additional methods present in NSMutableArray is not known to NSArray class.

Now moving ahead, the copy method on an NSArray will return an object of type NSArray(The array that can not be modified). And mutableCopy method will return an object of mutable type (The array that can be modified).

Now, there can below cases :

Case 1:

    NSArray *arr1=[NSArray arrayWithObjects:@"A",@"B",@"C", nil];
    NSArray *arr2=[arr1 copy];

    NSLog(@"arr1:%@",[arr1 description]);
    NSLog(@"arr2:%@",[arr2 description]);

In this case an NSArray object is returned and is received in an NSArray object.
So, the array received can not be modified.

Therefore, we will not be able to use below statement
[arr2 insertObject:@"Z" atIndex:0];


Case 2:

    NSArray *arr1=[NSArray arrayWithObjects:@"A",@"B",@"C", nil];
    NSArray *arr2=[arr1 mutableCopy];

    NSLog(@"arr1:%@",[arr1 description]);
    NSLog(@"arr2:%@",[arr2 description]);

In this case an NSMutableArray object is returned and is received in an NSArray object.
Since the receiver object is of type NSArray, it doesn't know the methods present in NSMutableArray, arr2 will not be able to use any of the methods of NSMutableArray.
That is, the method mutableArray will make no sense in this scenario.

So, we will not be able to use below statement
[arr2 insertObject:@"Z" atIndex:0];

Case 3:

    NSArray *arr1=[NSArray arrayWithObjects:@"A",@"B",@"C", nil];
    NSMutableArray *arr2=[arr1 copy];

    NSLog(@"arr1:%@",[arr1 description]);
    NSLog(@"arr2:%@",[arr2 description]);

In this case an NSArray object is returned and is received in an NSMutableArray type object. The receiver arr2 is now pointing to an object address that is of type NSArray. However arr2 has the additional methods than NSArray, it will not be able to use those methods coz the pointed object NSArray does not know the additional methods present in arr2(NSMutableArray).

Hence, we will not be able to use below statement
[arr2 insertObject:@"Z" atIndex:0];


Case 4:

    NSArray *arr1=[NSArray arrayWithObjects:@"A",@"B",@"C", nil];
    NSMutableArray *arr2=[arr1 mutableCopy];

    NSLog(@"arr1:%@",[arr1 description]);
    NSLog(@"arr2:%@",[arr2 description]);
    [arr2 insertObject:@"Z" atIndex:0];

In this scenario, the receiver(arr2) of type NSMutableArray receives an object of type NSMutableArray. Therefore, the receiver knows the additional methods of NSMutableArray as well as the object that is being pointed by receiver(arr2).

And finally below statement will work like charm,
[arr2 insertObject:@"Z" atIndex:0];

Log before insertion will be:
arr1:(
    A,
    B,
    C
)
arr2:(
    A,
    B,
    C
)
And log after insertion will be:
arr1:(
    A,
    B,
    C
)
arr2:(
    Z,
    A,
    B,
    C
)



Hope above description helped you.


Saturday, July 23, 2011

Random questions in iOS

1) How to disable UIWebView scrolling ?

Ans: UIWebView is derived from UIScrollView. Therefor we must be able to disable the scrolling of UIWebView.

Here is the working code:
UIScrollView *scrollView=[[webView subViewslastObject];
[scrollView setScrollingEnabled: NO];

2) How to check the iOS version of device ?

Ans: This is a very frequent scenario where you need to check which version of iOS the target device is running.

The very best solution that Apple recommends is,

  • if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
  • // Load resources for iOS 6.1 or earlier
  • } else {
  • // Load resources for iOS 7 or later
  • }

Tuesday, July 12, 2011

Blank status bar problem with MediaPlayer


Playing videos in iOS is like butter and nothing much on developer side.

iOS has provided MediaPlayer.framework to play videos either from resource or from a http url.

In a full screen application development, you might come across the problem that, after finish of the video play the status bar is hidden and the place for status bar is left blank (white).

Also, this problem may occur when you present the MoviePlayerViewController on current view and not on adding MoviePlayerViewController's view on the parent view
i.e,
[self presentMoviePlayerViewControllerAnimated:moviePlayerViewController];
not on doing
[self.view addSubview:[[moviePlayerViewController moviePlayer] view]];

Hey, and do not forget to test your code on iPad device, as you can find this problem only on device & works fine on simulator.


You will notice that the status bar is left blank when you click on "Done" button while video is being played. If the video ends after full video play everything goes right.

This white status bar may look like this:



To handle this problem, We add observers for MPMoviePlayer class notifications and all you need is to set the status bar hidden in the method implementation of 'MPMoviePlayerPlaybackDidFinishNotification' notification, as below:

We can add MoviePlayer notification observers as below:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_MPMoviePlayerPlaybackDidFinishNotification) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];

The implementation for 'MPMoviePlayerPlaybackDidFinishNotification' can be as below:

-(void)_MPMoviePlayerPlaybackDidFinishNotification{
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];

}

That is all we need to do.
You can download the working code here



Monday, June 27, 2011

Horizontal scroll using tableView


Very recently I happened to be in an efficiency problem with displaying large amount of images.
The problem was that I had to display more than 1000s images in horizontal in a way that user can scroll through in an easy and efficient way.

In this case the very first thing that may come in to mind is using a ScrollView with ImageViews added into them. In such a case we have to do a lot of book keepings and I didn't wanted that.

Certainly an idea came into my mind, why not to using TableView with the help of QuartzCore… as below.

Using QuartzCore we can rotate/transform the view. So, I added the table view on my view and rotated it by -90 degree (i.e, anti-clockwise) and made some adjustment in the view frame. Now, the table view is in horizontal mode.

Only thing is that image in cell is still not proper. So, change rotate the imageView also by +90 degree (i.e, clockwise). Hurrahhh!!! task complete..


Initially the screen looked like this,


Vertical table view



Final screen would look like this.

Horizontal table view 


Rotating the tableView:
m_tableView.layer.transform = CATransform3DRotate(CATransform3DIdentity,-1.57079633,0,0,1);
    m_tableView.frame=CGRectMake(0,200, 700,234);



Rotating the imageView:
imageView.layer.transform = CATransform3DRotate(CATransform3DIdentity,1.57079633,0,0,1);
        imageView.frame=CGRectMake(0,0,234,150);


Be sure to implement the lazy loading… for a better user experience.




Updated:
Finally got some time to create a sample for the stated purpose. The example will look like below. 


Custom Gallery




Here is the sample code that may help you go ahead. Be sure to run in Landscape mode... I am sorry that I didn't check for memory in this short time. Please make changes while using...








Wednesday, March 23, 2011

release Vs drain in autorelease pool

An autorelease pool stores objects that are sent a release or autorelease message and are deallocated when the autorelease pool itself is drained.

If a question like "what to use?  'drain' or 'release' ? comes in your mind, below is the simple resolve for your question.

release:
In a reference-counted environment, since an autorelease pool cannot be retained , this method causes the receiver to be deallocated. When an autorelease pool is deallocated, it sends a 'release' message to all its autoreleased objects. Also, In a garbage-collected environment, this method is a no no.

- (void)release

drain:
In a reference-counted environment, releases and pops the receiver; in a garbage-collected environment, triggers garbage collection if the memory allocated since the last collection is greater than the current threshold.

- (void)drain

Conclusion:
From the above brief discussion it is clear that, we should always use 'drain' over 'release' for an autorelease pool(be the Cocoa or Cocoa touch).



Wednesday, March 16, 2011

Determine if string is numeric only

 In Objective-C there is no in-built method which determines whether the given string is numeric only or is an alphanumeric, but has provided ways to do that.


The objective can be achieved using the NSCharacterSet class, which provides a set of characters.
Using below method we can identify the whether the string is numeric or alphanumeric.


- (void)testNumeric{
      NSString *result=@"2011";
      if([self isNumeric:result]){
// Numeric
        }else{
  // Alphanumeric
        }
}
- (BOOL)isNumeric:(NSString*)inputString{
        BOOL isValid=NO;
       NSCharacterSet *alphaNumbersSet = [NSCharacterSet decimalDigitCharacterSet];
       NSCharacterSet *stringSet = [NSCharacterSet characterSetWithCharactersInString:inputString];
       isValid = [alphaNumbersSet isSupersetOfSet:stringSet];
       return isValid;
}


decimalDigitCharacterSet is a character set containing the characters in the category of Decimal Numbers,i.e, the set with all numeric characters.


Method characterSetWithCharactersInString: returns the character set containing the characters in the given string, i.e, the set with characters '2','0','1','1' in our case.


Using the two sets, we determine whether all characters of inputString is contained in alphaNumbersSet.


Happy coding.

Wednesday, March 2, 2011

Auto Play youtube video in iPhone / iPad


Playing a youtube video in iOS sdk can be done in two ways:
1) Invoke the native youtube player in the device.
2) Open the youtube video link in a WebView.
3) Autoplay the youtube video using WebView .

Method 1:
This method utilizes the Apple's URLScheme to play youtube video by launching the youtube application on the device. This involves a simple call to the openURL method of UIApplication class as below:

NSURL *url=[NSURL URLWithString:@"http://www.youtube.com/v/IkvXcvb7rkg?f=user_favorites&app=youtube_gdata\"];
[[UIApplication sharedApplication] openURL:url];



This method may seem easy, but it's at the cost that the video will be played in other application
and your application will not be called even after the video playing is finished.
There is no other way to return to your application after video playing is done.

Method 2:
This method involved a little bit of tweak around the UIWebView control.
In this method a youtube embed code is constructed and is loaded in the WebView control in the application.
The WebView displays the video thumbnail and a play button over the thumbnail. As the user taps on the play
button the video is launched in QuickTime player and after the video playing is done, control is returned to the application.



                                                           (YouTube video in WebView with play button )

So, with a little bit of tweak we can retain the control in the application.

    NSString *htmlString =@"<html><head>"
        "<meta name = \"viewport\" content = \"initial-scale = 1.0, user-scalable = no, width = 212\"/></head>"
        "<body style=\"background:#FFFFF;margin-top:20px;margin-left:0px\">"
        "<div><object width=\"320\" height=\"240\">"
        "<param name=\"wmode\" value=\"transparent\"></param>"
        "<embed src=\"http://www.youtube.com/v/Hu684V2lB3Q?f=user_favorites&app=youtube_gdata\""
        "type=\"application/x-shockwave-flash\" wmode=\"transparent\" width=\"320\" height=\"240\"></embed>"
        "</object></div></body></html>";

    [webView loadHTMLString:htmlString baseURL:nil];



Method 3:
This method takes takes the 'Method 2' one step ahead by utilizing the delegate methods of WebView control
to auto play the video in QuickTime player as soon as the WebView loading is finished.



(Playing video in QuickTime player)


You need to assign the class as WebView delegate:

webView.delegate=self;

The idea is to find the play button on the WebView and send the button touch event to the control to play the video.

Complete code will look like this:

    NSString *htmlString =@"<html><head>"
        "<meta name = \"viewport\" content = \"initial-scale = 1.0, user-scalable = no, width = 212\"/></head>"
        "<body style=\"background:#FFFFF;margin-top:20px;margin-left:0px\">"
        "<div><object width=\"320\" height=\"240\">"
        "<param name=\"wmode\" value=\"transparent\"></param>"
        "<embed src=\"http://www.youtube.com/v/Hu684V2lB3Q?f=user_favorites&app=youtube_gdata\""
        "type=\"application/x-shockwave-flash\" wmode=\"transparent\" width=\"320\" height=\"240\"></embed>"
        "</object></div></body></html>";

    webView.delegate=self;
    [webView loadHTMLString:htmlString baseURL:nil];
   
- (void)webViewDidFinishLoad:(UIWebView *)_webView {
    UIButton *b = [self findButtonInView:_webView];
    [b sendActionsForControlEvents:UIControlEventTouchUpInside];
}

- (UIButton *)findButtonInView:(UIView *)view {
    UIButton *button = nil;
   
    if ([view isMemberOfClass:[UIButton class]]) {
        return (UIButton *)view;
    }
   
    if (view.subviews && [view.subviews count] > 0) {
        for (UIView *subview in view.subviews) {
            button = [self findButtonInView:subview];
            if (button) return button;
        }
    }
    return button;
}

I prefer Method 3 over all the methods but you choose the one that suits your need.
Happy coding...

Wednesday, February 23, 2011

iPad Launch screen image

With the usual requirement every iPad application is supposed to support all the orientations available, which a nice to have feature. In general the applications using a launch image for splash screen.

To supply an launch image, we use an image named as Default.png and is added to the resource folder of the application, and this image is loaded as launch image when the application is launched.
   
Since, we are using a single image for all orientations, there may be a case where the splash image me look stretched, blur, crisped (depending upon the image used).

This happens due to the different screen size of the device at different orientations. Landscape: 1024w x 748h  and Portrait: 768w x 1004h.
   
To get this thing to work we can create images with names and dimensions as mentioned below, and add them to the application resource folder (no code required).

Default-Portrait.png    768w x 1004h
Default-PortraitUpsideDown.png    768w x 1004h
Default-Landscape.png    1024w x 748h
Default-LandscapeLeft.png    1024w x 748h
Default-LandscapeRight.png    1024w x 748h
Default-PortraitUpsideDown.png    1024w x 748h


Clean the project by pressing Command+shift+k or from Build>Clean.
All set to go now, run the application.

NSSearchField return, arrow key press notification

In Cocoa development environment you might find NSSearchField difficult to trap the enter key event.
Also it becomes difficult to get the arrow key movements events.


In order to get these things to work, you need to do some simple stuffs with IBOutlet. You just need to connect your controller class with the delegate of NSSearchField.


In the controller class use below code to get the job done:

-(BOOL)control:(NSControl*)control textView:(NSTextView*)textView doCommandBySelector:(SEL)commandSelector {
    NSLog(@"doCommandBySelector");
    BOOL result = NO;
    if (commandSelector == @selector(insertNewline:)) {
        // enter key pressed
        result = YES;
    }
    else if(commandSelector == @selector(moveLeft:)) {
        // left arrow key pressed
        [textView moveLeft:nil];
        result = YES;
    }
    else if(commandSelector == @selector(moveRight:)) {
        // right arrow key pressed
        [textView moveRight:nil];
        result = YES;
    }
    else if(commandSelector == @selector(moveUp:)) {
        // up arrow key pressed
        result = YES;
    }
    else if(commandSelector == @selector(moveDown:)) {
        // down arrow key pressed
        result = YES;
    }
    return result;
}



Also, If you are interested in only in enter key event, set your controller class as the delegate of NSSearchField and implement the below method, which will be called when enter key is hit on the NSSearchField:
- (void)controlTextDidEndEditing:(NSNotification *)obj{
    NSLog(@"Enter key is hit");
}



* How to get the text out of NSSearchField:
The notification object(obj) in controlTextDidEndEditing method has the userInfo dictionary which contains the reference to the NSTextField in the NSSearchField control. Use below code to get the NSTextField object and the text in it.
NSTextView* textView = [[obj userInfo] objectForKey:@"NSFieldEditor"];
NSString *searchText=[textView string];





Let me know if something can be improved.

Monday, February 21, 2011

Foursquare

Where to register your application:
https://foursquare.com/oauth/

Sunday, February 20, 2011

Working with UILocalNotification in iOS

Back was the time before iPhone OS 3.0, APNS (apple push notification) was introduced. APN's are the means to send a remote notifications to a device connected to the internet.


With the increasing need of scheduling reminders at the device level, Local notification was introduced with the release iOS 4.0 . With the help of local notification, we can schedule a notification for any required date-time and the notification is handled by the device itself, no need to be connected to the
internet or a remote server.






UILocalNotification is the class behind the local notifications and the customization of the notification.


Local notification limitation:
Every application is allowed a maximum of 64 local notifications. iOS takes the upcoming 64 scheduled notifications and notifies for these notifications only, rest notifications are ignored.


1) How to registering Local notification:


    // Check for whether device supports local notification
    Class cls = NSClassFromString(@"UILocalNotification");
    if (cls != nil) {
       
        UILocalNotification *notif = [[cls alloc] init];
        notif.fireDate = [datePicker date];
        notif.timeZone = [NSTimeZone defaultTimeZone];
       
        notif.alertBody = @"Whooaa?";
        notif.alertAction = @"Show";    // alert button title (other than cancel)
        notif.soundName = UILocalNotificationDefaultSoundName; (default alert sound name, can be cutomized)
        notif.applicationIconBadgeNumber = 1;
       
        // Associate a dictionary to identify to gather the information about the notification
        NSDictionary *userDict = [NSDictionary dictionaryWithObject:@"Notification text"
                                                forKey:kRemindMeNotificationDataKey];
        notif.userInfo = userDict;
       
        [[UIApplication sharedApplication] scheduleLocalNotification:notif];
        [notif release];
    }



This will create a notification with the date selected in "datePicker" control.


In this case application name will be the title and "Whoaaa?" will be the body of the alert message, "Show" will be the title of the action button on alert (other than cancel button).


userInfo is the dictionary you will receive in the delegate method of the local notification. So, you can add your desired information for the notification to the dictionary while creating a notification.




2) How to handle notification delegate:


- This delegate method will be called If user tapped "Show Me" button and the application was running in background or was in active state.

- (void)application:(UIApplication *)application
        didReceiveLocalNotification:(UILocalNotification *)notification {
   
    application.applicationIconBadgeNumber = 0;
    NSString *reminderText = [notification.userInfo
                              objectForKey:kRemindMeNotificationDataKey];

    // Call to a method to handover the notification handling
    [viewController handleReminder:reminderText];
}





- This delegate method will be called If user tapped "Show Me" button and the application was not running in background.

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

    Class cls = NSClassFromString(@"UILocalNotification");
    if (cls) {
        UILocalNotification *notification = [launchOptions objectForKey:
                                UIApplicationLaunchOptionsLocalNotificationKey];
       
        if (notification) {
            NSString *reminderText = [notification.userInfo
                                      objectForKey:kRemindMeNotificationDataKey];

            // Call to a method to handover the notification handling
            [viewController handleReminder:reminderText];
        }
    }
   
    application.applicationIconBadgeNumber = 0;
   
    [window addSubview:viewController.view];
    [window makeKeyAndVisible];

    return YES;
}




3) How to cancel all local notification:

You can cancel the selected local notification if you have preserved the notification object like,


 [[UIApplication sharedApplication] cancelLocalNotifications:notif];


where "notif" is the notification object(saved/unsaved) .


and you can cancel all the local notifications by calling below,
 [[UIApplication sharedApplication] cancelAllLocalNotifications];




4) Custom alert sound:
To make your local notification make a custom sound, you will have to provide the name of the sound file with extension as .caf . This sound file must be in your application resource bundle.
Below code registers a custom notification sound called "alert.caf".
notif.soundName = @"alert.caf";


Note: Alert sound must have .caf extension.