Sunday, March 2, 2014

REST API and JSON


Hi all,

Almost every mobile app uses REST API where user needs to handle web requests.
The request could be GET or POST
The data to be carried could be JSON or XML or nay other.

So today we will be working on GET and POST requests using JSON.

Hope you find it useful and easy too. 
:)

Lets begin...

***********************How things work******************************

LoginViewController 
  •  Implements the Webservice Protocol.
  •  Calls method of webserviceManager to execute login webrequest
  •  Handles response

WebServiceManager
  • Creates JSON request dict / object.
  • Makes GET / POST request.
  • Creates NSURL Connections.
  • Receives the Response.
  • Using delegate makes a callback to the calling class that implemented the protocol method.
***************************************************************************

1) Create WebServiceManager.h
  •     @property (weak, nonatomic) id                               delegate;
  •     @property (strong, nonatomic) NSMutableData       *responseData;
  •     @property (strong, nonatomic) NSURLConnection *remoteConnection;
  •     @property (nonatomic) NSInteger                             statusCode;
  •    @property (strong, nonatomic) NSMutableData        *connectionData;
  •    @property (nonatomic) WebServiceTransactionType   transactionType;
  •    Create ENUMS
2) Create protocol in WebServiceManager.h.
    This protocol will be implemented by the class that implements it
     typedef NS_ENUM (NSInteger, WebServiceTransactionType)
    {
        WebServiceTransactionTypeUserLogin,
        WebServiceTransactionTypeUserLogout,
    };

    typedef NS_ENUM (NSInteger, NetworkOperationStatusCode)
   {
        NetworkOperationStatusCodeUnkown,
        NetworkOperationStatusCodeInProgress,
        NetworkOperationStatusCodeSuccess,
       NetworkOperationStatusCodeError
   };

     #pragma mark - Delegate Protocol

    @protocol WebServiceTransactionResponseDelegate <NSObject>

    @required

     - (void)assitant : (WebServicesManager *)assistant
           transaction : (WebServiceTransactionType)type
                   status : (NetworkOperationStatusCode)statusCode
         remoteData : (id)remoteData;

@end

3) WebServiceManager.m 

a) Execute login with POST request  & credentials in JSON format.
    Call this method from any class

- (void)authenticateLoginforUserName : (NSString*)userName
                                              password : (NSString*)password
                                     transactiontype : (WebServiceTransactionType)transaction_type
                                               delegate : (id)del
{
    self.delegate = del;  
    
    NSDictionary *requestDict = [[NSDictionary allocinitWithObjectsAndKeys:
                                 userName  ,@"userName",
                                 password   ,@"password",
                                 nil];
    
    NSString *url = [NSString stringWithFormat:@"%@%@",BASE_URL,LOGIN_REQUEST];

    [self createURLRequest : url 
                        requestDict : requestDict 
                 transactionType : transaction_type 
                             delegate : del];
}

b) Creating a generic method that handles GET / POST request

- (void)createURLRequest : (NSString*)url
                        requestDict : (NSDictionary*)requestDict
                transactionType : (WebServiceTransactionType)transaction_type
                            delegate : (id)del
{
    if (self.remoteConnection)
        [self.remoteConnection cancel];
    
    self.delegate = del;
    self.transactionType = transaction_type;
    
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:
                                                                                        [NSURL URLWithString : url]];

    [request setValue @"application/json" forHTTPHeaderField @"Content-Type"];
    
    if(requestDict != nil)
    {
        [request setHTTPMethod:@"POST"];

        NSData *jsonData = [NSJSONSerialization dataWithJSONObject : requestDict 
                                                                                                          options 0 
                                                                                                              error nil];
        [request setHTTPBody : jsonData];
    }
    else
        [request setHTTPMethod @"GET"];
    

    [request setTimeoutInterval 10];
    
    self.remoteConnection = [NSURLConnection connectionWithRequest : request
                                                                                                      delegate self];
    self.statusCode = -1;
    [self.remoteConnection start];
}


c) NSURLConnection Delegate methods


- (void)connection : (NSURLConnection *)connection 
                                        didFailWithError : (NSError *)error
{
        if([self.delegate respondsToSelector:@selector(assitant : transaction : status : remoteData : )])
        {
            [self.delegate assitant self
                            transaction self.transactionType
                                    status NetworkOperationStatusCodeError
                          remoteData nil];
        }
      
    if (connection == self.remoteConnection)
        self.remoteConnection = nil;
}


- (void)connection : (NSURLConnection *)connection 
                                    didReceiveResponse : (NSURLResponse *)response
{
    self.statusCode = [(NSHTTPURLResponse*) response statusCode];
    
    if (self.statusCode > 200) return;
    
    self.connectionData = nil;
}

- (void)connection : (NSURLConnection *)connection 
                                     didReceiveData : (NSData *)data
{
    if (self.statusCode > 200 || data == nil) return;
    
    if (self.connectionData ==  nil)
        self.connectionData = [NSMutableData dataWithData:data];
    else
        [self.connectionData appendData : data];
}


- (void)connectionDidFinishLoading : (NSURLConnection *)connection
{
    id temp;

    if (self.statusCode > 200)
    {
        temp = nil;
        
        if([self.delegate respondsToSelector @selector(assitant : transaction : status : remoteData : )])
        {
            [self.delegate assitant self
                            transaction self.transactionType
                                    status NetworkOperationStatusCodeError
                          remoteData nil];
        }
    }
    else
    {
        if (connection == self.remoteConnection)
            self.remoteConnection = nil;
        
        if(self.statusCode == 200)
        {
            if([self.delegate respondsToSelector:@selector(assitant : transaction : status : remoteData :)])
            {
               NSDictionary *parsedData = [Utils convertJSONDataToDictionary self.connectionData];
                
              // Check JSON Parsing in another blog of mine :  JSON Parsing Tutorial

                [self.delegate assitant self
                                transaction self.transactionType
                                        status NetworkOperationStatusCodeSuccess
                              remoteData : parsedData];
            }
        }
    }
}

4) Implementing the protocol in LoginViewController.h

 @interface LoginViewController : UIViewController              
                                                         <WebServiceTransactionResponseDelegate>

    @end

5) Calling WebServiceManager from LoginViewController.m

    WebServicesManager *webManager = [[WebServicesManager alloc] init];

    [webManager authenticateLoginforUserName : @"Swati"
                                                              password : @"password"
                                                     transactiontype WebServiceTransactionTypeUserLogin
                                                                delegate self];

6) Handling response in LoginViewController.m

-  (void) assitant : (WebServicesManager *)assistant
        transaction : (WebServiceTransactionType)type
                status : (NetworkOperationStatusCode)statusCode
      remoteData : (id)remoteData
{
    switch (type)
    {
        case WebServiceTransactionTypeUserLogin:
        {            
            if(statusCode == NetworkOperationStatusCodeError)
            {
                // FAILURE                
                return;
            }
          else
          {
                  // SUCCESS
           }
        }
            break;
        default:
            break;
    }
}

tada........

now try out yourself.....



Wednesday, February 12, 2014

Working with Database


Hi all,

Pretty sure that many of you have already worked on this.
An idea to frame things related to DB together.

Lets see how much this works!!!!


Ok Now lets proceed

1) Create Database

- (BOOL)createAppDatabase
{
    NSString *docsDir;
    NSArray *dirPaths;
    BOOL isSuccess = NO;
    
    dirPaths = NSSearchPathForDirectoriesInDomains
                                                 (NSDocumentDirectory, NSUserDomainMask, YES);
    
    docsDir = [dirPaths objectAtIndex:0];
    
    self.databasePath = [[NSString alloc] initWithString
           [docsDir stringByAppendingPathComponent: @"MyDatabase.db"]];
    
    NSFileManager *filemgr = [NSFileManager defaultManager];
    
    if ([filemgr fileExistsAtPath: databasePath ] == NO)
    {
              const char *dbpath = [databasePath UTF8String];
        
              if (sqlite3_open(dbpath, &database) == SQLITE_OK)
              {
                             isSuccess = YES;
                             sqlite3_close(database);
             }
             else
                             isSuccess = NO;
    }    
    return isSuccess;
}


2) Create Tables

- (BOOL)createTableWithSqlStatement:(NSString *)sqlStatement
{
    BOOL isSuccess = NO;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    
    if ([fileManager fileExistsAtPath:self.databasePath ]  ==  YES)
    {
        const char *dbpath = [self.databasePath UTF8String];

        if (sqlite3_open(dbpath, &database) == SQLITE_OK)
        {
            char *errMsg;            
            const char *sql_stmt = [sqlStatement UTF8String];
            if (sqlite3_exec(database, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
            {
                isSuccess = NO;
                NSLog(@"Failed to create table");
            }
            sqlite3_close(database);
            return  isSuccess;
        }
        else
       {
            isSuccess = NO;
            NSLog(@"Failed to open/create database");
        }
    }
    return isSuccess;
}

3) Fetch Data from Table

NSString *sqlStatement = [NSString stringWithFormat:@"SELECT * FROM Info 
                                                                                             where userId=='%d'",@"21"];

- (LoginModel*)fetchDataFromInfoTable:(NSString*)sqlStatement
{
    sqlite3_stmt *sql_smt;
    LoginModel *loginModel;
    
    if (sqlite3_open([self.databasePath UTF8String], &database) == SQLITE_OK)
    {
        if (sqlite3_prepare_v2(database, [sqlStatement UTF8String], -1, &sql_smt, nil
                          == SQLITE_OK)
        {
            loginModel = [[LoginModel alloc] init];
            while(sqlite3_step(sql_smt)==SQLITE_ROW)
            {
                const char *s;
                
                s=(char *)sqlite3_column_text(sql_smt, 0); // Here 0 is the 1st column

                if(s==NULL)
                    loginModel.userID=@"";
                else
                    loginModel.userID =[NSString stringWithUTF8String:s];
                
                s=(char *)sqlite3_column_text(sql_smt, 1); // Here 1 is the 2nd column

                if(s==NULL)
                    loginModel.userName=@"";
                else
                    loginModel.userName =[NSString stringWithUTF8String:s];
            }
        }
        sqlite3_finalize(sql_smt);
        sqlite3_close(database);
    }
    else
    {
        loginModel = nil;
        NSLog(@"Failed to open/create database");
    }
    return loginModel;
}

4) Execute Statements

- (BOOL)executeSqlStatement:(NSString*)sqlStatement
{
    sqlite3_stmt *sql_smt;
    BOOL isSuccess = NO;
    
    if (sqlite3_open([self.databasePath UTF8String], &database) == SQLITE_OK)
    {
        if (sqlite3_prepare_v2(database, [sqlStatement UTF8String], -1, &sql_smt, nil
                     ==  SQLITE_OK)
        {
            if (SQLITE_DONE!=sqlite3_step(statement))
            {
                sqlite3_close(database);
                isSuccess = NO;
            }
            else {
                NSLog(@"Success");
                isSuccess = YES;
                NSLog(@"%@",sqlStatement);
            }
        }
        sqlite3_finalize(sql_smt);
        sqlite3_close(database);
    }
    else
    {
        isSuccess = NO;
        NSLog(@"Failed to open/create database");
    }    
    return isSuccess;
}

5) Call executeSqlStatement 

    NSString *sqlStatement = [NSString stringWithFormat:@"INSERT INTO Info
          (userId , userName) VALUES (%d,'%@')",[userID intValue],userName];

   [self executeSqlStatement:sqlStatement];

  sqlStatement = [NSString stringWithFormat:@"UPDATE Info 
            Set userName =  '%@' where userID =  '%d' ",@"Swati",@"21"];
    
  [self executeSqlStatement:sqlStatement];

sqlStatement = [NSString stringWithFormat: @"DELETE FROM Info
                                                                                    WHERE userID ='%d'",@"21"];


Hey where is my database ???

Here is the path >> Admin >> Library >> Application Support >> iPhone Simulator >> Your chosen Version >> Applications >> Here you will see a list of all apps on Simulator >> choose yours >> Documents >> MyDatabase.db


How to view the contents ???

You can install a plugin in /firefox named Sqlite Manager, click and provide the location and here is the DB view.....

Wednesday, February 5, 2014

JSON Utilization in iOS


Hi

The time since Apple has provided JSONSerialisation things have became far more easier.

For my ease i have created 2 methods for JSON Conversion to-fro.

Hope someone finds it suitable too.


+ (NSString*)convertDictionaryToJSONString:(NSDictionary*)dict
{
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict
                                                                              options:NSJSONWritingPrettyPrinted
                                                                              error:nil];

    return [[NSString alloc] initWithData:jsonData 
                                                   encoding:NSUTF8StringEncoding];
}


+ (NSDictionary*)convertJSONDataToDictionary:(NSData*)data
{
    NSDictionary *parsedData = nil;
    parsedData = [NSJSONSerialization JSONObjectWithData:data
                                                                    options:NSJSONReadingMutableContainers
                                                                     error:nil];
    return parsedData; 

}

Tuesday, February 4, 2014

Save Image in Documents Directory


Hi all,

Yup i know its very basic for many but for some it may be useful ;)

//Get Array of paths :
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

//Get Documents Folder
NSString *documentsDirectory = [paths objectAtIndex:0]; 

//Create path of File, may be inside any directory
NSString *dataPath = [NSString stringWithFormat:@"%@/%@",documentsDirectory,currentElement.iD];
        
if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath])
{
//For Creating directory
            [[NSFileManager defaultManager] createDirectoryAtPath:dataPath 
                                                                withIntermediateDirectories:NO 
                                                                                                 attributes:nil 
                                                                                                          error:nil];
}
        
[self saveImage:image withFileName:currentElement.iD ofType:@"png" inDirectory:dataPath];


//Here is the called method definition


- (void) saveImage:(UIImage *)image 
        withFileName:(NSString *)imageName
                    ofType:(NSString *)extension
            inDirectory:(NSString *)directoryPath
{
    if ([[extension lowercaseString] isEqualToString:@"png"])
    {
        [UIImagePNGRepresentation(image) writeToFile:[directoryPath stringByAppendingPathComponent:[NSString                                                                                                                       stringWithFormat:@"%@.%@", imageName, @"png"]] 
                                                                                 options:NSAtomicWrite 
                                                                                      error:nil];
    }
    else if ([[extension lowercaseString] isEqualToString:@"jpg"] ||
                 [[extension lowercaseString] isEqualToString:@"jpeg"]) 
   {
        [UIImageJPEGRepresentation(image, 1.0) writeToFile:[directoryPath stringByAppendingPathComponent:                                                                                                     [NSString stringWithFormat:@"%@.%@", imageName, @"jpg"]] 
                                                                                          options:NSAtomicWrite
                                                                                               error:nil];
    }
    else
   {
        NSLog(@"Image Save Failed\nExtension: (%@) is not recognized, use (PNG/JPG)", extension);
    }
}


Hope it helps

Enjoy :)

        

Monday, February 3, 2014

Working with UIPopOverControllers


Hi, I have been using them since popover feature was introduced.

I would like to show a small sample for those whom popover fascinates..

Hope you all find it simplest and helpful to..

Lets start.....

1) Create a Simple View based Application as a start project.

I created like this : 



2) Add files namely  : 

PopOverViewController.h
PopOverViewController.m
PopOverViewController.xib

DataViewController.h
DataViewController.m
DataViewController.xib


3) Lets start with file PopOverViewController.xib

Add a UIButton on iPad UI showing text "Show PopOver"
Link this button with an IBAction named - (IBAction)showPopOver:(id)sender

4) Moving towards PopOverViewController.m

 Firstly create a private property like this : 



Secondly Perform Action on the IBAction as : 


Explanation : 
  • DataViewController is another controller with some UI components placed on its XIB.
  • The IBActions are handled accordingly.

  • We set the preferredContentSize property so that we can define the bounds of the popover being displayed.

  • self.popOverController is the private property we created in the .m file. 
  • This helps in presenting the DataController's view inside a popOver.

List of permitted Arrow Directions:


    UIPopoverArrowDirectionUp = 0,
    UIPopoverArrowDirectionDown = 1,
    UIPopoverArrowDirectionLeft =  2,
    UIPopoverArrowDirectionRight = 3,
    UIPopoverArrowDirectionAny = UIPopoverArrowDirectionUp
                                                          UIPopoverArrowDirectionDown
                                                          UIPopoverArrowDirectionLeft
                                                          UIPopoverArrowDirectionRight,
    UIPopoverArrowDirectionUnknown = NSUIntegerMax


5) Now moving towards DataViewController.h



6) UI Designing on DataViewController.xib

I added a label and 2 buttons which are associated with IBActions respectively.


7) Handling button clicks on DataViewController.m





Both the View Controllers are ready, now run the app and see the work..

One important thing for Orientation change



Whenever orientation change creates problem for popover presentation , remember to present popover again @ orientation did change selector.
      
        

Hope all are able to get help from this.
:)