How to fetching image from server asynchronously - iphone

I am doing following thing to load my image from server. But problem is that imageview is showing up 5-7 seconds later when alertview is closing.
how to solve this ?
- (void)showFullImage :(id) sender
{
// for loading view
self.loading_alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"LOADING",nil) message:nil delegate:self cancelButtonTitle:nil otherButtonTitles: nil];
[self.loading_alert show];
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithFrame: CGRectMake(125, 65, 30, 30)];
indicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
//indicator.center = CGPointMake(loading_alert.bounds.size.width / 2, loading_alert.bounds.size.height - 50);
[indicator startAnimating];
[self.loading_alert addSubview:indicator];
self.image_url = [self.question_set valueForKey:#"image_url"];
//--------Asyncronously fetch image----------------------------------------
NSURL *URL = [NSURL URLWithString:image_url];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL cachePolicy:NSURLCacheStorageAllowedInMemoryOnly
timeoutInterval:60.0];
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
NSLog(#"1",nil);
imgView= [[UIView alloc] initWithFrame:CGRectMake(0,0,320,480) ];
UIImage* queImage = [UIImage imageWithData:data];
UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectMake(0,42,320,420)];
iv.image = queImage;
[imgView addSubview:iv];
[self.view addSubview:imgView];
//dismiss alert view on main thread
dispatch_async(dispatch_get_main_queue(), ^(void) {
// dismiss alert view...
NSLog(#"2",nil);
[self.loading_alert dismissWithClickedButtonIndex:0 animated:YES];
});
}];
}
Help will be appreciated.

Forget GCD, you can pass [NSOperationQueue mainQueue] in queue parameter of NSURLConnection's sendAsynchronousRequest:queue:completionHandler: method, so you dont need to think much about main thread and background thread, it'll automatically handle call request in background and return data on main thread.
And below is how your code will look like:
NSURL *URL = [NSURL URLWithString:image_url];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL cachePolicy:NSURLCacheStorageAllowedInMemoryOnly timeoutInterval:60.0];
// request is called asynchronously and response completion handler will be called on main thread
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
// do your whatever work here as you do normally, because it's in main thread
NSLog(#"1",nil);
imgView= [[UIView alloc] initWithFrame:CGRectMake(0,0,320,480) ];
UIImage* queImage = [UIImage imageWithData:data];
UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectMake(0,42,320,420)];
iv.image = queImage;
[imgView addSubview:iv];
[self.view addSubview:imgView];
}

You need to download images in background queue and UI updation in main queue.
Using GCD like this,
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSURL *URL = [NSURL URLWithString:image_url];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL cachePolicy:NSURLCacheStorageAllowedInMemoryOnly
timeoutInterval:60.0];
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
NSLog(#"1",nil);
UIImage* queImage = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
imgView= [[UIView alloc] initWithFrame:CGRectMake(0,0,320,480) ];
if([receivedView isKindOfClass:[UIImageView class]])
{
UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectMake(0,42,320,420)];
iv.image = queImage;
[imgView addSubview:iv];
[self.view addSubview:imgView];
}
// dismiss alert view...
NSLog(#"2",nil);
[self.loading_alert dismissWithClickedButtonIndex:0 animated:YES];
});
}
});

SDWebmage -> This is a nice third party library for loading images.

Related

UIAlertView is showing up late

I am communicating with server in my ios app. I have following method in which I'm opening an alertview. I want to show a loading view while app is getting response from the server.
- (void) showDetailedQuestion:(id)sender
{
//loading view
self.loading_alert = [[UIAlertView alloc] initWithTitle:#"Loading\nPlease Wait..." message:nil delegate:self cancelButtonTitle:nil otherButtonTitles: nil];
[self.loading_alert show];
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
// Adjust the indicator so it is up a few pixels from the bottom of the alert
indicator.center = CGPointMake(loading_alert.bounds.size.width / 2, loading_alert.bounds.size.height - 50);
[indicator startAnimating];
[self.loading_alert addSubview:indicator];
UIButton *btn = (UIButton*)sender;
int indx = btn.tag;
NSLog(#"tag:%d",indx);
answerAnQuestion *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"Answer"];
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal ;
vc.que_id = [self.que_id valueForKey:[NSString stringWithFormat:#"%d",indx]];
vc.qid_list = self.que_id;
vc.crnt = indx;
[self presentViewController:vc animated:YES completion:nil];
[self.loading_alert dismissWithClickedButtonIndex:0 animated:YES];
}
and in another answerAnQuestion.m
- (void)viewDidLoad
{
NSString *address = [NSString stringWithFormat:#"%#%#%#%#%#%#%#", path,#"questions/",que_id,#"?token=",token,#"&user_id=",usrId];
NSURL *URL = [NSURL URLWithString:address];
NSLog(#"%#",address);
[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[URL host]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL cachePolicy:NSURLCacheStorageAllowedInMemoryOnly
timeoutInterval:60.0];
[request setHTTPMethod:#"GET"];
responseData = [[NSMutableData alloc] init];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (data)
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*) response;
//If you need the response, you can use it here
int statuscode = [httpResponse statusCode];
NSString *responseMsg = [NSHTTPURLResponse localizedStringForStatusCode:statuscode];
NSLog(#" Status code: %d",statuscode );
NSLog(#" Status msg: %#",responseMsg );
}
else
{
// Handle error by looking at response and/or error values
NSLog(#"%#",error);
}
}
My problem is alertview is only shown up for a moment when view is changing. It suppose to open when I click the button. What could be the reason? how to solve this?
EDIT 1:
If i make asynchronous request to server then i'm not able to set those data in my tableview. I can set those data in my tableview Only if send synchronous request,but it blocks the app. Why this is happening ?
Any help will be appreciated.
Thank you.
You are sending SynchronousRequest on main thread, so it is blocking your UI thread. Read multithreading you will get various tutorial on this. I can suggest you to go for GCD or NSOperation and NSOperationQueue. Google for any of the above and you will get various sample for the same.
Or you can send asynchronous request as follows...
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//Write code you want to call when data is received,
//Like dismissing loading view and populating UI.
}];
Updated:
//Display alert view, before sending your request..
[alertview show];
//send first request
[NSURLConnection sendAsynchronousRequest:request1 queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//Write code you want to call when data is received,
//send second request
[NSURLConnection sendAsynchronousRequest:request2 queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//Write code you want to call when data is received,
//send third request
[NSURLConnection sendAsynchronousRequest:request3 queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//Write code you want to call when data is received,
//dismiss alert view on main thread
dispatch_async(getmainqueue, ^(void) {
// dismiss alert view...
});
}];
}];
}];
I have worked with Nuzhat Zari code, and I thank him for it, but also have experienced some issues with some core data operations between nested "sendAsynchronousRequest" (getting some weird thread and memory errors) so, my solution was unnest the calls to "sendAsynchronousRequest" and use some main thread variable validation.
#interface myMainThreadClass
#property (nonatomic,assign) NSInteger *currentAsyncTasks;
#end
#implementation
// Use init or viewDidLoad to make "currentAsyncTasks=0"!!
-(void)method
{
[self showLoadingAlert]; //or some ui update function
currentAsyncTasks++;
[NSURLConnection sendAsynchronousRequest:urlRequest queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//do something with data
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self dismissAlertInFinalTask]
});
}];
currentAsyncTasks++;
[NSURLConnection sendAsynchronousRequest:urlRequest2 queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//do something with data
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self dismissAlertInFinalTask]
});
}];
currentAsyncTasks++;
[NSURLConnection sendAsynchronousRequest:urlRequest3 queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//do something with data
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self dismissAlertInFinalTask]
});
}];
}
-(void)dismissAlertInFinalTask
{
currentNetworkTasks--;
if (currentNetworkTasks == 0)
{
[self dismissLoadingAlert];//or some ui update function;
}
}
#end
I also want to know if someone has managed to do multiple request using NSURLConnection delegate NSURLConnectionDataDelegate and ui calls.

how to show activity indicator in iphone application while uploading data

I am uploading data to server i want that when i click upload button then activity indicator should start and stop after the data is uploaded.
This is how i am uploading data but activity indicator not working.
-(IBAction)startSyncButtonAction{
[self startActivity];
CereniaAppDelegate *appDelegate = (CereniaAppDelegate *)[[UIApplication sharedApplication] delegate];
for (int i=0; i<[appDelegate.coffeeArray count]; i++) {
Coffee *coffeeObj = [appDelegate.coffeeArray objectAtIndex:i];
int mycount=[appDelegate.coffeeArray count];
NSLog(#"My Array count is %d",mycount);
NSString*device_Id=coffeeObj.device_Id;
NSString*R1=coffeeObj.R1;
NSString*R2=coffeeObj.R2;
NSString*R3=coffeeObj.R3;
NSString*R4=coffeeObj.R4;
NSString*R5=coffeeObj.R5;
NSString*R6=coffeeObj.R6;
NSString*R7=coffeeObj.R7;
NSString*R8=coffeeObj.R8;
NSString*R9=coffeeObj.R9;
NSString*R10=coffeeObj.R10;
NSString*R11=coffeeObj.R11;
NSString*R12=coffeeObj.R12;
NSString*R13=coffeeObj.R13;
NSString*R14=coffeeObj.R14;
NSString*update_date_time=coffeeObj.update_date_time;
NSString*teritory1=coffeeObj.teritory;
int mycount1=[appDelegate.coffeeArray count];
NSLog(#"My Array After delete is %d",mycount1);
NSLog(#"device_Id%#",device_Id);
NSLog(#"R1%#",R1);
NSLog(#"R2%#",R2);
NSLog(#"R3%#",R3);
NSLog(#"R4%#",R4);
NSLog(#"R4%#",R5);
NSLog(#"R4%#",R6);
NSLog(#"R4%#",R7);
NSLog(#"R4%#",R8);
NSLog(#"R4%#",R9);
NSLog(#"R4%#",R10);
NSLog(#"R4%#",R11);
NSLog(#"R4%#",R12);
NSLog(#"R4%#",R13);
NSLog(#"R4%#",R14);
NSLog(#"update_date_time%#",update_date_time);
NSString *post =[[NSString alloc] initWithFormat:#"device_Id=%#&R1=%#&R2=%#&R3=%#&R4=%#&R5=%#&R6=%#&R7=%#&R8=%#&R9=%#&R10=%#&R11=%#&R12=%#&R13=%#&R14=%#&update_date_time=%#&teritory1=%#",device_Id,R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12,R13,R14,update_date_time,teritory1];
NSLog(post);
NSURL *url=[NSURL URLWithString:#"http://celeritas-solutions.com/pah_brd_v1/pfizersurvey/SyncSurveySTD.php"];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init] ;
[request setURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSError *error;
NSURLResponse *response;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString *data=[[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
NSLog(#"%#",data);
}
for (int i=0; i<[appDelegate.coffeeArray count]; i++) {
Coffee *coffeeObj = [appDelegate.coffeeArray objectAtIndex:i];
[appDelegate removeCoffee:coffeeObj];
}
}
-(void)startActivity:(id)sender
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
activityImageView.hidden=NO;
activityView.hidden=NO;
[activityView startAnimating];
[pool release];
}
Try below code but I am giving example you should modify it & use according to your need:
alert= [[UIAlertView alloc] initWithTitle:#"Loading\nPlease Wait..." message:nil delegate:self cancelButtonTitle:nil otherButtonTitles: nil];
[alert show];
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
indicator.center = CGPointMake(150, 100);
[indicator startAnimating];
[alert addSubview:indicator];
Use this line to dismiss indicator:
[alert dismissWithClickedButtonIndex:0 animated:YES];
Try. Best of luck.
For better user experience i will recommend you to use UIProgressHUD
UIProgressHUD* hud = [[UIProgressHUD alloc] initWithFrame:CGRectZero];
[hud setText:#"Loading, please wait."];
[hud showInView:someView];
...
[hud done];
...
[hud hide];
...
[hud release];
Are you 100% sure that activityView is not nil?? I don't see anywhere you set it to anything. Also, even it were not nil, have you added it to a view? activityView is just a regular UIView, it won't automatically appear in UIWindows.

How to download & display an image from ftp server

(new to xCode and programming) I am trying to connect/download/save to variable and display an image in UIImageView from an ftp server. The code is below. Any help advice would be appreciated.
- (void)viewDidLoad
{
//sets label to notify user whats happening
NSMutableString *labelString;
labelString = [NSMutableString stringWithString: #"Connecting"];
[labelDymamic setText: labelString];
//variable for ftp location
NSString *ftpLocation = [NSString stringWithFormat:#"ftp2.bom.gov.au/anon/sample/gms/IDE00003.201011170430.gif"];
//variable to recieve data
NSMutableData *responseData;
//loads ftpLocation into url
NSURL *url = [NSURL URLWithString:ftpLocation];
//sets label to notify user whats happening
NSMutableString *labelStringDownloading;
labelStringDownloading = [NSMutableString stringWithString: #"Downloading"];
[labelDymamic setText: labelStringDownloading];
//Connect to ftp
self.ftpImageView.image = [UIImage imageNamed:#"Icon.png"];
self.labelDymamic.text = #"Receiving";
NSURLRequest *request = [NSURLRequest requestWithURL:url];
(void) [[NSURLConnection alloc] initWithRequest: request delegate:self];
//download image
//save to variable
//display to screen
//sets label to notify application loading complete
NSMutableString *labelLoadedString;
labelLoadedString = [NSMutableString stringWithString: #"Radar"];
[labelDymamic setText: labelLoadedString];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
At the moment all that is displayed is a white screen with labelLoadedString variable "Radar".
Thanks
Allan
your url is wrong, its missing the SCHEME: ftp://
as for downloading:
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//download
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * r, NSData * d, NSError * e) {
//save
UIImage *img = [[UIImage alloc] initWithData:d];
//display
self.imageView.image = img;
//sets label to notify application loading complete
NSMutableString *labelLoadedString;
labelLoadedString = [NSMutableString stringWithString: #"Radar"];
[labelDymamic setText: labelLoadedString];
}];
After fixing your URL, which as mentioned appears to be incorrect, checkout AFNetworking (see https://github.com/AFNetworking/AFNetworking). There's a category on UIImage that will make your life a lot easier when dealing with loading images from remote locations (such as over http, https, ftp, you name it ;)
Here's an example from their overview:
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 100.0f)];
[imageView setImageWithURL:[NSURL URLWithString:#"http://i.imgur.com/r4uwx.jpg"] placeholderImage:[UIImage imageNamed:#"placeholder-avatar"]];

ASIHTTPRequest-multiple request

I am developing an app that will request the profile picture URL of some users from Facebook servers, but I don't know how many users I will have (it might be 2 or it might be 20). Should I use ASIHTTPRequest with a loop and a synchronous request, or the API graph (with Facebook SDK for iOS) with a loop?
Trying using ASINetworkQueue. It will allow you to create a queue of ASIHTTPRequests that can still be started asynchronously. For example
- (void)getImages
{
if(!self.queue)
self.queue = [[[ASINetworkQueue alloc] init] autorelease];
NSArray* urlStringsToRequest = [NSArray arrayWithObjects:#"http://www.example.com/image1.png",#"http://www.example.com/image2.png",nil];
for(NSString* urlString in urlStringsToRequest)
{
NSURL *url = [NSURL URLWithString:urlString];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request setDidFinishSelector:#selector(requestDone:)];
[request setDidFailSelector:#selector(requestWentWrong:)];
[self.queue addOperation:request];
}
[self.queue go];
}
- (void)requestDone:(ASIHTTPRequest*)req
{
UIImage* image = [UIImage imageWithData:[req responseData]];
[imageArray addObject:image];
}
- (void)requestWentWrong:(ASIHTTPRequest*)req
{
NSLog(#"Request returned an error %#",[req error]);
}

iPhone - is ASIHTTPRequest threadsafe?

I have this method:
-(void)updateSomething
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSURL *url = [NSURL URLWithString:#"some url"];
ASIFormDataRequest *httpRequest = [ASIFormDataRequest requestWithURL:url];
[httpRequest startSynchronous];
//some other stuff
[pool drain];
}
I call this method onapplicationDidFinishLaunching
IF i call it on the main thread it works fine
[self getMyItems];
But when I call it on a separate thread I get a "Program received signal: "EXC_BAD_ACCESS"
[self performSelectorInBackground:#selector(getMyItems) withObject:nil];
Any idea how to resolve this issue?
Why perform individual requests on separate threads when you can use ASINetworkQueue?
ASINetworkQueue *aQueue = [[ASINetworkQueue alloc] init];
[aQueue addOperation:requestToAdd];
[aQueue setDelegate:self];
[aQueue setRequestDidFinishSelector:#selector(requestFinished:)];
[aQueue setRequestDidFailSelector:#selector(requestFailed:)];
[aQueue setQueueDidFinishSelector:#selector(queueFinished:)];
[aQueue go];
ASINetworkQueue is a subclass of NSOperationQueue and ASI*Requests are run on separate threads.