Friday, October 12, 2012

How to add Tap Event to UIImageView in XCode?


This blog post is about adding tap event to UIImageView dynamically.

Here we can use UITapGestureRecognizer class. Checkput the following code.

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleImageTap:)];
        tap.cancelsTouchesInView = YES;
        tap.numberOfTapsRequired = 1;

Above code is to identify single tap on image. If you want to do it for double tap just increase the count by one in numberOfTapsRequired.

Now let's create our image view.

NSString *urlString = @"";
NSURL *url = [NSURL URLWithString:urlString];
NSData *imageData = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:imageData];
UIView* mainServiceView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
UIImageView* imageView = [[UIImageView alloc] initWithImage:image];
imageView.userInteractionEnabled =TRUE;

Here note the last line imageView.userInteractionEnabled =TRUE; This is necessary else it will not respond to any gesture. Now add a gesture to image

[imagView addGestureRecognizer:tap];

Also add handleImageTap function to your view controller file.

- (void) handleImageTap:(UIGestureRecognizer *)gestureRecognizer {
    UIView* view = gestureRecognizer.view;
    //object of view which invoked this 

That's it now user can tap on your image.

Hope this helps you.

XCode- Send data and Close Popover from Master View Controller


Recently I was working on the app, where there was a button in toolbar which opens the Pop over with a table view. After selecting table cell, we need to pass some information to master view controller and close the Popover.

First you need a reference in your master view controller. Add following to your View controller header file.

@property (nonatomic, strong) UIPopoverController *myPopOver;

Synthesize it in .m file.

@implementation masterViewController

@synthesize myPopOver; 

Now add prepareForSegue method.

-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    if([segue.identifier isEqualToString:@"popOverSegue"]){
        UIStoryboardPopoverSegue *popoverSegue = (UIStoryboardPopoverSegue *)segue;
        self.myPopOver = popoverSegue.popoverController;
        [segue.destinationViewController setDelegate:self];

Also add one call call back method in your master view controller, which will be invoked when user selects a cell in pop over table view.


Now in pop over table view controller import your master view controller and set delegate as follow.

#import "masterViewController.h"

@interface myPopOverController : UITableViewController 
@property (nonatomic, weakmasterViewController* delegate;

Add following code to .m file

#import "myPopOverController.h"
#import "masterViewController.h"

@interface  myPopOverController ()<UITableViewDelegate>


@implementation iPadCategoriesPopOver
@synthesize categoriesArray,categoriesTableView,delegate;

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
        [[self delegatemyCallBack];

Check above code carefully, here we have delegate of type mater view controller and using it to invoke our call back function, Above code is executed when some one selects a row from table view. Now add following code to myCallBack function to close the pop over.

[self. myPopOver dismissPopoverAnimated:YES];

Also note that you can pass any parameter in callback if you want.

Hope this helps you.

Parse JSON data in Objective C (iOS 5)


Recently I was working on native iPAD app where we were having certain APIs which returns JSON data. This blog is about parsing JSON data in Objective C.

Following is the code to send request.

NSString *serviceURI = @"";
    serviceURI = [serviceURI stringByAppendingString:sort];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:[NSURL URLWithString:serviceURI]];
    [request setHTTPMethod:@"GET"];
    NSString *contentType = [NSString stringWithFormat:@"application/json"];
    [request addValue:contentType forHTTPHeaderField: @"Content-Type"];
    [request addValue:@"application/json" forHTTPHeaderField: @"Accept"];

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
    dispatch_async(queue, ^{
        NSURLResponse *response = nil;
        NSError *error = nil;
        NSData *receivedData = [NSURLConnection sendSynchronousRequest:request
            [SerenaNotifications showNetworkNotifcations];

Please note that here we are using GCD (grand central dispatch) I will explain this in other blog post. We will get our JSON data in receivedData variable. iOS 5 gives native classes for JSON serialization. Following code will go in else loop.

NSError *myError = nil;
            NSDictionary *res = [NSJSONSerialization JSONObjectWithData:receivedData options:NSJSONReadingMutableLeaves error:&myError];
            NSArray *resultArray = [res objectForKey:@"results"];

Normally in JSON request, results are added with results key. In your case if key is different, replace it in place of results.

This will give you all the results. If you have a single value in key you can access it as follow.

NSString* value = [object valueForKey:@"key"];

If you want to convert it to integer value. Use following code.

NSInteger intValue = [[object valueForKey:@"value"] intValue];

If you want to convert it to boolean value, use following code.

bool boolValue = [[object valueForKey:@"value"] boolValue];

Now you have all the results in resultArray. How to iterate through it and get a single object? Check the following code.

 NSEnumerator *e = [resultArray objectEnumerator];
            NSDictionary *object;
            while (object = [e nextObject]) {

Object is the NSDictionary object having your single result object. Again you can use objectForKey and valueForKey methods of NSDictionary class in case you have nested JSON structure.

Hope this post helps you.

iOS Pass Values to Native App from JavaScript in Webviews (Xcode)


Recently I was working on a native iOS application for iPAD. There are several web views in app which loads some sencha touch forms in web views. Web views are in modal window. Requirement was to notify native app to close web views upon certain user actions.  So how to do that?  Here is the trick

Add following to your modal view controller header file.


@interface iPadCatalogFormMoalController : UIViewController{
    IBOutlet UIWebView *webView;
@property (nonatomic, retain) UIWebView *webView;
@property (nonatomic) IBOutlet UIActivityIndicatorView  *webviewLoadingIndicator;

Now synthesize this properties in .m file

@synthesize webView,webviewLoadingIndicator;

Following code should be added in viewDidLoad method.

    NSString *urlAddress = @"";
    NSURL *url = [NSURL URLWithString:urlAddress];
    NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];

    webView.delegate= self;
    [self.webView loadRequest:requestObj];

Now add few delegate functions for web views.

-(void)webViewDidStartLoad:(UIWebView *)webView{
    [webviewLoadingIndicator startAnimating];

-(void)webViewDidFinishLoad:(UIWebView *)webView{
    [webviewLoadingIndicator stopAnimating];

- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
    NSURL *URL = [request URL]; 
    if ([[URL scheme] isEqualToString:@"closeWebView"]) {
        // parse the rest of the URL object and execute functions
        [self dismissModalViewControllerAnimated: YES];
        return NO;
    return YES;

Most important function for is the third one. This is called when web view url is assigned. Here we can check url schemes and do the necessary action. 

Now in your JS code when you want to notify native app. Just add following code.

window.location.href = 'closeWebView://param=value';

Here when you add this it will again fire shouldStartLoadWithRequest delegate function of web view and there we are checking the the URL scheme. 

Also you can pass ay number of params to native app if needed. Please note that this isn't the most efficient method. But it works in major scenarios.

Hope this helps you.