Tuesday, July 26, 2011

View Controller Life Cycle

View Controllers have a “lifecycle” from loading to unloading, and we have to override its delegate methods according to our requirement.

1.The life cycle starts with alloc and initialization:
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)aBundle;
This is UIViewController’s designated initializer. The UIViewController tries to get its view from the specified .xib file called nibName.
If nibName is nil, it uses the name of the class as the nibName (MyViewController.xib).
The bundle allows you to specify one of a number of different .xib files (localization).
Passing nil for aBundle basically means “look in the Resources folder from Xcode.”
Initializing UIViewController with init is very common, it means nibName is nil & aBundle is nil.
Can I build a UIViewController’s view in code (i.e. w/o a .xib)? Yes. If no .xib is found using mechanism above, UIViewController will call - (void)loadView on itself. loadView’s implementation MUST set the view property in the UIViewController. Don’t implement loadView AND specify a .xib file (it’s undefined what this would mean).

2. viewDidLoad is called after the UIViewController is initialized.
- (void)viewDidLoad;
The viewDidLoad method is only called when the view is first loaded from the Nib file. If the view was already loaded and you push the view again it will not fire again. viewDidLoad is things you have to do once.Whenever I'm adding controls to a view that should appear together with the view, right away, I put it in the ViewDidLoad method. Basically this method is called whenever the view was loaded into memory. So for example, if my view is a form with 3 labels, I would add the labels here; the view will never exist without those forms.
3. Just before the view appears on screen, viewWillAppear is called.
- (void)viewWillAppear:(BOOL)animated;
Your view will probably only get “loaded” once, but it might appear and disappear a lot. So don’t put something in this method that really wants to be in viewDidLoad. Otherwise, you might be doing something over and over unnecessarily.
Use this to optimize performance by waiting until this method (i.e. just before view appears) to kick off an expensive operation (might have to put up a spinning “loading” icon though).
4. viewWillDisappear will be called when you will disappear off screen
- (void)viewWillDisappear:(BOOL)animated {
}
[superviewWillDisappear:animated]; //callthisinalltheviewWill/Didmethods // let’s be nice to the user and remember the scroll position they were at ... [selfrememberScrollPosition]; //we’llhavetoimplementthis // do some other clean up now that we’ve been removed from the screen
[self saveDataToPermanentStore];
// but be careful not to do anything time-consuming here, or app will be sluggish // maybe even kick off a thread to do what needs doing here
5. There are also “did” versions of both of these method:
- (void)viewDidAppear:(BOOL)animated; - (void)viewDidDisappear:(BOOL)animated;

6.  In low-memory situations, viewDidUnload is called. 
Be sure to release your outlets (or other data tied with the view and its subviews).

7. Now comes to device rotation
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)anOrientation {
return (anOrientation == UIInterfaceOrientationPortrait) || (anOrientation == UIInterfaceOrientationPortraitUpsideDown);
}
The default is to only allow UIInterfaceOrientationPortrait. This UIViewController’s view is allowed to flip around if the device is turned upside down. There is also UIInterfaceOrientationLandscapeLeft and Right. It is certainly nice to return YES from this method for as many as possible orientations.
But make sure that your view can draw itself “wide and not-tall” as well as “tall and not-wide” if you are going to return YES for the landscape orientations.

View Controller When rotation actually happens
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)anOrientation duration:(NSTimeInterval)seconds;
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)anOrientation; @property UIInterfaceOrientation interfaceOrientation;
The property will have the current orientation when each of the above is called. Stop doing anything expensive (e.g. an animation maybe?) in will and resume it in did.
The best way to handle rotations is to design your view to layout its subviews properly (i.e. set their frames) no matter what the aspect ratio of the view is.
Interface Builder can let you set “struts and springs” to help with layout flexibility. Or the UIView method layoutSubviews can be overridden to do this (outside this course’s scope).

Monday, July 25, 2011

iPhone/iPad Technical Interview Question(FAQ) with answers(Part 2)


Q11. What is atomic and nonatomic property attribute? 
A.
Both are same unless we use our setter and getter methods.
If we create our own setter and getter method, then atomic is useful in thread processing, but it is slow.
Nonatomic does not give guarantee on thread processing but it is fast.

Q12. What is the life cycle of view controller?
A.  Press here....
  
Q13. Difference between viewDidLoad, viewWillAppear, viewDidAppear and viewLoad?
A.
  • ViewDidLoad - The viewDidLoad method is only called when the view is first loaded from the Nib file. If the view was already loaded and you push the view again it will not fire again. viewDidLoad is things you have to do once.Whenever I'm adding controls to a view that should appear together with the view, right away, I put it in the ViewDidLoad method. Basically this method is called whenever the view was loaded into memory. So for example, if my view is a form with 3 labels, I would add the labels here; the view will never exist without those forms.
  • ViewWillAppear: I use ViewWillAppear usually just to update the data on the form. So, for the example above, I would use this to actually load the data from my domain into the form. Creation of UIViews is fairly expensive, and you should avoid as much as possible doing that on the ViewWillAppear method, becuase when this gets called, it means that the iPhone is already ready to show the UIView to the user, and anything heavy you do here will impact performance in a very visible manner (like animations being delayed, etc).
when you are loading things from a server, you also have to think about latency. If you pack all of your network communication into viewDidLoad or viewWillAppear, they will be executed before the user gets to see the view - possibly resulting a short freeze of your app. It may be good idea to first show the user an unpopulated view with an activity indicator of some sort. When you are done with your networking, which may take a second or two (or may even fail - who knows?), you can populate the view with your data. Good examples on how this could be done can be seen in various twitter clients. For example, when you view the author detail page in Twitterrific, the view only says "Loading..." until the network queries have completed.
  • ViewDidAppear: Finally, I use the ViewDidAppear to start off new threads to things that would take a long time to execute, like for example doing a webservice call to get extra data for the form above.The good thing is that because the view already exists and is being displayed to the user, you can show a nice "Waiting" message to the user while you get the data.
  • ViewLoad: loadView is the method in UIViewController that will actually load up the view and assign it to the "view" property. This is also the location that a subclass of UIViewController would override if you wanted to programatically set up the "view" property.
          I've found that often when I add init code to loadView, I end up with an infinite stack trace
          Don't read self.view in -loadView. Only set it, don't get it.
          The self.view property accessor calls -loadView if the view isn't currently loaded. There's your infinite recursion.


All The Best :)


Next(Part 3)….
                                                                                                           
                                                                                                     

Wednesday, July 20, 2011

QR Code reader/scanner for iphone app in objective c (source code) using ZBarSDK

Hey, I have googled a lot and found very less material for how to implement a QR code reader in our iPhone app. Here I have integrated all material and implemented in my project.
So here I am sharing my experience of implementing a QR code reader in our iPhone app using ZBarSDK.


Step 1: Download  ZBarSDK from here.


Step 2: Create a new project in xcode and name it as QRscanner.


Step 3: Integrate this  ZBarSDK folder in your xcode project by drag and drop on equal level of class folder in left panel in xcode.


Step 4: Add these 7 frameworks in Frameworks folder: 

  1. AudioToolbox.framework
  2. CoreMedia.framework
  3. QuartzCore.framework
  4. SystemConfiguration.framework
  5. libiconv.dylib
  6. AVFoundation.framework
  7. CoreVideo.framework

Step 5: Now Go To this link and generate some QR codes.
(to generate QR codes only add the text which you want to attach with QR code at the end of the link (e.g. I have written archana) and press enter, and right click to save this image.) 


Step 6: Add these generated QR code's image in iphone library.


Step 7: Now open QRscannerViewController.h in your xcode and write this code:


#import <UIKit/UIKit.h>
#import "ZBarSDK.h"

@interface QRscannerViewController : UIViewController <UIImagePickerControllerDelegate,ZBarReaderDelegate>{

IBOutlet UITextView *resultTextView;
}
@property (nonatomic, retain) IBOutlet UITextView *resultTextView;
@property (nonatomic, retain) UIImagePickerController *imgPicker;

-(IBAction)StartScan:(id) sender;

@end

Step 8: Now open QRscannerViewController.m in your xcode and write this code:





#import "QRscannerViewController.h"

@implementation QRscannerViewController

@synthesize imgPicker,resultTextView;

-(IBAction)StartScan:(id) sender
{
ZBarReaderViewController *reader = [ZBarReaderViewController new];
reader.readerDelegate = self;
reader.readerView.torchMode = 0;
ZBarImageScanner *scanner = reader.scanner;
// TODO: (optional) additional reader configuration here
// EXAMPLE: disable rarely used I2/5 to improve performance
[scanner setSymbology: ZBAR_I25
  config: ZBAR_CFG_ENABLE
  to: 0];
// present and release the controller
[self presentModalViewController: reader
animated: YES];
[reader release];
resultTextView.hidden=NO;
}

- (void) readerControllerDidFailToRead: (ZBarReaderController*) reader
                             withRetry: (BOOL) retry{
NSLog(@"the image picker failing to read");
}

- (void) imagePickerController: (UIImagePickerController*) reader didFinishPickingMediaWithInfo: (NSDictionary*) info
{
NSLog(@"the image picker is calling successfully %@",info);
// ADD: get the decode results
id<NSFastEnumeration> results = [info objectForKey: ZBarReaderControllerResults];
ZBarSymbol *symbol = nil;
NSString *hiddenData;
for(symbol in results)
hiddenData=[NSString stringWithString:symbol.data];
NSLog(@"the symbols  is the following %@",symbol.data);
// EXAMPLE: just grab the first barcode
//  break;
// EXAMPLE: do something useful with the barcode data
//resultText.text = symbol.data;
resultTextView.text=symbol.data;
NSLog(@"BARCODE= %@",symbol.data);
NSUserDefaults *storeData=[NSUserDefaults standardUserDefaults];
[storeData setObject:hiddenData forKey:@"CONSUMERID"];
NSLog(@"SYMBOL : %@",hiddenData);
resultTextView.text=hiddenData;
[reader dismissModalViewControllerAnimated: NO];
}


Step 9: Now open QRscannerViewController.xib and design it UI like this:






Step 10: Now make connection of above 2 objects(UITextView and UIButton) with IBOutlet resultTextView and IBAction StartScan.(Refer Step 7 of…) 


At last build and run this app.


How to run this app:


Press  "START SCAN" button, and as we are running our app in simulator you will get screen like this:






Now press and hold (alt key)+(left click), Photo Album (image gallery, photo library) will open.
Select any QR code image. It will take hardly 2-3 seconds for scanning and finally you will get home screen with scanned data associated with QR code image on text view.


Download source code from here.

Friday, July 15, 2011

XML parser in Objective-C for iPhone Projects (KissXML Parser)

There are many XML parsers for iPhone project :


But here I want to share my view on KissXML Parser, because I have implemented this in all my projects.

Getting started with  KissXML Parser :

1.       Download the API's package for KissXML Parser from here.

2.      Add all files of this package in your project.

3.      Add libxml2.dylib framework in your project.

4.      Do some setting in your project:
         Open application file under Target in left panel of xcode ->  Go To build tab -> set the values of "Other Linker Flags" and "Header Search Paths" as shown in below picture:

5.      Now suppose your xml is in this formate:


     and you want to parse this xml and save it data in an array.

6.   Now open your app.h file and write this code :
   
 7.   Now open your app.m file and write this code :



Note: Here, this xml is static for static data, you can create your own dynamic xml for dynamic data.


Next….

Thursday, July 14, 2011

Add Images To iPhone Simulator photo gallery

There are 2 ways to add image to iphone photo gallery:
  • Direct Method(drag and drop method).
  • Though coding.
Direct Method(drag and drop method):

Launch the simulator and go to this screen:

Drag the image which you want to add in gallery and drop on safari icon:


Click on image(anywhere inside the red rectangle in above image) and hold it:



You will get above 3 options: Save Image, Copy and Cancle.
Click on Save Image.
Now to see the saved image Go To below screen and click on photo:



 It will open the iPhone Album, select the 1st row of table, it will open all saved images.

Just double click on image to open.


Though coding : 
  1. Create a new project in xcode and name it as addImageInPhotoGallery.
  2. Add the image(Ref step 3 of .....) which you want to add in photo gallery in Resource folder of project.
  3. Open addImageInPhotoGallery.m, and write this code :

 - (void)viewDidLoad {
    
//suppose you have added photo.png in resource folder.
UIImage *sampleImage = [UIImage imageNamed:@"photo.png"];
    
UIImageWriteToSavedPhotosAlbum(sampleImage, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
   
 [super viewDidLoad];
}

- (void) image:(UIImage *) image didFinishSavingWithError:(NSError *) error contextInfo:(void *) contextInfo {
    UIAlertView *alert;
   
    // Unable to save the image 
    if (error)
        alert = [[UIAlertView alloc] initWithTitle:@"Error"
                                           message:@"Unable to save image to Photo Album."
                                          delegate:self cancelButtonTitle:@"Ok"
                                 otherButtonTitles:nil];
    else // All is well
        alert = [[UIAlertView alloc] initWithTitle:@"Success"
                                           message:@"Image saved to Photo Album."
                                          delegate:self cancelButtonTitle:@"Ok"
                                 otherButtonTitles:nil];
   
   
    [alert show];
    [alert release];
   
}


4. Now just build and run this code.
 You will not see any thing on simulator screen, Go to photo gallery, open the Album and you will see  that photo is added to photo gallery.