Wednesday, May 30, 2012

Localization in 5.0 - Simplest

Good Evening,

I have been working on localization and was moving around various samples.
Thought i should write one too....
May be it helps someone ;)

Trying to write a simpler one in just 5 steps......

Step : One

Create a new Project in Xcode. In our case its a "Single View Application"


Now save project as : 





Step : Two

Now before going to User Interface part lets add the localization files for different languages.
We will be using English (default) and French

Right click on the project name >> Add New File >> Resource >> Strings File and then do as shown :



Name this file as "Localizable.strings"


Step : Three

By default it accepts English so we need to add another file for French like this:

Click on the Localizable.string file and open "File Inspector"
GoTo Localization section
Click "+" symbol
You can see a list of Apple Languages like this :


Select French from above list . It appears in grey after selection.
Below Image shows how it looks after french gets added up in localization languages for the app.




And after addition you can see files here also:



Step : Four


Contents that we write in these localization file:






Step : Five


Now lets work on UI.
We will add four labels on the view of ViewController and display the contents on it that gets changed as we change the language.

Below image will show how the IBOutlets are connected.



Now whenever you change the language from settings you will see the change is reflected in the app.
The contents get changed :)

How the output appears:




Hope it helps :)

Enjoy coding...........






















Monday, May 21, 2012

Lazy Loading of Images in Table (iOS : 5.0)


Hello all,

I know many of us have successfully done this.
I have tried to show the working via images. Hope it helps all the beginners like me to learn more.

What you can get here:

1) How to start with Story-Boards
2) Url Encoding
3) Lazy loading of images


Here is a tutorial for all,

Step -1 : Open New Project in Xcode :






Step - 2 : Open MainStoryBoard.storyboard

Inside the View add a tableview and connect its DataSource and Delegate with the controller class.
You can also change the background color of the view to have a look like this : 





Step - 3 : Now Open your LazyLoadingViewController.h file and write :


@interface LazyLoadingViewController : UIViewController<UITableViewDelegate,UITableViewDataSource>
{
    IBOutlet UITableView            *tableView;
    NSArray                         *animals;
    NSArray                         *animalUrl;
    NSMutableDictionary             *imageDict;
}
@property(nonatomic,retain)UITableView              *tableView;
@property(nonatomic,retain)NSArray                  *animals;
@property(nonatomic,retain)NSArray                  *animalUrl;
@property(nonatomic,retain)NSMutableDictionary      *imageDict;

-(NSString *) URLEncodeString:(NSString *) str;
@end


Step - 4 : Now Open your LazyLoadingViewController.m file and write this : 

a) Synthesize all the properties that you created in .h class
b) Initialize your arrays and dictionary in ViewDidLoad.
       I have done like this : 

    imageDict = [[NSMutableDictionary alloc] initWithCapacity:4];
    animals = [NSArray arrayWithObjects:@"CAT",@"DOG",@"FOX",@"LION", nil];
    animalUrl = [NSArray arrayWithObjects:
         @"http://www.zastavki.com/pictures/1600x1200/2008/Animals_Cats_Small_cat_005241_.jpg",
         @"http://spadogbotanicals.com/wp-content/uploads/puppy1-300x225.jpg",
         @"http://www.nj.gov/dep/fgw/images/wildlife/fox_gl.jpg",
         @"http://www.mikesel.info/wp-content/uploads/2011/07/lion.jpg",nil];


c) Now add all table view methods : 


In our case the number of sections is only one but the rows depend on the total contents in the array we will use to display the contents in the table view


- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{
return [animals count];
}



d) For cell creation we want to display a default image in the image view till we get the image from server.In our case we have used this :


e) Cell creation is the most important part of the table view  that will display the contents from the web when they are available. This is done via dispatching a background thread that fetches the images in background.



- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *Identifier=@"Identifier";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:Identifier];
if(cell == nil)
{
cell = [self reuseTableViewCellWithIdentifier:Identifier withIndexPath:indexPath];
 cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.selectionStyle = UITableViewCellSelectionStyleNone
}
//configure cell
UIImageView *imgView= (UIImageView *)[cell.contentView viewWithTag:IMG_TAG];
if([imageDict  valueForKey:[NSString stringWithFormat:@"%i,%i", indexPath.row, indexPath.section]]==nil)
{
[NSThread detachNewThreadSelector:@selector(displayingSmallImage:) 
            toTarget:self withObject:indexPath];
}
else
{
imgView.image = [imageDict valueForKey:[NSString stringWithFormat:@"%i,%i",
                                          indexPath.row, indexPath.section]];
}
UILabel *lblName = (UILabel *)[cell.contentView viewWithTag:TITLE_TAG];
[lblName setText:[animals objectAtIndex:indexPath.row]];
return cell;
}


-(UITableViewCell *)reuseTableViewCellWithIdentifier:(NSString *)identifier withIndexPath:(NSIndexPath *)indexPath 
{
CGRect cellRectangle;
cellRectangle = CGRectMake(0.0, 0.0, 340, 180);
UITableViewCell *cell = [[UITableViewCell alloc]
                         initWithFrame:cellRectangle reuseIdentifier:identifier];

//here we create the image view and set its properties

UIImageView *img11;
cellRectangle = CGRectMake(15,18, 75, 70);
img11 = [[UIImageView alloc] initWithFrame:cellRectangle];
img11.tag = IMG_TAG;
img11.image = [UIImage imageNamed:@"base-image.png"] ;//acts as default image
img11.contentMode = UIViewContentModeScaleToFill;
[cell.contentView addSubview:img11];
//here we create the label and set its properties

UILabel *labelName;
cellRectangle = CGRectMake(150, 40, 200, 20);
labelName = [[UILabel alloc] initWithFrame:cellRectangle];
labelName.font =[UIFont fontWithName: @"Verdana"size:15.0f];
labelName.textColor = [UIColor blackColor];
labelName.autoresizingMask = UIViewAutoresizingFlexibleWidth;
labelName.tag = TITLE_TAG;
 [cell.contentView addSubview:labelName];

return cell;
}

Note : Remember to add the labels and the image view to the cell's content view.


f) Encode URL : This is done to create verbatim string for url to override the behavior of the escape sequences.

-(NSString *) URLEncodeString:(NSString *) str
{
    
    NSMutableString *tempStr = [NSMutableString stringWithString:str];
    [tempStr replaceOccurrencesOfString:@" " withString:@"+" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [tempStr length])];
    
    
    return [[NSString stringWithFormat:@"%@",tempStr] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
}

g) Cell creation is the most important part of the table view  that will display the contents from the web when they are available.If Image is available from the server we will display it else we will display the default image. You can see the test condition for this in BOLD.

After we get the image we save it in the dictionary and display the image on the image view in main thread i.e when the working of background thread is complete.


- (void) displayingSmallImage:(NSIndexPath *)indexPath
{
NSString *imageUrl = [animalUrl objectAtIndex:indexPath.row];
 imageUrl = [self URLEncodeString:imageUrl];
   
NSURL *url = [NSURL URLWithString:imageUrl];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
if(image == nil)
{
image = [UIImage imageWithContentsOfFile:[[[NSBundle mainBundle
               resourcePath] stringByAppendingPathComponent:@"base-image.png"]];
}
[self.imageDict setObject:image forKey:[NSString
                 stringWithFormat:@"%i,%i",indexPath.row,indexPath.section]];

[self performSelectorOnMainThread:@selector(imageReceived:) 
                        withObject:indexPath 
                     waitUntilDone:NO];
}



h) Here we display the image received and reload the particular row of the table for which we got the image.

- (void) imageReceived:(NSIndexPath *)indexPath

{
UIImage *image = (UIImage *)[imageDict objectForKey:
                             [NSString stringWithFormat:@"%i,%i",
                             indexPath.row,indexPath.section]];
UIImageView *imgs = (UIImageView *)[[tableView
                     cellForRowAtIndexPath:indexPath] viewWithTag:IMG_TAG];
[imgs setImage:image];
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                  withRowAnimation:UITableViewRowAnimationNone];
}




i) Don't forget to add this tag in your .m file : This is done so that the labels and image views when created we assign a tag to them so that while giving them their values the same can be accessed via tags.




#define IMG_TAG   1
#define TITLE_TAG 2

This is to be done after the properties are synthesized.

j) You will see output like this : 

  i) When the Application is launched.

ii) When only 2 icons were fetched and rest are in transit


iii) When all icons were fetched from the web server







Enjoy table view and iOS....... :)









Reading & Writing Images from iPhone's Documents Directory


Hello,

Many a times we face situations where we want to save some images or files in phones documents directory and then retrieve them when needed.

This option is usually chosen to avoid  fetching contents from web server
 instead saving & fetching contents locally on user's iPhone.

I have created two functions hope it helps somebody :)



-(void)saveImageInPhone:(NSData*)imageData withName:(NSString*)iconName
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory
                     NSUserDomainMask, YES);  


    //Get the docs directory
    NSString *documentsPath = [paths objectAtIndex:0]; 
    NSString *folderPath = [documentsPath
                            stringByAppendingPathComponent:@"IconImages"];
    
   if (![[NSFileManager defaultManager] fileExistsAtPath:folderPath])
        [[NSFileManager defaultManager] createDirectoryAtPath:folderPath 
          withIntermediateDirectories:NO attributes:nil error:nil];
    
    //Add the FileName to FilePath
    NSString *filePath = [folderPath stringByAppendingPathComponent:[iconName 
                         stringByAppendingFormat:@"%@",@".png"]];

    //Write the file to documents directory
    [imageData writeToFile:filePath atomically:YES]; 
}




-(UIImage*)retrieveImageFromPhone:(NSString*)fileName 
                    havingVersion:(NSString*)iconVersionString 
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory
                     NSUserDomainMask, YES);  
    
    //Get the docs directory
    NSString *documentsPath = [paths objectAtIndex:0]; 

    NSString *folderPath = [documentsPath
                           stringByAppendingPathComponent:@"IconImages"];

    NSString *filePath = [folderPath stringByAppendingPathComponent:
                          [fileName stringByAppendingFormat:
                            @"%@",@".png"]];

    if([[NSFileManager defaultManager] fileExistsAtPath:filePath])
        return [[UIImage alloc] initWithContentsOfFile:filePath];
    else 
        return nil;
}


How to view contents in Document Directory :


Finder  >> Library >> Application Support >> iPhone Simulator >> 
iOS version (5.1) >>  Applications >> Your Sample Application >> 
Documents >> IconImages >> myFirstImage.png.