I'm loading JSON data using ASIHTTPRequest. I'm requesting huge amount of data when the user touch the button (Here I'm loading another view which will request JSON data). It takes about 15 sec. to load. How can I use the UIActivityIndicatiorView once the user touch the button until the data loads.
Anyone did this before or any suggestion to improve user performance?
-(void) startRequest:(NSString*)username password:(NSString*)password
{
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:mainUrl];
[request setDelegate:self];
[request setDidFailSelector:#selector(requestFailed:)];
[request startAsynchronous];
[self.addSubview:self.indicator];
[indicator startAnimating];
}
-(void) requestFinished: (ASIHTTPRequest *) request {
[self.indicator stopAnimating];
[self.indicator removeFromSuperview];
}
Here is a sample for using the ASIHTTPRequest and UIActivityIndicator
-(void) loadImageFromURL:(NSURL *) url withActivityIndicator:(BOOL) yesOrNo {
__block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
UIActivityIndicatorView *activityIndicator = nil;
if (yesOrNo == YES) {
activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleGray];
[activityIndicator setCenter: self.center];
[activityIndicator startAnimating];
[self addSubview: activityIndicator];
}
[request setCompletionBlock: ^{
self.image = [UIImage imageWithData: [request responseData]];
[activityIndicator removeFromSuperview];
[activityIndicator release];
}];
[request setFailedBlock: ^{
[activityIndicator removeFromSuperview];
[activityIndicator release];
}];
[request startAsynchronous];
}
#end
Related
I have cobbled together some methods to resize images and put them into a UIScrollView for horizontal scrolling, however one of my problems is that I'm capturing strongly, and I have attempted a few options that I have read about, but all result in no images being displayed. I'm hoping one of you can help me resolve this issue so I can quit cooking so much memory when my app loads the images into the scroll view.
- (void)setImage:(NSURL *)imageURL errorImage:(UIImage *)errorImage{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:imageURL];
[request addValue:#"image/*" forHTTPHeaderField:#"Accept"];
UIImageView *newView = [[UIImageView alloc] initWithFrame: CGRectMake(self.x, 0, self.screenWidth, self.screenHight)];
[self.scrollView addSubview: newView];
self.x = (self.x + newView.frame.size.width);
if(self.x > self.view.frame.size.width) {
self.scrollView.contentSize = CGSizeMake(self.x, self.scrollView.frame.size.height);
}
[[newView subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)]; // Remove previous that not stop
__block UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] init];
activityIndicator.frame = newView.bounds;
[activityIndicator setHidden:NO];
[activityIndicator startAnimating];
activityIndicator.color = [UIColor redColor];
[newView addSubview:activityIndicator];
void (^removeSpinner)(void) = ^{ // Desctuctor Block
if (activityIndicator) {
[activityIndicator setHidden:YES];
[activityIndicator stopAnimating];
[activityIndicator removeFromSuperview];
activityIndicator = nil;
}
};
[newView setImageWithURLRequest:request placeholderImage:nil success: ^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
removeSpinner();
// resize the resulting image for this device
newView.image = [self imageScaleCropToSize:image];
NSLog(#"successfully loaded image: %#", imageURL);
} failure: ^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
removeSpinner();
NSLog(#"failed loading [%#]: %#", imageURL, error);
}];
}
Hi in my application i have the image on UIImageView and i have button called download once user click the download button the image will save to the Photolibrary. Now i want to add the Progressbar for the download to know the user its downloading the image.
I have used the MBProgressHUD for the progress but not able work like i wanted. I want to show once user click the download button like its downloading message with progress once image got downloaded i want to show like image downloaded please tell me how to achieve this one i tired something like that its not working.
My MBProgressHUD code.
- (IBAction)down:(id)sender {
HUD = [[MBProgressHUD alloc] initWithView:self.view];
HUD.labelText = #"downloading...";
HUD.mode = MBProgressHUDModeAnnularDeterminate;
[self.view addSubview:HUD];
[HUD showWhileExecuting:#selector(download) onTarget:self withObject:nil animated:YES];
UIImageWriteToSavedPhotosAlbum(imageview.image, nil, nil, nil);
}
- (void)download {
float progress = 0.0;
while (progress < 1.0) {
progress += 0.01;
HUD.progress = progress;
usleep(50000);
}
}
I have used the above code to achieve but its not working like i wanted please tell me how to achieve this one.
Thanks.
- (IBAction)down:(id)sender {
HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.mode =MBProgressHUDModeAnnularDeterminate;
NSString *strloadingText = [NSString stringWithFormat:#"Downloading...."];
HUD.labelText = strloadingText;
[HUD show:YES];
[HUD showWhileExecuting:#selector(doSomeFunkyStuff) onTarget:self withObject:nil animated:YES];
}
- (void)doSomeFunkyStuff {
float progress = 0.0;
while (progress < 1.0) {
progress += 0.01;
HUD.progress = progress;
usleep(5000000);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
^{
// process in background thread
NSString *strloadingText = [NSString stringWithFormat:#"completed"];
HUD.labelText = strloadingText;UIImageWriteToSavedPhotosAlbum(imageview.image, nil, nil, nil);
[HUD hide:YES];
});
}
}
UIImageWriteToSavedPhotosAlbum works on main thread. So, put this function in GCD. Your UI can not update itself when main thread is busy.
Try this:
- (IBAction)down:(id)sender {
...
[HUD showWhileExecuting:#selector(download) onTarget:self withObject:nil animated:YES];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
^{
// process in background thread
UIImageWriteToSavedPhotosAlbum(imageview.image, nil, nil, nil);
// when finish, dismiss HUD
HUD.hidden = YES;
});
}
you can use https://github.com/samvermette/SVProgressHUD for showing progress bar..If you are downloading image from server then use async call. Like if you are using ASIFormDataRequest request for getting image then use as follow :
[SVProgressHUD showWithStatus:#"Please wait"];
self.view.userInteractionEnabled = NO;
NSURL *url=[NSURL URLWithString:#"your URL request"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setRequestMethod:#"POST"];
[request setPostValue:xyz forKey:#"abc"];
[request.shouldAttemptPersistentConnection = NO;
request.delegate=self;
request.timeOutSeconds = 10;
[request startAsynchronous];
After this you can call :
-(void)requestFinished:(ASIHTTPRequest *)request
{
NSError *error = [request error];
if (!error)
{
NSString *response = [request responseString];
NSMutableDictionary *responseJSON = [response JSONValue];
[SVProgressHUD dismiss];
self.view.userInteractionEnabled = YES;
UIImageWriteToSavedPhotosAlbum(imageview.image, nil, nil, nil);
}
}
Hope this will help you.
Ok here's the question, how do I simulate loading message until I fully downloaded the data from the server. I have this problem as I can't pass the data to the next view controller when the properties to hold the data from the downloaded json is still nil. So, How can I simulate a loading message until I fully parsed the Json.
Here's my code to fetch data
-(void)fetchFeed
{
NSString *requestString = #"some website";
NSURL *url = [NSURL URLWithString:requestString];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary * jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
self.locations = jsonObject[#"someKey"];
NSLog(#"%#", self.locations);
}
];
[dataTask resume];
}
- (void)viewDidLoad
{
[super viewDidLoad];
MBProgressHUD *hud = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:hud];
[hud show:YES];
[hud setLabelText:#"Loading..."];
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
[self fetchFeed]; //Network activity
dispatch_async(dispatch_get_main_queue(), ^{
//do stuff after json download
[MBProgressHUD hideHUDForView:self.view animated:YES];
});
});
Please check out my answer here.. It pretty much does the same thing that you are looking for..
I have used MBProgressHUD to show the loading message.
Its as simple as
MBProgressHUD *hud = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:hud];
[hud show:YES];
[hud setLabelText:#"Loading..."];
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
//Network activity
dispatch_async(dispatch_get_main_queue(), ^{
//do stuff after json download
[MBProgressHUD hideHUDForView:self.view animated:YES];
});
});
for a more detailed answer check the link.
*************EDIT*******************
As you are using NSURLSession it allows you to perform background download operations. As per the code you posted, we don't to start a new thread using dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{})
Please try this..
- (void)viewDidLoad
{
[super viewDidLoad];
[self fetchFeed]; //Network activity
}
-(void)fetchFeed
{
MBProgressHUD *hud = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:hud];
[hud show:YES];
[hud setLabelText:#"Loading..."];
NSString *requestString = #"some website";
NSURL *url = [NSURL URLWithString:requestString];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
[[self.session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){
NSDictionary * jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
self.locations = jsonObject[#"someKey"];
NSLog(#"%#", self.locations);
dispatch_async(dispatch_get_main_queue(), ^{
[MBProgressHUD hideHUDForView:self.view animated:YES];
});
}] resume];
}
This should work.
Here i am trying to call my ASIHTTPRequest in a GCD. Sometimes the comletion blocks and failed blocks are not executing. What i want to do is, after this request finished, i have to use the returned data in a another ASIHTTPRequest. So how to improve this code:
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:url]];
[request setCompletionBlock:^{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
NSData *_responseData = [request responseData];
NSString *response = [[NSString alloc] initWithData:_responseData encoding:NSASCIIStringEncoding] ;
self.albumDic = [response JSONValue];
[response release];
dispatch_async(dispatch_get_main_queue(), ^{
[self GetDictionary:self.albumDic];
});
});
}];
[request setFailedBlock:^{
NSError *error = [request error];
NSLog(#"Error : %#", error.localizedDescription);
}];
[request startSynchronous];
Don't go that way. You're doing threading on threading (GCD uses threading and so does ASIHTTPRequest when used asynchronously).
Use ASINetworkQueue instead - read about it here
Here is a simple way you could use it:
- (void)addRequestsToNetworkQueue:(NSArray *)requests {
// Stop anything already in the queue before removing it
[[self networkQueue] cancelAllOperations];
// Creating a new queue each time we use it means we don't have to worry about clearing delegates or resetting progress tracking
[self setNetworkQueue:[ASINetworkQueue queue]];
[[self networkQueue] setDelegate:self];
[[self networkQueue] setRequestDidFinishSelector:#selector(requestFinished:)];
[[self networkQueue] setRequestDidFailSelector:#selector(requestFailed:)];
[[self networkQueue] setQueueDidFinishSelector:#selector(queueFinished:)];
//Add all requests to queue
for (ASIHTTPRequest *req in requests) {
[[self networkQueue] addOperation:req];
}
//Start queue
[[self networkQueue] go];
}
ASINetworkQueue provides many delegate methods (most are also customizable), so you can update the GUI when a request is finished and so forth. It is asynchronous, so GCD is unnecessary.
I use asihttprequest to download multiple files and I'm wondering how I can remove the associated UIProgressview with the right request when the download is done.
NSMutableArray *contentArray contains the ASIHTTPRequest and NSMutableArray *progArray contains my custom UIProgressview.
-(void)addDownload:(NSString *)theURL withName:(NSString *)fileName
{
theProgress = [[PDColoredProgressView alloc] initWithFrame:CGRectMake(3, 17, 314, 14)];
//...
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:theURL]];
//..
[request setDelegate:self];
[request setDownloadProgressDelegate:theProgress];
request.allowResumeForFileDownloads = YES;
[request startAsynchronous];
[request setShouldContinueWhenAppEntersBackground:YES];
[contentArray addObject:request];
[progArray addObject:theProgress];
[theProgress retain];
[self.tableView reloadData];
}
- (void)requestFinished:(ASIHTTPRequest *)request{
[contentArray removeObject:request];
[progArray removeObject:theProgress];
NSLog(#"%#",progArray);
NSLog(#"%#",contentArray);
[self reloadMyData];
[self.tableView reloadData];
}
The problem is that this code remove the last progressview even if the there are 3 downloads in contentArray and the second one finish first.
Can you help me with this ?
If you need to remove progress view that's associated with finished request you can get it from request's downloadProgressDelegate property:
- (void)requestFinished:(ASIHTTPRequest *)request{
PDColoredProgressView *progress = (PDColoredProgressView*)request.downloadProgressDelegate;
[contentArray removeObject:request];
if (progress)
[progArray removeObject:progress];
[self reloadMyData];
[self.tableView reloadData];
}