Wednesday, 11 December 2013

Issues in iOS 7.0



                  FEW ISSUES WHICH I GOT IN MY APP WHILE UPDATING TO iOS 7.0



1.) To avoid a white line at start of separator in UITableView.

In iOS 7.0 tableView, Separator starts from where the text(Cell title and detail title) starts.
If you want to avoid it and want that your cell separator starts from initial.

Do code :

{
     CGRect separatorFrame;
     separatorFrame = CGRectMake(0, 59, 320, 1);  // set separator frame according to your table cell

     UIImageView *rowSaperatorImageView = [[UIImageView alloc]
                                          initWithFrame:separatorFrame];
     rowSaperatorImageView.image=[UIImage     imageNamed:kCELL_ROW_SEPARATOR_IMAGE_NAME];
   
     [cell.contentView addSubview:rowSaperatorImageView];
}

You need to add your own separator image to cell content view instead of doing this :

      UIColor *color = [UIColor colorWithPatternImage:[UIImage                                                           imageNamed:kCELL_ROW_SEPARATOR_IMAGE_NAME]];
     [tableView setSeparatorColor:color];



2.)Warning :  Implicit conversion from enumeration type 'enum UILineBreakMode' to different enumeration type 'NSLineBreakMode' (aka 'enum NSLineBreakMode')

Constant for setting line break mode got changes from iOS 7.
For this you will get warning.

Do the following code to avoid this warning :

#ifdef __IPHONE_6_0
# define LINE_BREAK_WORD_WRAP NSLineBreakByWordWrapping
#else
# define LINE_BREAK_WORD_WRAP UILineBreakModeWordWrap
#endif
    [[cell textLabel] setLineBreakMode:LINE_BREAK_WORD_WRAP];

Note : If you set it for iOS 6(that is, NSLineBreakByWordWrapping) it wont give any warning but when you run the app you will find that constant won't work for iOS 7.
And,if you set it for iOS 7(that is, NSLineBreakByWordWrap) it will give above warning.


3.) To avoid white background color on TableView Cell.

If you have set any background color for your tableView cell, running your Application on iOS 7 device you will find that your tableView cell's background will not get visible.
To resolve this issue you need to explicitly do clear color for your table View Cells.

Do implement this delegate method :

- (void)tableView:(UITableView *)tableView
  willDisplayCell:(UITableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath
{
    [cell setBackgroundColor:[UIColor clearColor]];
}


4.) Entire view moved up after picker is dismissed

One more issue which I got  while running my App is that dismissing picker view from any text editable field will move the whole view up .To resolve this we have coded this on all view controllers that has picker :

 - (void)navigationController:(UINavigationController *)navigationController
      willShowViewController:(UIViewController *)viewController
                    animated:(BOOL)animated
{
    if(kIOS_VERSION >= 7)
    {
        viewController.edgesForExtendedLayout = UIRectEdgeNone;
       
        [[UIApplication sharedApplication]
         setStatusBarStyle:UIStatusBarStyleLightContent];
    }
}

Note : Reason of this issue could be our custom Pickers or can be UINavigationController category.


5.) View Behind Status Bar

Another very common issue, entire view moves up behind status bar that means it will not leave 20px of status bar 


Do Code following on all view controller's viewDidLoad() that have this  issue :

    if (kIOS_VERSION >= 7)
    {
        self.edgesForExtendedLayout = UIRectEdgeNone;
    }


6.) View background not covering entire view

I also found very common issue in my App too. Views have white space at bottom that means the view background that I have set was not covering the whole view from top to bottom.

I did this code in View Controller's viewWillAppear() to resolve it :

    self.viewBackground.frame = self.view.bounds;

If you have set background frame to self.view.frame, change it to self.view.bounds



Please Note : If your App is supporting iOS < 7.0, do write this code specific to iOS 7 in your view controllers. If you do this for iOS it might be possible that your running code on iOS < 7 gets disturbed.


Happy Coding ..!!










Monday, 9 December 2013

JSON Parsing Framework and Integration


JSON Parsing Framework and Integration

Following are the parsers that can be used for JSON parsing:

1.)  iOS  Native parser : With the introduction of iOS 5, Apple introduced native support for parsing JSON with the NSJSON Serialization class. Therefore there’s really no need for third-party libraries (except really in terms of performance in some cases - or if you’re more comfortable with them). It is very simple to use:

1.  Firstly, retrieve your JSON data from your web-service as NSData
2.  Then, create your JSON dictionary with something like: ⁃ NSDictionary* json = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];
Reference Urls:
http://www.appcoda.com/fetch-parse-json-ios-programming-tutorial/
http://www.raywenderlich.com/5492
http://blog.safaribooksonline.com/2013/03/06/parsing-json-in-objective-c-using-nsjsonserialization/
https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSJSONSerialization_Class/Reference/Reference.html

2.)  Open Source Libraries:

Ø TouchJSON :  TouchJSON is an Objective-C based parser and generator for JSON encoded data. TouchJSON compiles for Mac OS X and iOS devices (currently iPhone, iPad and iPod Touch).
It is based on Jonathan Wight's CocoaJSON code: http://toxicsoftware.com/cocoajson/
Licence: Redistributions of source code must retain the copyright notice, this list of conditions and the disclaimer.
Reference Urls:
https://github.com/TouchCode/TouchJSON
https://github.com/twoism/iphone-json-example


Ø JSONKit : The fastest performing JSON parser for objective-c by a considerable margin However, there are a couple of limitations that come with it, these are:
Not ARC support.
JSON being parsed must be encoded as Unicode.
That being the case, it is very simple to set-up and use, follow these steps:
1.  Download the repository from the URL above.
2.  Add the JSONKit .h & .m files to your project.
3.  Add the appropriate #import statements to the classes that need it.
4.  You can create a dictionary with a line similar to:
o   NSDictionary *deserializedData = [jsonString objectFromJSONString]; And, if your dictionary contains an array, you can use a line like:
o   NSArray *resultList = [deserializedData objectForKey:@"ResultList"];
Licence : Redistributions of source code must retain the copyright notice, this list of conditions and the disclaimer.
Reference Urls:
https://github.com/johnezang/JSONKit
https://github.com/techtraits/jsonkit-example
https://github.com/JoistApp/JSONKit


ØYAJL: A JSON parser with an array of features:
Stream parsing, comments in JSON and better error messages.
Parse directly from NSString or NSData.
Generate JSON from default or custom types.
Properly handles large numeric types.
Document style parser.
Error by exception or out error.
It’s also very easy to install for iOS (Xcode 4):
1.  Add the YAJLiOS.framework to your project.
2.  In Build Phases, make sure its listed in Link Binary With Libraries, along with: CoreGraphics.framework * Foundation.framework * UIKit.framework 3. In Build Settings: * Under Framework Search Paths make sure the (parent) directory to YAJLiOS.framework is listed. * Under Other Linker Flags in your target, add -ObjC and –all load 4. Import with #import <YAJLiOS/YAJL.h>
YAJL is the next fastest library after native iOS library but it still took twice as long as the native library. It got some issues with ARC also. For apps that must provide legacy support, YAJL is the best choice.
Reference Urls:
http://kevsaidwhat.blogspot.in/2013/04/using-yajl-with-objective-c.html


Ø  JSON – framework : JSON (JavaScript Object Notation) is a light-weight data interchange format that's easy to read and write for humans and computers alike. This library implements chunk-based JSON parsing and generation in Objective-C.
It’s also very straight forward to install, simply go to https://github.com/stig/json-framework/, download the repository and follow these steps:
1.  In the Finder, navigate to the Classes folder (in the repository).
2.  Select all the files and drag-and-drop them into your Xcode project.
3.  Tick the Copy items into destination group's folder option.
4.  Use #import "SBJson.h" in your source files.
Licence : Redistributions of source code must retain the copyright notice, tis list of conditions and the disclaimer.
Reference Urls :
https://github.com/stig/json-framework
http://blog.zachwaugh.com/post/309924609/how-to-use-json-in-cocoaobjective-c


How to integrate iOS FrameWork For JSON Parsing?

1.) Create a new Xcode application following your own app architecture
2.) Integrate your Url in App that gives JSON data in response.I have used "@"http://api.kivaws.org/v1/loans/search.json?status=fundraising"
" that will have loan data .
3.) Create Connection and make request with your JSOn Url
4.) In Connection:DidFinishLoading,make a call to your parser class that will parse JSON data(This will be totally depend on you from where you make call to parser class,I made it from Manager ).

Parser Class will have the following code :(This is just an example which I used)

- (id)initWithData:(NSData *)responseData
{
   
    // 1.Now create a NSDictionary from the JSON data
        NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:nil];
       
    // 2.Create a new array to hold the loans
    NSMutableArray *loans = [[NSMutableArray alloc] init];

    //3. Get an array of dictionaries with the key "loans"
    NSArray* latestLoans = [jsonDictionary objectForKey:@"loans"];
   
        //4.Iterate through the array of dictionaries
        for(NSDictionary *dict in latestLoans)
        {
            //NSLog(@"Loan :%@",dict);
           
            // 4.1.Create a new loan object for each one and initialise it with information in the dictionary
            LoanEntity *loan = [[LoanEntity alloc] initWithJSONDictionary:dict];
           
            //4.2. Add the loan object to the array
            [loans addObject:loan];
           
        }
   
        // Return the array of loan objects
        return (id)loans;
}

The above code will give me individual loans as a dictionary in an Array of Dict("Loans") for JSON data that looks like this in Url:
"loans":[
              {"id":643323,
                "name":"Tabitha",
                "description":{"languages":["en"]},
                "status":"fundraising",
                "funded_amount":0,
                "basket_amount":0,
                "image":{"id":1487041,"template_id":1},
                "activity":"Fruits & Vegetables",
                "sector":"Food",
                "use":" to buy a variety of vegetables, potatoes and tomatoes for sale.",
                "location":{"country_code":"KE","country":"Kenya","town":"Msambweni","geo":       {"level":"country","pairs":"1 38","type":"point"}},
                "partner_id":164,
                "posted_date":"2013-12-09T10:50:02Z",
                "planned_expiration_date":"2014-02-07T10:50:02Z",
                "loan_amount":250,
                "borrower_count":1,
                "lender_count":0,
                "bonus_credit_eligibility":true},

In the above Code,

Loan Entity is an individual NSObject class that will retrieve individual loan data from dictionary and save them in Entity.
See below code this class contains:

// Init the object with information from a dictionary
- (id)initWithJSONDictionary:(NSDictionary *)jsonDictionary
{
    if(self = [self init]) {
        // Assign all properties with keyed values from the dictionary
         _name = [jsonDictionary objectForKey:@"name"];
        _sector = [jsonDictionary objectForKey:@"sector"];
        _use = [jsonDictionary objectForKey:@"use"];
        _activity = [jsonDictionary objectForKey:@"activity"];
        _funded_amount =[jsonDictionary objectForKey:@"funded_amount"];
        _loan_amount = [jsonDictionary objectForKey:@"loan_amount"];
        _country = [[jsonDictionary objectForKey:@"location"] objectForKey:@"country"];
        _status = [jsonDictionary objectForKey:@"status"];
    }  
    return self;
}

This Parsed data can now be used on your iOS App.

Note : I have given Loan example to show parsing.Retrieving data in "initWithJSONDictionary" will totally depend on your JSON data and structure they bind up in.

Happy Coding ...!!!!!

LinkedIn Integration In iOS App

LinkedIn Integration In iOS App

Step 1 : Register your App
First step that you need to follow is to register you application in linkedIn.For this you need to have a LinkedIn Account.Create one if you don't have and register your App
This unique key helps us identify your application and lets you make API calls. Once you've registered your LinkedIn app, you will be provided with an API Key and Secret Key. For the safety of your application please do not share your Secret Key.

Step 2 :Create Project
Next thing you need to do is to create a new Xcode App and integrate OAuth files in it.

Step 3 : Get an access token
Access token is unique to a user and an API Key. You need access tokens in order to make API calls to LinkedIn on behalf of the user who authorized your application. Follow the two steps below to get one:

a. Generate Authorization Code by redirecting user to LinkedIn's authorization dialog
https://www.linkedin.com/uas/oauth2/authorization?response_type=code
                                    &client_id=YOUR_API_KEY
                                     &scope=SCOPE
                                           &state=STATE
                                           &redirect_uri=YOUR_REDIRECT_URI
Make sure that you are using https for the request or you will get an error.
If the user authorizes your application they will be redirected to the redirect_uri that you specified in your request above along with a temporary authorization_code and the same state that you passed in the request above.
Upon successful authorization, the redirected URL should look like:
YOUR_REDIRECT_URI/?code=AUTHORIZATION_CODE&state=STATE

b.Request Access Token by exchanging the authorization_code for it
POST
https://www.linkedin.com/uas/oauth2/accessToken?grant_type=authorization_code
                                           &code=AUTHORIZATION_CODE
                                           &redirect_uri=YOUR_REDIRECT_URI
                                           &client_id=YOUR_API_KEY
                                           &client_secret=YOUR_SECRET_KEY


Step 4. Make the API calls
You can now use this access_token to make API calls on behalf of this user by appending "oauth2_access_token=access_token" at the end of the API call that you wish to make.
GET:
https://api.linkedin.com/v1/people/~?oauth2_access_token=AQXdSP_W41_UPs5ioT_t8HESyODB4FqbkJ8LrV_5mff4gPODzOYR
Access tokens have a life span of 60 days.


Please find some examples below of Get and Post that I have used in my Application :

1.) Get Profile Data:
For getting Profile you need to make a request to profile Api which looks like this:

- (void)profileApiCall
{
        NSURL *url = [NSURL URLWithString:@"http://api.linkedin.com/v1/people/~"];
        OAMutableURLRequest *request =
        [[OAMutableURLRequest alloc] initWithURL:url
                                        consumer:self.linkedInLoginViewController.consumer
                                           token:self.linkedInLoginViewController.accessToken
                                        callback:nil
                               signatureProvider:nil];
   
       
        [request setValue:@"json" forHTTPHeaderField:@"x-li-format"];
        OADataFetcher *fetcher = [[OADataFetcher alloc] init];
        [fetcher fetchDataWithRequest:request
                             delegate:self
                    didFinishSelector:@selector(profileApiCallResult:didFinish:)
                      didFailSelector:@selector(profileApiCallResult:didFail:)];

 
}

On successful response, FinishSelector will get called that have code something like:

- (void)profileApiCallResult:(OAServiceTicket *)ticket didFinish:(NSData *)data
{
    NSString *responseBody = [[NSString alloc] initWithData:data
                                                   encoding:NSUTF8StringEncoding];
   
    NSDictionary *profileData = [responseBody objectFromJSONString];
   
    if ((profileData)&&(!isImagePost))
    {
        self.name.text = [[NSString alloc] initWithFormat:@"%@ %@",
                     [profileData objectForKey:@"firstName"], [profileData objectForKey:@"lastName"]];
        self.headline.text = [profileData objectForKey:@"headline"];
    
    }
   
    // The next thing we want to do is call the network updates
    [self networkApiCall];
   
}

Here in code I am retrieving name and headline in label.

2.) Post Status:
Again for posting status url request is being made.Find the code below:
- (IBAction)postButton_TouchUp:(UIButton *)sender
{

//create url request   
NSURL *url = [NSURL URLWithString:@"http://api.linkedin.com/v1/people/~/shares"];
    OAMutableURLRequest *request =
    [[OAMutableURLRequest alloc] initWithURL:url
                                    consumer:self.linkedInLoginViewController.consumer
                                       token:self.linkedInLoginViewController.accessToken
                                    callback:nil
                           signatureProvider:nil];
   
//create dictionary with status that need to be posted
    NSDictionary *update = [[NSDictionary alloc] initWithObjectsAndKeys:
                            [[NSDictionary alloc]
                             initWithObjectsAndKeys:
                             @"anyone",@"code",nil], @"visibility",
                            self.statusText.text, @"comment", nil];
   
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
   
//update JSON String
    NSString *updateString = [update JSONString];
    NSLog(@"json string is %@",updateString);
   
  [request setHTTPBodyWithString:updateString];
[request setHTTPMethod:@"POST"];
   
//Call OAuth method to post status and call bak methods
    OADataFetcher *fetcher = [[OADataFetcher alloc] init];
    [fetcher fetchDataWithRequest:request
                         delegate:self
                didFinishSelector:@selector(postUpdateApiCallResult:didFinish:)
                  didFailSelector:@selector(postUpdateApiCallResult:didFail:)];
    }

3.) Get Recent Status:
On successful post,the next thing you need to do is to call the network update for getting recent post.For this you need to make request to networkApi somewhat like :

- (void)networkApiCall
{
    NSURL *url = [NSURL URLWithString:@"http://api.linkedin.com/v1/people/~/network/updates?scope=self&count=1&type=SHAR"];
    OAMutableURLRequest *request =
    [[OAMutableURLRequest alloc] initWithURL:url
                                    consumer:self.linkedInLoginViewController.consumer
                                       token:self.linkedInLoginViewController.accessToken
                                    callback:nil
                           signatureProvider:nil];
   
    [request setValue:@"json" forHTTPHeaderField:@"x-li-format"];
   
    OADataFetcher *fetcher = [[OADataFetcher alloc] init];
    [fetcher fetchDataWithRequest:request
                         delegate:self
                didFinishSelector:@selector(networkApiCallResult:didFinish:)
                  didFailSelector:@selector(networkApiCallResult:didFail:)];
   
}

Based on network Api response ,data will be fetched.On Success,you need to code like this this to get current post :

- (void)networkApiCallResult:(OAServiceTicket *)ticket didFinish:(NSData *)data
{
    NSString *responseBody = [[NSString alloc] initWithData:data
                                                   encoding:NSUTF8StringEncoding];
   
    NSDictionary *person = [[[[[responseBody objectFromJSONString]
                               objectForKey:@"values"]
                              objectAtIndex:0]
                             objectForKey:@"updateContent"]
                            objectForKey:@"person"];
   
   
    if ( [person objectForKey:@"currentShare"] )
    {
        self.status.text = [[person objectForKey:@"currentShare" ]
                            objectForKey:@"comment"];       
    }
}


This are some operations to play with linked In. You can try some others also.

Happy Coding….!!!

Creating static library & adding views to it


   Creating static library & adding views to it 

 

What is Static Library?

Static library are  custom users library which contain user specific classes bundled together same as iOS created frameworks. 


Why Use Static Libraries?

You might want to create a static library for different reasons. For example:
  • You want to bundle a number of classes that you and/or your colleagues in your team use regularly and share those easily around.
  • You want to be able to keep some common code centralized so you can easily add bugfixes or updates.
  • You’d like to share a library with a number of people, but not allow them to see your code.
  • You’d like to make a version snapshot of a library that develops over time.

 

 

How to create Static Libraries?

Following are the steps to create static library:
  • Create a new project and select static library( New->iOS->Frameworks & Library) in it you will get two files .h & .m file in it, either you can add your own methods in it or you can delete these files to add your own custom code in it.The methods written in it can be accessed in your application after integrating in it.  
  • You will find that in place of .app or ipa the static library file with extension .a is created in the products folder.Build your application & make sure you can locate your .a file {static library} in finder.
Note: The binary file create here might not work on simulator but when you check it on device it will work properly because of the difference in architecture of library & simulator. 
Question: why it happens???
By default, the library file will be built only for the current architecture. If you build for the simulator, the library will contain object code for the i386 architecture; and if you build for the device you’ll get code for the ARM architecture. You would need to build two versions of the library and pick which one to link as you change targets from simulator to device.
Solution:
Create a universal binary that contains the object code for both architectures.

Adding Views to Static Library

  • From the build settings of your library project click the “Add Target” button and add a target to the library project of type “Bundle”.
  • When the resources bundle target is added, default it will be set to  Mac OS X build target.Change its iOS target to be (probably “Latest iOS”).
  • In order to get resources to be put into the bundle all you have to do is add them to the “Copy Bundle Resources” build phase of the target.

    Your library will get created SUCCESSFULLY


How to create Universal binary?

  • Tap on File->New->Add target->OSX->Other->Aggregate -YourBinaryName - Finish.
  • Click on the project in the project navigator, then select the aggregate(Your binary Name) target. Switch to the Build Phases tab; this is where you will set up the actions that will run when the target is built.
  • Click on the Add Build Phase button, and select Add Run Script in the menu that pops up, as shown

 The code is not so complicated, this is how it goes line-by-line:  

UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# Step 1. Build Device and Simulator versions
xcodebuild -target TestLibrary ONLY_ACTIVE_ARCH=NO -configuration $ {CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="$ {BUILD_ROOT}"
xcodebuild -target TestLibrary -configuration ${CONFIGURATION} -sdk iphonesimulator -arch i386 BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"
# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# Step 2. Create universal binary file using lipo
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/lib${PROJECT_NAME}.a" "$ {BUILD_DIR}/${CONFIGURATION}-iphoneos/lib${PROJECT_NAME}.a" "${BUILD_DIR}/$ {CONFIGURATION}-iphonesimulator/lib${PROJECT_NAME}.a"
# Last touch. copy the header files. Just for convenience
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/include" "$ {UNIVERSAL_OUTPUTFOLDER}/"
  
  • Select the aggregate target UniversalLib in the Scheme Selection drop down, as so (unlike on the screenshot below instead of “iOS Device” you might see your device’s name):Press the Play button to build the target for the aggregate scheme. 
  • To see the result, use the Show in Finder option on the libTestLibrary.a product again. Switch to Finder’s column view to see the folders in the hierarchy and you’ll see a new folder called Debug-Universal (or Release-Universal if you built the Release version), which contains the Universal version of the library, as shown below:
Note: If you have made any changes to your storyboard/nib & you observe that your resource bundle is visible in red color as shown below(fig 1.12) or you are not able to locate it in finder, then you need to select your bundle resources from the edit scheme(fig 1.13) & build the bundle resources. 


How to use this Static library in App?

  • Create NewProject->TestProject(You Project Name).Add library resource files in the test project following the below folder structure
  1. Note: The typical convention is an include folder for the header files, and a lib folder for the library files (.a). This folder structure is only a convention; it’s not mandatory in any way. You don’t need to follow this structure or copy the files inside your project’s folder. In your own apps, you can have the header and library files in any location of your choice, as long as you set the proper directories when you configure the Xcode project later on.

 

Linking your static library to the XCode

  • Click on the project root node in the project navigator 
  • Select the TestProject target.
  • Select Build Settings.
  • Locate the Header Search Paths setting in the list. You can type “header search” in the search box to filter the big list of settings if necessary.
  • Double click on the Header Search Paths item, and a popover will appear. Click the + button, and enter the following:
$SOURCE_ROOT/include
 

Note: You will get a linker error when you try to import your library in your project, to get rid of it follow the below steps
(1) return to the build settings for the TestProject target
(2). Select the Build Phases tab
(3), and expand the Link Binary With Libraries section
(4). Finally, click the + button in that section
(5).click on the Add Other… button and locate the libTestLibrary.a library file in the lib subdirectory inside the project’s root folder
6. The final step is to add the -ObjC linker flag. Click on the Build Settings tab, and locate the Other linker Flags settings.



  • Now your library is SUCCESSFULLY linked with your project.
 
Happy Coding ...!!!!!