Search code examples
iosobjective-ciphonexcodensurlconnection

Common API request handler


One of the request in my app looks like this :

-(void)login
{
    @try {
        NSString *str = [NSString stringWithFormat:TGURL_LOGIN];
        NSURL *url = [NSURL URLWithString:str];
        [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
        NSDictionary *requestData = @{@"---": ----,
                                      @"---": ----,
                                      @"OutResponse": [NSNumber numberWithInteger:0]};

        NSError *error;
        NSData *postData = [NSJSONSerialization dataWithJSONObject: requestData options:0 error:&error];

        NSString *postLength = [NSString stringWithFormat:@"%lu", (unsigned long)[postData length]];


        NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
        [request setURL:url];
        [request setHTTPMethod:@"POST"];
        [request setValue:@"application/json; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
        [request setValue:postLength forHTTPHeaderField:@"Content-Length"];
        [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
        [request setHTTPBody:postData];

        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
        __block int iSuccess = 0;

        [NSURLConnection
         sendAsynchronousRequest:request
         queue:queue
         completionHandler:^(NSURLResponse *response,
                             NSData *data,
                             NSError *error) {
             [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
             if ([data length] >0 && error == nil){
                 dispatch_async(dispatch_get_main_queue(), ^{
                     iSuccess = [self parseResponse:data];
                 });
                 dispatch_async(dispatch_get_main_queue(), ^{
                     if(iSuccess == 1)
                     {
                         [[NSUserDefaults standardUserDefaults] setObject:_email.text forKey:@"EmailText"];
                         [[NSUserDefaults standardUserDefaults] setObject:_password.text forKey:@"PasswordText"];
                         [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"User_Logged_In"];
                         [[NSUserDefaults standardUserDefaults]synchronize];

                         [TGProjectHandler saveCookiesToDefaults];
                         [self getUserID];
                     }
                     else if(iSuccess == 3)
                     {
                         [[NSUserDefaults standardUserDefaults] setObject:_email.text forKey:@"EmailText"];
                         [[NSUserDefaults standardUserDefaults] setObject:_password.text forKey:@"PasswordText"];
                         [[NSUserDefaults standardUserDefaults]synchronize];
                         [self.view endEditing:YES];
                         [TGProjectHandler saveCookiesToDefaults];
                         [TGProjectHandler removeLoadingIndicator];
                         [self performSegueWithIdentifier:@"ShowJoinGroup" sender:nil];
                     }
                     else
                     {
                         [[[UIAlertView alloc] initWithTitle: NSLocalizedString(@"Login_failed", nil)
                                                     message:NSLocalizedString(@"Invalid_credentials", nil)
                                                    delegate:nil
                                           cancelButtonTitle:@"OK"
                                           otherButtonTitles:nil] show];
                         [TGProjectHandler removeLoadingIndicator];
                         self.view.userInteractionEnabled = YES;
                     }
                 });
             }
             else if ([data length] == 0 && error == nil){
                 NSLog(@"Empty Response, not sure why?");
             }
             else if (error != nil){
                 NSLog(@"%@", error.description);
                 self.view.userInteractionEnabled = YES;
                 [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Login_failed", nil)
                                             message:error.localizedDescription
                                            delegate:nil
                                   cancelButtonTitle:@"OK"
                                   otherButtonTitles:nil] show];
                 [TGProjectHandler removeLoadingIndicator];
                 self.view.userInteractionEnabled = YES;
             }
         }];
    }
    @catch (NSException *exception) {
        [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
    }
}

This is just one of the service call. Have hundred's of them. Currently I am writing these in the controller itself (Bad approach, I know :)).
I am looking for a way where I can write all the request based code in a single class and access it everywhere.
For a moment I thought about creating Singleton. But I am not sure about creating Singleton for this.
Also thought about creating a protocol, but then finally I have to implement it in the controller.
What are the different patterns I can go for, so that I have a common class for the code I am repeating everywhere.


Solution

  • I have done like this, I have made a utility class

    this is my webservice.h file

    #import <Foundation/Foundation.h>
    
    typedef void (^webCompletionHandler)(NSData *data);
    typedef void (^webFailuerHandler)(NSError *error);
    
    
    @interface WebService : NSObject
    
    
    
    -(BOOL)callPostWebService:(NSString *)methodURL
                        param:(NSMutableDictionary *)params
            completionHandler:(webCompletionHandler)completion
              failuerHandler:(webFailuerHandler)failuer;
    
    
    -(BOOL)callgetWebService:(NSString *)methodURL
            completionHandler:(webCompletionHandler)completion
              failuerHandler:(webFailuerHandler)failuer;
    
    
    
    @end
    

    Here i have created two handlers one for completion and another for failure

    and these are the two methods for Post and Get

    -(void)getWebServiceCall:(NSString *)methodURL
                  parameters:(NSMutableDictionary *)parameters
           completionHandler:(webCompletionHandler)completion
              faliureHandler:(webFailureHandler)failure;
    
    -(void)postWebserviceCall:(NSString *)methodURL
                        param:(NSMutableDictionary *)params
            completionHandler:(webCompletionHandler)completion
               faliureHandler:(webFailureHandler)failure;
    

    This is the post method i have used

    -(void)callPostWebService:(NSString *)methodURL
                        param:(NSMutableDictionary *)params
            completionHandler:(webCompletionHandler)completion
              failuerHandler:(webFailuerHandler)failuer{
    
        if(![Utility isReachable]){
            DisplayLocalizedAlert(@"Network is not reachable");
            return;
        }
    
    
        NSLog(@"%@",methodURL);
        NSURLRequest *request = [self createRequest:params url:methodURL];
    
        NSURLSession *session = [NSURLSession sharedSession];
        NSURLSessionDataTask *dataTask =
        [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    
    
            dispatch_async(dispatch_get_main_queue(), ^{
                if(error != nil){
                    failuer(error);
                    return ;
                }
                else{
    
                    NSError* error;
                    NSDictionary* json = [NSJSONSerialization
                                          JSONObjectWithData:data
                                          options:kNilOptions 
                                          error:&error];
                    NSLog(@"json %@",json);
    
                    completion(data);
                }
            });
        }];
        [dataTask resume];
    
        return true;
    }
    

    Then where ever you need to call the webservice you can just call the post and gte method, whichever you require by passing the url and the parameters

    [webService postWebserviceCall:strURL param:dicInfo completionHandler:^(id data) {
    
        } faliureHandler:^(NSError *error) {
    
        }];
    

    In Swift:

    import UIKit
    import MobileCoreServices
    import CoreLocation
    
    
    typealias webCompletionHandler = (data : NSData) -> Void;
    typealias webFailuerHandler = (error : NSError,isCustomError : Bool) -> Void;
    
    
    let failureStatusCode = 0;
    let successStatusCode = 200;
    
    class WebServiceCall :NSObject {
    
        static var webService = WebServiceCall();
    
        override init() {
    
        }
    
    func callPostWebService(methodURL methodURL :String, param:NSDictionary, completionHandler:webCompletionHandler, failureHandler: webFailuerHandler) -> Bool
        {
            if (isInternetHasConnectivity() == false ) {
                let myError = NSError(domain: "Internet is not available", code: 1001, userInfo: nil)
                failureHandler(error: myError, isCustomError: true);
    //            AlertView.showMessageAlert(myError.domain)
                return false;
            }
    
            let request = self.createRequest(param, strURL: methodURL)
    
            let serviceTask = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: {
                data, response, error in
    
                dispatch_async(dispatch_get_main_queue(), { () -> Void in
    
                    if(error != nil){
    
                        failureHandler(error: error!, isCustomError: false);
                    }
                    else{
    
                        let response = Utilities.parseData(data!)
                        let status = response.objectForKey("status") as! Int;
    
                        if(status == successStatusCode){
                            completionHandler(data: data!)
                        }
                        else {
                            let msg = response.objectForKey("message") as! String
                            let error = NSError(domain: msg, code: Int(status), userInfo: nil);
                            failureHandler(error: error, isCustomError: true);
                        }
    
                    }
    
                })
            })
            serviceTask.resume();
    
            return true;
        }
    }