Thursday, February 14, 2013

Load Image Asynchronously in iOS

This post describes how to load an image from a remote server asynchronously in iOS, and from this post it even shows how to subclass UIImageView.

Whenever our application communicates with a server for data we usually use asynchronous calls to server from client side,so as to avoid blocking or so as to maintain thread safety, suppose say we are fetching an image from a url since we are making an asynchronous call from client side and since it is asynchronous call we can't make sure that when exactly we will get response so till that time we need to show some default image to user and once you get the actual image refresh the UIImageView with this image.

Here LoadImageAsynchronousSample demo app available to download

Algorithm:
Step 1: Subclass UIImageView and add a method to this class to load image asynchronously.
Step 2: Add a placeholder default image to this imageview initially, until you get actual image from service(url).

Step 3: Create an object of NSURLRequest so as to invoke asynchronous service call and implement NSURLConnection Methods delegate methods so as to handle response.
Step 4: Once you get response successfully from service just load that image(data) to your imageview.

LoadImageAsynchronously.h file is as below,

#import <UIKit/UIKit.h>
@interface LoadImageAsynchronously : UIImageView{
    NSURLConnection *connection;
    NSMutableData *data;
}
- (void)loadImageAsyncFromURL:(NSURL *)url placeholderImage:(UIImage *)placeholderImg; //method to load image asynchronously
@end

loadImageAsyncFromURL method you need to call from your class file where ever you want to load an image from a url, this method accepts 2 paramaters one is your image url from where you want to load another is placeholderImg which is to fill your image view with some local default image from your project bundle initially until and unless you get the actual image from your image url.

LoadImageAsynchronously.m file is as below,


#import "LoadImageAsynchronously.h"
@implementation LoadImageAsynchronously

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
    }
    return self;
}

#pragma mark - LoadImageAsyncFromURL Method
- (void)loadImageAsyncFromURL:(NSURL *)url placeholderImage:(UIImage *)placeholderImg{
    if(placeholderImg)
    {
        self.image=placeholderImg; //placeholderImg is a local image inside project bundle

    }
    
    NSURLRequest *request=[[NSURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:90.0];
    if(connection)
    {
        [connection cancel];
        connection=nil;
        data=nil;
    }
    connection=[[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];

}

#pragma mark - NSURLConnection Methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
     [data setLength:0];
}

- (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)incrementalData 
{
    if (data == nil)
        data = [[NSMutableData alloc] init];
    [data appendData:incrementalData];
    
}

- (void)connectionDidFinishLoading:(NSURLConnection *)theConnection
{
    UIImage *image=[UIImage imageWithData:data]; //image data from service(url)
    if(image){
        self.image=image;
    }
    data=nil;//so as to flush any cache data
    connection=nil;//so as to flush any cache data
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
      NSLog(@"Connection failed: %@", [error description]);
}

and finally in your calling class just import LoadImageAsynchronously.h file and create an object of LoadImageAsynchronously class as below,

#import <UIKit/UIKit.h>
#import "LoadImageAsynchronously.h"
@interface ViewController : UIViewController
{
    LoadImageAsynchronously *myImageView;
}
@end

finally pass your image url and call loadImageAsyncFromURL method of LoadImageAsynchronously class as below,


#import "ViewController.h"

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    NSString *imageURL = @"http://www.gstatic.com/webp/gallery/1.jpg";//image url
    UIImage *defaultPlaceholderImg = [UIImage imageNamed:@"default_image.jpeg"];//from local bundle
    myImageView=[[LoadImageAsynchronously alloc] initWithFrame:CGRectMake(20.0, 20.0, 200.0, 200.0)];
    myImageView.contentMode=UIViewContentModeScaleAspectFill;
    myImageView.clipsToBounds=true;
    NSURL *url = [NSURL URLWithString:imageURL];
    [myImageView loadImageAsyncFromURL:url placeholderImage:defaultPlaceholderImg];  //UIImageView subclass method
    [self.view addSubview:myImageView];
}

@end

and thats it, hope you enjoyed the post, any pros or cons or suggestions is appreciated and accepted in advance, thank you,,,, :-)




Wednesday, January 2, 2013

Class and Objects in OOP Language


This post is specifically for a newbie for an object oriented programming(OOP), this is about what is a class and object in an OOP Language along with an example,

A class is a definition of an object.Its a combination of data representation(variables) and method declaration.The data and methods within a class are called members of class.
A Class is a type just like a int.

Object is an instance of a class. or we can say an object is just a variable of a class.

say for ex:
1)  int a; // here "int" is a type, "a" is a variable of type int 
so w.r.t above example int specifies a class and 'a' specifies a Object of a class int.

2) A real world example for class and objects 
Consider species birds, under birds species n number of animals will comes all those are objects of class birds.
say, Birds - Class
sparrow,ostrich,parrots,penguins etc etc are objects of class Birds 

Now we can come to a conclusion that an object is a real world entity which has its own characteristics,and originated from a type of class.

A class definition starts with the keyword class followed by the class name; and the class body, enclosed by a pair of curly braces. A class definition must be followed either by a semicolon or a list of declarations.

example:-
class Birds
{
public:
float age;
float weight;  
};

int main()
{
Birds *parrot;  //parrot of Class Birds
Birds *penguin;  //penguin of Class Birds

parrot.age = 3;
parrot.weight = 5;
penguin.age = 8;
penguin.weight = 12;

cout << "parrot is an object of class Birds, and its age is"<<parrot.age<<"years old and weight is"<<parrot.weight <<"kgs";
cout << "penguin is an object of class Birds, and its age is"<<penguin.age<<"years old and weight is"<<penguin.weight <<"Kgs";

return 0;
}

The output of the above example program is as below:
parrot is an object of class Birds, and its age is 3 years old and weight is 5 kgs.
penguin is an object of class Birds, and its age is 8 years old and weight is 12 kgs.

the properties of an object can be accessed by the help of dot(.) operator as shown in above example like parrot.age

Hope you guys enjoyed the post,any comments or suggestions is acceptable.

Wednesday, December 26, 2012

AHSStarRating for iOS


AHSStarRating for iOS

iOS star Rating with a different logic :

Hi friends in this blog post i'm going to explain you that how to create a rating control(say, 5 star rating) by the help of touch events. Below is a snapshot of AHSStarRating,


From this logic you can able to rate even fractions & no need of n number of star images just a single image as below is sufficient.


pros:
1. Since we need only 1 image, bundle size will be reduced.
2. You can rate (& get) even fraction values.


Coming to the logic i have a rating control class called AHSRatingView which is a subclass of UIView, this rating control class you can add to any of viewController class like below,

- (void)viewDidLoad
{
    [super viewDidLoad];
    UIImage *ratingImg = [UIImage imageNamed:@"starRatingImg"];
    ahsRatingVw = [[AHSRatingView alloc] initWithFrame:CGRectMake(10.0, 100.0, ratingImg.size.width, ratingImg.size.height) andStarColor:[UIColor redColor]];
    ahsRatingVw.delegate = self;
    [self.view addSubview:ahsRatingVw];
}

their is a custom init method called "initWithFrame: andStarColor:" in AHSRatingView which you need to call so as to show rating control, initWithFrame: accepts a cgrect parameter where we will pass a CGRect for rate control its a good idea to get your rating image dimensions & set those width & height values, & andStarColor: accepts a UIColor type of parameter where yo can pass any of UIColor you wish, this color will be your rating star color.
After this just set the delegate "AHSRating"  in your viewController class file as below so as to get the user rating value from the AHSRatingView(rating control),

@interface ViewController : UIViewController<AHSRating>

@property (retain, nonatomic) IBOutlet UILabel *ahsRatingCountLbl; //property to get user rated value

and in your viewController implementation file if you wanna want to display user rated value just define AHSRatingView delegate method as below or you can make use of this count for further processing as per your application requirement, below is the snippet where as of now we are just updating user rated value to a UILabel.

#pragma mark - AHSRating Delegate
- (void)getRatingCount:(float)rateCount{
    ahsRatingCountLbl.text = [NSString stringWithFormat:@"your rating count is %f",rateCount];
}

thats it in your calling class.

Now coming to AHSRatingView, this is the main rating control, below is the snapshot of AHSRatingView interface file which you can refer,

AHSRatingView.h
#import <UIKit/UIKit.h>

@protocol AHSRating <NSObject>
@optional
    - (void)getRatingCount:(float)rateCount;
@end

@interface AHSRatingView : UIView
{
    UIImageView *ratingImgVw;
    CGPoint startPoint;
    CGPoint endPoint;
    UIView *fillColorView;
    CGFloat ratingViewFrameWidth;
    CGFloat singleStarRect;
    CGFloat currentStarRating;
    UIColor *ratingColor;
}
@property(nonatomic,retain) id<AHSRating> delegate;
- (id)initWithFrame:(CGRect)frame andStarColor:(UIColor *)color;
@end

here in interface file we are having instance variables which are required first is object ratingImgVw of type UIImageView so as to hold your rating image, startPoint & endPoint is of type CGPoint so as to capture user touch points, fillColorView is of UIView type so as to fill (rate) stars, ratingViewFrameWidth, singleStarRect, currentStarRating are iVars for core user rating calculation(logic), ratingColor is of type UIColor which will effect to stars. 
and on top there is a protocol definition which is defined  just to update calling class with user rated value whenever he rates.

Below is the snapshot of AHSRatingView implementation file which you can refer,

AHSRatingView.m
#import "AHSRatingView.h"
#define kNumberOfStars 5
#define kdefaultFillColor [UIColor blueColor]

@interface AHSRatingView(Private)
- (void)rating;
@end

@implementation AHSRatingView
@synthesize delegate;

- (id)initWithFrame:(CGRect)frame andStarColor:(UIColor *)color{
    self = [super initWithFrame:frame];
    if (self) {
        //initilization code
        self.clipsToBounds = YES;
        
        ratingColor = color;
        if (!ratingColor) {
            ratingColor = kdefaultFillColor;
        }
        ratingImgVw=[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
        ratingImgVw.contentMode=UIViewContentModeScaleToFill;
        ratingImgVw.image=[UIImage imageNamed:@"starRatingImg"];
        ratingImgVw.clipsToBounds = YES;
        [self addSubview:ratingImgVw];
        
        ratingViewFrameWidth = self.frame.size.width;
    }
    return self;
}

#pragma mark - Touch Events Methods
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint point = [touch locationInView:self];
    startPoint = point;
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint point = [touch locationInView:self];
    endPoint = point;
    [self rating];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
    UITouch *touch = [touches anyObject];
    CGPoint point = [touch locationInView:self];
    endPoint = point;
    singleStarRect = ratingViewFrameWidth/kNumberOfStars;//get each single star rect(width)
    currentStarRating = endPoint.x/singleStarRect;//get rating value
    
    /* handling exception */
    if (currentStarRating > 5.0) {
        currentStarRating = 5.0;
    }else if(currentStarRating < 0.0){
        currentStarRating = 0.0;
    }
    
    if (delegate) {
        if ([delegate respondsToSelector:@selector(getRatingCount:)]) {
            [delegate getRatingCount:currentStarRating];
        }
    }
    [self rating];
}

/* cancel in the sense on touch event if a call comes then this method ll trigger */
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{
    /* handle ur exception code */
    NSLog(@"Touches Cancelled");
}

#pragma mark - Rating Method
- (void)rating{
    [UIView animateWithDuration:0.50
                          delay:0.0
                        options: UIViewAnimationCurveLinear
                     animations:^{
                         if (fillColorView) {
                             [fillColorView removeFromSuperview];
                             fillColorView = nil;
                         }
                         fillColorView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, endPoint.x, self.frame.size.height)];
                         fillColorView.backgroundColor = ratingColor;
                         [self addSubview:fillColorView];
                         [self sendSubviewToBack:fillColorView];                         
                     } 
                     completion:^(BOOL finished){
                         // NSLog(@"Done!");
                     }];
    
}
@end

here in implementation file mainly we are dealing with touch events initially we will initialize our rating view with a rating image frame & a specified color, & we are getting the entire view frame width in ratingViewFrameWidth iVar. Then we are capturing touch event by touchesBegan:, touchesMoved: & touchesEnded: events. where in touchesBegan: we are capturing the starting point, touchesMoved: we are capturing the user swipe movement (points) & parallel updating star rating by calling "rating" method, & in touchesEnded: we are capturing the end Point & in parallel  calculating the rate count & informing all delegates, & updating rate by calling "rating" method.

rating instance method is actually updating ui by rating with specified color for stars.

and tats all, hope you enjoyed the post any comments either pros or cons or suggestions or whatever is acceptable from my side.
Thank you,,,:-)