I have a UICollectionViewCell, in which it has a UIImageView abd I am using the AFNetworking UIImageView category to help me load the images. I've profiled my app and it seems that the memory spike is over the top, it just keeps increasing and increasing after profiling it via Instruments under allocation tools.
I am not sure what happened here and how to fix this. Cells are being reused all the time, but it's just that maybe these images aren't purged from the cache or something. Here's some code of how I am using it, it's pretty straightforward:
NSURLRequest *imageURLRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:imageURLString] cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:30];
[self.imageView_ setImageWithURLRequest:imageURLRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
weakSelf.imageView_.image = image;
weakSelf.imageView_.alpha = 0.0;
[UIView animateWithDuration:0.3 animations:^{
weakSelf.imageView_.alpha = 1.0;
}];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
}];
If I remove this code to download the image, then the memory footprint is way smaller. Any idea on what might be causing this?
Try to wrap it in autoreleasepool and check your memory usage
#autoreleasepool {
// Code that creates autoreleased objects.
}
Related
UIImage view show previous image not update next one.this is my code
[userImage setImageWithURL:[NSURL URLWithString:[Engin shared].imagePath] placeholderImage:[UIImage imageNamed:#"dummyImge.png"]];
when i come first time on this view where i added this code in my viewdidload function ok first time image update successfully and after that i update a new image on server and get path of that image after uploaded on server and save him a separate class like that
[Engin shared].imagePath = [JSON valueForKey:#"image"];
and after that i go back to previous view and again come on that view and run this line again
[userImage setImageWithURL:[NSURL URLWithString:[Engin shared].imagePath] placeholderImage:[UIImage imageNamed:#"dummyImge.png"]];
but now this not update the image rather they show the previous image . when i check path of that image they show updated (mean) show new image but when i call function which image path they now previous image
NSUrlRequset *request = [NSUrlRequest requestWithURL:[NSURL URLWithString:[Engin shared].imagePath]];
[userImage setImageWithURLRequest:request
placeholderImage:[UIImage imageNamed:#"dummyImge.png"]
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image){
//handle success message here
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error){
//handle error message here
}];
i did not actually run this code , but you can test it your self.
I am using this code for displaying the image from URL to UIImageview
UIImageView *myview=[[UIImageView alloc]init];
myview.frame = CGRectMake(50, 50, 320, 480);
NSURL *imgURL=[[NSURL alloc]initWithString:#"http://soccerlens.com/files/2011/03/chelsea-1112-home.png"];
NSData *imgdata=[[NSData alloc]initWithContentsOfURL:imgURL];
UIImage *image=[[UIImage alloc]initWithData:imgdata];
myview.image=image;
[self.view addSubview:myview];
But the problem is that its taking too long time to display the image in imageview.
Please help me...
Is there any method to fast the process...
Instead of dispatch_async, Use SDWebImage for caching the images.
This is best I have seen...
The problem of dispatch_async is that if you lost focus from image, it will load again. However SDWebImage, Caches the image and it wont reload again.
The answers given to me on my own question Understanding the behaviour of [NSData dataWithContentsOfURL:URL] inside the GCD block does makes sense.So be sure that if you use [NSData dataWithContentsOfURL:URL] inside the GCD(as many developers do these days) is not a great idea to download the files/images.So i am leaning towards the below approach(you can either use NSOperationQueue).
Load your images using [NSURLConnection sendAsynchronousRequest:queue:completionHandler: then use NSCache to prevent downloading the same image again and again.
As suggested by many developers go for SDWebimage and it does include the above strategy to download the images files .You can load as many images you want and the same URL won't be downloaded several times as per the author of the code
EDIT:
Example on [NSURLConnection sendAsynchronousRequest:queue:completionHandler:
NSURL *url = [NSURL URLWithString:#"your_URL"];
NSURLRequest *myUrlRequest = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:myUrlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
if ([data length] > 0 && error == nil)
//doSomething With The data
else if (error != nil && error.code == ERROR_CODE_TIMEOUT)
//time out error
else if (error != nil)
//download error
}];
Use Dispatch queue to load image from URL.
dispatch_async(dispatch_get_main_queue(), ^{
});
Or add a placeholder image till your image gets load from URL.
I'm looking to set the image within a custom tableviewcell and use the height of the returned image within the heightForRowAtIndexPath method.
Is there anyway to get this returned data into the heightForRowAtIndexPath method?
Currently I'm using a local dictionary and setting it as per below:
NSURLRequest* urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:recent.show.showImage] cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:30];
[cell.imageView setImageWithURLRequest:urlRequest placeholderImage:[UIImage imageNamed:#"icon"] success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
NSNumber *imageHeight = [[NSNumber alloc] initWithFloat:image.size.height];
NSString *indexString = [NSString stringWithFormat:#"%d", indexPath.row];
[self.returnedImages setValue:imageHeight forKey:indexString];
[imageHeight release];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
}];
any pointers on a more efficient approach greatly appreciated.
Cheers
Nik
The way you're currently doing this in a NSDictionary is appropriate. Although to make sure it updates as quickly as possible you could add [self.tableView reloadData] to your success block, since then it will immediately refresh your tableview with the updated data. Even better you could use the reloadRowsAtIndexPaths:withRowAnimation: and pass it just the index path of the newly downloaded UIImage so it won't refresh the entire tableview.
Docs
In short, I'm looking for a way to use a previously cached image as my placeholder in AFNetworking's UIImageView Category:
- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest
placeholderImage:(UIImage *)placeholderImage
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure
Example Use case:
I have a model named Post that I populate from an API response:
#interface Post : NSObject
#property ... NSString *smallImagePath;
#property ... NSString *largeImagePath;
#property ... NSString *description;
#end
My first ViewController will display a grid of thumbnails (retrieved via the smallImagePath property) for all my Post objects. Tapping on a thumbnail will take you to a DetailViewController, where the large image will ultimately display with the description.
Since I've already downloaded and cached the small thumbnail, I'd like to use it as the placeholder while I wait for the large image to be downloaded. At this point I can't figure out how to get into the AFImageCache since it's not publicly accessible.
One thing I thought of is storing the UIImage that is passed as an argument in the success block:
// add property to Post model
#property ... UIImage *smallImage;
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
[self.post setSmallImage:image];
}
And then I can use that image directly as the placeholder while I download the large image.
I'm not sure if this will have any noticeable/negative impact to my memory footprint by keeping references to a bunch of UIImage's though. Can you think of a better way?
Ended up going with my original idea, which was to store the image as a property on my model. That way, when needing to declare a placeholder while the larger image loads, I just access that property. Performance has been great.
I am using following code to download file from url's asynchronously,
NSMutableData *responseData = [[NSMutableData alloc] init];
NSURL *url = [NSURL URLWithString:#"http://www.tuiscos.com/images/trading.png"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
// do something with data
[responseData appendData:data];
myImage8.image = [UIImage imageWithData:data];
NSInteger len = response.expectedContentLength;
NSInteger receiverdBytes = 0;
receiverdBytes = data.length+ receiverdBytes;
float prog = (float)[responseData length]/(float)len;
[progress8 setProgress:prog];
}];
as the download progresses, I want to update the progress bar, but using this code, I am not getting a gradual progress, instead it is waiting to complete the download and jumping to the maximum value. How can I make a gradual progress in the value?
Can somebody provide a sample code? For asynchronous method with delegate methods.
Thanks :)
If you don't want to code everything on your own, I would suggest using ASIHTTPRequesst on this task:
http://allseeing-i.com/ASIHTTPRequest/How-to-use
It is very simple to implement and you can do simultaneous, asynchrony downloads. It also provides delegates for all needs, also for progress updates.
I used it in my projects for almost a year now and never regretted it.
CompletionHandler is executed at completion, of course. You have to a delegate for the connection. Use -initWithRequest:delegate: method. You will have to code the NSURLConnectionDelegate methods and the one you need to set progressView value is -connection:didReceiveData:
Here is the doc: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.pdf