Thursday, May 8, 2014

AVSpeechSynthesizer example iOS7

There is no doubt that iOS has a very rich set of APIs and that richness is getting just better with each release of the OS. Blocks, ARC, GCD, Background Fetch etc are making the things a lot more easier and thus makes the app more intuitive in terms of performance and in terms of usability.

Since long people/developers have wanted to incorporate the voice interaction into their app and this made devs use other frameworks like OpenEar etc which is quite difficult to implement in real sense.

But, with the introduction of iOS 7, iOS has received a set of APIs to accomplish the text to voice functionality that too in different voices, based on the devices current locale or can be set through code. So, lets dive into it.

AVSpeechSynthesizer is the class under AVFoundation framework which is used to leverage the text to voice functionality. There are a couple of other classes involved as well to handle the things like speed, pitch, voice etc.

The text to voice can be implemented in simple four lines of code as below,


AVSpeechUtterance *utterence = [[AVSpeechUtterance allocinitWithString:@"Hi there."];
utterence.rate = 0.25f;
AVSpeechSynthesizer *synthesizer = [[AVSpeechSynthesizer allocinit];
[synthesizer speakUtterance:utterence];

And wollahh!! you are done.

But that is not all. 
Notice that we have created an AVSpeechUtterance object. Utterance basically defines the kind of speech you want including pitch, speed, voice, volume, pre and post delays between speeches.
Right now we have just defined an utterance with the speed(.25) we wanted, and we can add above properties to the speech as needed. The speed can vary from 0.0f (super slow) to 2.0f(super fast). Take a look at the class for more on it.

Also, one thing to be noted about AVSpeechSynthesizer is that if there is an ongoing speech and you ask the synthesizer to speak another text, this text will be added in a queue and will be spoken after the first speech is finished. So, in summary only one text/speech can be spoken at a time, rest are added in queue and dequeued on first come first serve (FCFS).

We have just made the Siri say few words in devices current locale voice. Now lets go ahead an change the voice on demand which it can be done as below, 

AVSpeechSynthesisVoice *voice = [AVSpeechSynthesisVoice voiceWithLanguage:@"zh-CN"];
[utterence setVoice:voice];

Notice that we have created a voice object and have set the voice to utterance. So, again its the utterance that has all the attributes of a speech. Also, in above, we have set the voice to Chinese but that doesn't mean that out English text will be converted to Chinese and Siri will speak in Chinese :).
It simply means that the voice will be like a English spoken by a Chinese person, in short voice is the accent of speech.

Voice strings can be like en-US (English- United States), ar-SA (Arabic- Saudi Arabia), fr-FR (French - France), zh-CN (Chinese - China) and many more.

AVSpeechSynthesizer does have a set of delegate methods in protocol AVSpeechSynthesizerDelegate, which keeps you posted on the current state of the speech, started, ended, cancelled, the word that will be spoken next etc. However all the delegate methods are optional. Below are the list of delegate methods,

- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didStartSpeechUtterance:(AVSpeechUtterance *)utterance;
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didFinishSpeechUtterance:(AVSpeechUtterance *)utterance;
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didPauseSpeechUtterance:(AVSpeechUtterance *)utterance;
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didContinueSpeechUtterance:(AVSpeechUtterance *)utterance;
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didCancelSpeechUtterance:(AVSpeechUtterance *)utterance;
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer willSpeakRangeOfSpeechString:(NSRange)characterRange utterance:(AVSpeechUtterance *)utterance;


Checkout the below video to see the AVSpeechSynthesizer in action in a demo app.

(Sorry that the sound is not there, as it is the screen recording,  but you can checkout the code an see for yourself)


The source code of this demo app can found at my Github page here.

Thanks for checking it out and happy coding :)



Friday, September 21, 2012

Display toolbar with keyboard in iOS

Keyboard is the most basic component that we use to interact with our application, input data to a field.
In most of the cases the buttons available on default keyboard is enough to fulfill the requirement but to make the application more interactive, intuitive we may tend to add some stuffs, controls over keyboard to aid our requirement in an elegant way.

For an example, consider a situation where user needs to input some description in a UITextView on a screen.
One way could be that you use the keyboard return/done tap event to dismiss the keyboard and that may sound okay, but what if user wanted to supply a line break (paragraph) in his description text. In this case, user has no way but to leave it as it is, henceforth leaving a user down.

Other way could be display a pair of buttons, "Cancel" "Apply" , in the top on the navigation bar of screen. This will again work, but from a users perspective, user needs to type some 100 characters on keyboard and move his thumb all the way up to reach those abandoned buttons. Again a no-no from user point of view.

Now, what if we add a toolbar right above the keyboard with those "Cancel", "Apply" button. Yeay!!!
Like this..Sounds good.

How to do it ???

There could be plenty of ways to show a toolbar above keyboard, like adding a custom view on self view, animating the view all the way from bottom to keyboard height with matching keyboard animation speed and again reversing the sequence when keyboard goes away. Annoying.. (Not to mention, I used to the same before coming to know the best solution).

Yes, the solution itself is in the UITextField and UITextView classes in the "inputAccessoryView" property.
It is an accessory view to display when the UITextField or UITextView becomes first responder. and this accessory view is displayed right above the keyboard, as we wanted for our problem.

For example we can create a custom view or a xib with toolbar and required buttons and set the inputAccessoryView as our view. The supplied view will be displayed above the keyboard.

It can be done as below,
UIView *accessoryView=[[[NSBundle mainBundle] loadNibNamed:@"AccessoryView" owner:self options:nil] lastObject];
    _textField.inputAccessoryView=accessoryView;
// _textField.inputView=accessoryView;
    accessoryView=nil;

Here, we are loading a custom xib "AccessoryView" and assigning it to the inputAccessoryView of the current responder textField. Thus the AccessoryView will be displayed above the keyboard with "Cancel" and "Apply" buttons.

To add, "inputView" property of UITextField and UITextView classes is the view to be displayed when they become the first responder.
For example, if in above code "inputAccessoryView" is replaced by "inputView", it will show "AccessoryView" only when the textField becomes first responder i.e, keyboard won't be there.

"inputAccessoryView" are useful in more cases like to display auto complete text, display addition characters, smileys etcs while user types. This may look elegant and usable in any way! Like this one,



More info on "inputAccessoryView" and "inputView" can be found here.

You can download an example code and checkout yourself.

Hope this helps.


Friday, May 25, 2012

Developer Essentials for MacOS Lion and XCode 4.3


In most of the cases as soon as you are done with the installation of MacOS Lion on your Mac, you may probably find below unexpected and unknown things.

So, here is a list of some unexpected situations that you may face and solution for it.

+ MacHD asks for password if you create or delete any folder MacOS Lion?
Solution: Navigate to "MacHD" > Right click on "MacHD" icon > Select "Get Info" > Scroll down to "Sharing & Permissions" and change the privilege to "Read & Write" for all. It will not ask for permission again.

+ How to Show/Unhide "Library" folder MacOS Lion or XCode 4.3?
Solution: Open Terminal from Utilities in Applications directory and run this command, "chflags nohidden ~/Library/", (without inverted commas).


+ Installed Application location in iPhone Simulator in MacOS Lion or XCode 4.3
Solution: Applications installed on iPhone simulator in XCode 4.3 resides at this location ".//Library/Application Support/iPhone Simulator/5.1/Applications/F8CFC9C3-D21C-4E08-920B-4F09256868F6/YourApplicationName.app". You can list all the applications and see their locations with below command "find ./ -name "YourApplicationName.app"" (without first and last inverted commas), and of course you can navigate directly to the application location using "Go To Folder" option in Finder > Go menu drop down.

Hope this helps!


Friday, March 2, 2012

Facebook wall post parameters

As you already know, Facebook iPhone app is the most downloaded app on iTunes AppStore and sharing contents on Facebook has become an usual requirement in iPhone apps.

To post a feed on user's wall, we need to provide a set of values in the form of dictionary.

To post a feed, we use below method of facebook class,
[facebook dialog: @"feed"
               andParams: params
             andDelegate: self];

Here, 'params' is the dictionary that contains set of values to be posted on Facebook users wall.


A typical feed may look like below,

-(void)postToFacebook{
    NSString *description = @"Nice app to see movie trailers!";
    
    NSString* propString = @"{\"Download it free: \":{\"href\":\"http://itunes.apple.com/us/app/itunes-movie-trailers/id471966214?mt=8\",\"text\":\"On iTunes AppStore\"}}";
    
    // post FB dialog
    NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                   @"iTunes Movie Trailers!", @"name",                             // Bold/blue name
                                   @"www.apple.com", @"caption",                                   // 1st line
                                   description, @"description",                                    // 2nd line
                                   @"http://itunes.apple.com/us/app/itunes-movie-trailers/id471966214?mt=8", @"link",
                                   @"http://www.blogcdn.com/www.tuaw.com/media/2011/10/imovietrailersapp.jpg", @"picture",
                                   propString, @"properties",
                                   nil];
    
    [facebook dialog: @"feed"
           andParams: params
         andDelegate: self];
}

Using this, the wall post on web page will look like below,
eg. wall post

Keep integrating Facebook in your application !!!



Friday, January 6, 2012

Custom tab bar in iphone


Tab bar in iPhone application is a desirable control when your application has multiple section and subsections. It takes viewControllers to create the tabs and display on the view/window. The default color of tab bar controller is black.

With introduction of iOS 5.0, we can change its tint color using,
tabBar.tintColor=[UIColor greenColor];

But, this is not enough to satisfy our taste buds. We are not at all going to create a custom tab bar, any inheritance etcs. We are just going to have some Image layers put onto the tab bar. With a little tweak, we can use whatever image we like in tab bar.
For this we will need a set of Image for every tab like,







Now, we will need to initialize our view controller in "didFinishLaunchingWithOptions" method as below,

FirstViewController *firstViewController=[[FirstViewController alloc] initWithNibName:@"FirstViewController" bundle:[NSBundle mainBundle]];
..
..
FifthViewController *fifthViewController=[[FifthViewController alloc] initWithNibName:@"FifthViewController" bundle:[NSBundle mainBundle]];


and add to tab bar controller,
    NSArray *arr=[NSArray arrayWithObjects:firstViewController,secondViewController,thirdViewController,fourthViewController,fifthViewController,nil];
    tabBarController=[[UITabBarController alloc] init];
    [tabBarController setViewControllers:arr];


Finally add this tab bar controller to the window,
[self.window addSubview:tabBarController.view];

Complete "didFinishLaunchingWithOptions" method in AppDelegate.m of application will typically look like below,
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    
    FirstViewController *firstViewController=[[FirstViewController alloc] initWithNibName:@"FirstViewController" bundle:[NSBundle mainBundle]];
    
    SecondViewController *secondViewController=[[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:[NSBundle mainBundle]];
    
    ThirdViewController *thirdViewController=[[ThirdViewController alloc] initWithNibName:@"ThirdViewController" bundle:[NSBundle mainBundle]];
    
    FourthViewController *fourthViewController=[[FourthViewController alloc] initWithNibName:@"FourthViewController" bundle:[NSBundle mainBundle]];
    
    FifthViewController *fifthViewController=[[FifthViewController alloc] initWithNibName:@"FifthViewController" bundle:[NSBundle mainBundle]];
    
    NSArray *arr=[NSArray arrayWithObjects:firstViewController,secondViewController,thirdViewController,fourthViewController,fifthViewController,nil];
    tabBarController=[[UITabBarController alloc] init];
    [tabBarController setViewControllers:arr];
    [self.window addSubview:tabBarController.view];
    
    [self.window makeKeyAndVisible];
    return YES;
}

Now, the idea is that, we can add an ImageView over the tab bar and update the image with tab change in viewWillAppear method of every viewController as below,
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
for(UIView *view in self.tabBarController.tabBar.subviews) {
if([view isKindOfClass:[UIImageView class]]) {
[view removeFromSuperview];
}
}
[self.tabBarController.tabBar insertSubview:[[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"1.png"]] autorelease] atIndex:1];
}

You can download the example code from here.

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