Create Array in cellForRowInIndexPath - iphone

I'm trying to save an array of images that I retrieve asynchronously in the cellForRowInIndexPath method of the UITableViewController.
Unfortunately, the array is not fully populated or in incorrect order.
The code within my tableview:cellForRowAtIndexPath method is:
// populate the cell's image
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(queue, ^{
NSURL *url = [NSURL URLWithString:[newsModel url]];
NSData *data = [NSData dataWithContentsOfURL:url];
img = [[UIImage alloc] initWithData:data] ;
[imageArray insertObject:img atIndex:[indexPath row]];
dispatch_sync(dispatch_get_main_queue(), ^{
// make image standard size
CGSize imageSize = CGSizeMake(40, 40);
UIGraphicsBeginImageContext(imageSize);
CGRect imageRect = CGRectMake(0.0, 0.0, imageSize.width, imageSize.height);
[img drawInRect:imageRect];
cell.imageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[cell setNeedsLayout];
});
});
Both the imageArray (NSMutableArray) and img (UIImage) are of type __bool.
Thanks in advance for your help.

Try to store into dictionary with key inplace of array because no chances to duplication after that insert into array using AllValue of dictionary
For ex:
imageArray =[[dict allValues]mutableCopy];
NSMutableDictionary *dict=[[NSMutableDictionary alloc]init];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(queue, ^{
NSURL *url = [NSURL URLWithString:[newsModel url]];
NSData *data = [NSData dataWithContentsOfURL:url];
img = [[UIImage alloc] initWithData:data] ;
[dict setObject:img forKey:indexPath.row]
dispatch_sync(dispatch_get_main_queue(), ^{
// make image standard size
CGSize imageSize = CGSizeMake(40, 40);
UIGraphicsBeginImageContext(imageSize);
CGRect imageRect = CGRectMake(0.0, 0.0, imageSize.width, imageSize.height);
[img drawInRect:imageRect];
cell.imageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[cell setNeedsLayout];
});
});
imageArray =[[dict allValues]mutableCopy];

Don't try to modify the cell after the download has completed, you don't know if it's been reused. Just save the image and then ask the table view to reloadData (ensure you ask for the reload on the main thread).

Related

Strange UIImageview remote image loading behaviour

I am trying to load remote image on my imageview using the following code. displayImage is referenced with imageview at testview.xib
- (void)viewDidLoad
{
[super viewDidLoad];
self.displayImage.userInteractionEnabled = YES;
NSMutableURLRequest *requestWithBodyParams = [NSMutableURLRequest requestWithURL:self.gImg.URL];
NSData *imageData = [NSURLConnection sendSynchronousRequest:requestWithBodyParams returningResponse:nil error:nil];
self.originalImage = [UIImage imageWithData:imageData];
self.displayImage.contentMode = UIViewContentModeScaleAspectFit;
self.displayImage = [[UIImageView alloc] initWithImage:self.originalImage];
[self.displayImage setImage:self.originalImage];
NSLog(#"DisplayImage Object:%#",self.displayImage);
NSLog(#"height of Displayimage image:%.f",self.displayImage.image.size.height);
}
But the image is not showing. I am certain image did loaded on imageview. Here is output log:
DisplayImage Object:<UIImageView: 0x11033270; frame = (0 0; 720 632); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1104c620>>
height of Displayimage image:632
Here I am modified your code:
No need to alloc the UIImageView in code, if you have the UIImageView in .xib.
NSURL *gImg = [NSURL URLWithString:#"http://www.vinfotech.com/sites/default/files/iphoe-app-design-ios7-way-12.jpg"];
NSMutableURLRequest *requestWithBodyParams = [NSMutableURLRequest requestWithURL:gImg];
NSData *imageData = [NSURLConnection sendSynchronousRequest:requestWithBodyParams returningResponse:nil error:nil];
UIImage *originalImage = [UIImage imageWithData:imageData];
self.displayImage.contentMode = UIViewContentModeScaleAspectFit;
// self.displayImage = [[UIImageView alloc] initWithImage:originalImage];
[self.displayImage setImage:originalImage];
NSLog(#"DisplayImage Object:%#",self.displayImage);
NSLog(#"height of Displayimage image:%.f",self.displayImage.image.size.height);
Hope so, this code helps you.
Create a dispatch queue:
dispatch_queue_t backgroundQueue = dispatch_queue_create("com.mayapp", NULL);
Use NSData method dataWithContentsOfURL and download the image in a background thread:
dispatch_async(backgroundQueue, ^(void) {
NSData *data = [NSData dataWithContentsOfURL:requestWithBodyParams];
//as soon as the image is downloaded, draw image in a main thread
dispatch_sync(dispatch_get_main_queue(), ^(void) {
self.originalImage = [UIImage imageWithData:data];
self.displayImage.contentMode = UIViewContentModeScaleAspectFit;
self.displayImage = [[UIImageView alloc] initWithImage:self.originalImage];
[self.displayImage setImage:self.originalImage];
});//close main block
});//background block
This Sample code works fine for me :
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *url = [NSURL URLWithString:#"http://iceclearmedia.com/wp-content/uploads/2011/04/SEO-and-url-Shorteners.jpg"];
NSData* imageData = [[NSData alloc] initWithContentsOfURL:url];
UIImage* image = [[UIImage alloc] initWithData:imageData] ;
[self performSelectorOnMainThread:#selector(displayImage:) withObject:image waitUntilDone:NO];
}
- (void)displayImage:(UIImage *)image {
[self.imagedownload setImage:image]; //UIImageView
}

Loading images in background to optimize the loading in ios

I am trying to optimize the load in my application, in fact, I have a lot of images that loaded in my application, and I spend a lot of time waiting for a view controller to open, especially the first initial view which includes a lot of images.
I took a look at apple sample
but I cannot re-work the whole application, what I want is just to tell me specifically what should I do?, I implement?
in the tableview, where the cell is implemented cellforrowatindexpath:
NSURL *imageURL = ......;
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *imageLoad;
imageLoad = [[UIImage alloc] initWithData:imageData];
imageView.image = imageLoad;
could I do something?
thank you for your help!
Try this code:
dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(q, ^{
/* Fetch the image from the server... */
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[UIImage alloc] initWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
/* This is the main thread again, where we set the tableView's image to
be what we just fetched. */
cell.imgview.image = img;
});
});
Yes, you can add placeholder image to it.
It will not slow down the scrolling and will load image accordingly with time.
Also import this file UIImageView+WebCache.m and MapKit Framework
Here is the link to download the files.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
UIImageview* iV = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 50, 50)];
[iV setImageWithURL:[NSURL URLWithString:url] placeholderImage:[UIImage imageNamed:#"image_placeholder.gif"]];
[cell.contentView addSubview:iV];
[iV release];
}
Just clean, build and run.
To enable the app while getting the images from server and disable block while loading the images try to use UIImageView+AFNetworking library to load the image from server asynchronously AFNetworking
NSString *imageUrl = [[dict objectForKey:#"photo"] objectForKey:#"url"];
UIImageView *myImage = [[UIImageView alloc] init];
[myImage setImageWithURL:[NSURL URLWithString:imageUrl] placeholderImage:[UIImage imageNamed:#"PlaceHolder.png"]];
Just add this library and include the UIImageView+AFNetworking so you can use the new UIImageView Category imageWithUrl
Take a look at this control:
https://github.com/nicklockwood/AsyncImageView
It's very easy to implement (only 1 header file) and will suit your needs just fine.
Using this control:
Instead of declaring:
NSURL *imageURL = ......;
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *imageLoad;
imageLoad = [[UIImage alloc] initWithData:imageData];
imageView.image = imageLoad;
Use:
NSURL *imageURL = ......;
imageView.imageURL = imageURL;
you can check this tutorial on NSOperationQueue and this on GCD doing exactly same. Also you can try using:
// Block variable to be assigned in block.
__block NSData *imageData;
dispatch_queue_t backgroundQueue = dispatch_queue_create("com.razeware.imagegrabber.bgqueue", NULL);
// Dispatch a background thread for download
dispatch_async(backgroundQueue, ^(void) {
imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *imageLoad;
imageLoad = [[UIImage alloc] initWithData:imageData];
// Update UI on main thread
dispatch_async(dispatch_get_main_queue(), ^(void) {
imageView.image = imageLoad;
});
});
You can try something like this!....
dispatch_queue_t checkInQueueForPostImage = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(checkInQueueForPostImage, ^{
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:postAndCheckInDetails.postImageURL]]];
dispatch_sync(dispatch_get_main_queue(), ^{
if (image!=nil) {
[uploadImage setImage:image];
}
[cell setNeedsLayout];
});
});
Here is a slightly modified approach of Ramu Pasupoletis answer. I added the
__block
modifier to make the var img visible inside the block called on the main thread. Here is the complete method definition which I use in
-(UITableViewCell*)cellforRowAtIndexPath:(UIIndexPath*)indexPath;
for fetching the thumbnails lazily. I also added placeholders there for the cells UIImageViews.
//lazy loading of thumbnails for images in cell via bg thread
-(void)loadImageForCell:(CustomEditTableViewCell*)theCell withFilepath: (NSString*)filepath{
dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(q, ^{
UIImage (__block *img) = [UIImage imageWithContentsOfFile:filepath];
UIImage *thumbnail = [[GlobalFunctions sharedGlobalFunctions] imageOfSize:CGSizeMake(40, 40) fromImage:img];
dispatch_async(dispatch_get_main_queue(), ^{
theCell.imageView.image = thumbnail;
});
});
}
Use IDAsyncImageView.h
//////////////////////////////////////
IDAsyncImageView.h
/////////////////////////////////////
#interface IDAsyncImageView : NSObject
#property (nonatomic, strong) NSCache *cache;
+ (instancetype)instance;
- (void)loadImageView:(UIImageView*)imageView withURLString:(NSString *)urlString;
#end
//////////////////////////////////////
IDAsyncImageView.m
/////////////////////////////////////
#import "IDAsyncImageView.h"
#implementation IDAsyncImageView
+ (instancetype)instance
{
static IDAsyncImageView *_instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
});
return _instance;
}
- (instancetype)init
{
self = [super init];
if (self) {
self.cache = [[NSCache alloc] init];
}
return self;
}
- (void)loadImageView:(UIImageView*)imageView withURLString:(NSString *)urlString
{
UIActivityIndicatorView* activityView;
activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityView.hidesWhenStopped = YES;
activityView.center = CGPointMake(imageView.bounds.size.width / 2.0f, imageView.bounds.size.height / 2.0f);
activityView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
[imageView addSubview:activityView];
[activityView startAnimating];
UIImage* imageLoad = [self.cache objectForKey:urlString];
if (nil != imageLoad) {
imageView.image = imageLoad;
[activityView removeFromSuperview];
}
else {
// Block variable to be assigned in block.
__block NSData *imageData;
// Dispatch a background thread for download
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]];
UIImage* imageLoad = [[UIImage alloc] initWithData:imageData];
// Update UI on main thread
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self.cache setObject:imageLoad forKey:urlString];
imageView.image = imageLoad;
[activityView removeFromSuperview];
});
});
}
}
//////////////////////////////////////
ViewController.m
//////////////////////////////////////
- (void)viewDidLoad {
[super viewDidLoad];
[[IDAsyncImageView instance] loadImageView:myImageView withURLString:aUrl];
}
You can use async imageview.
- (void) loadImageFromURL:(NSURL*)url placeholderImage:(UIImage*)placeholder cachingKey:(NSString*)key {
self.imageURL = url;
self.image = placeholder;
NSData *cachedData = [FTWCache objectForKey:key];
if (cachedData) {
self.imageURL = nil;
self.image = [UIImage imageWithData:cachedData];
return;
}
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *imageFromData = [UIImage imageWithData:data];
[FTWCache setObject:data forKey:key];
if (imageFromData) {
if ([self.imageURL.absoluteString isEqualToString:url.absoluteString]) {
dispatch_sync(dispatch_get_main_queue(), ^{
self.image = imageFromData;
});
} else {
// NSLog(#"urls are not the same, bailing out!");
}
}
self.imageURL = nil;
});
}
Take a look at this link.You will have an idea on using async imageview.

Help me understand leaks on this code: [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to release an object declared into a method and passed to another method?
Can you help me fix leaks in this code:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
UIImage *payload = [[UIImage alloc] initWithData:self.activeDownload];
UIImage *picture = [[UIImage alloc] init];
if (payload.size.width != kAppIconHeight && payload.size.height != kAppIconHeight)
{
CGSize itemSize = CGSizeMake(kAppIconHeight, kAppIconHeight);
UIGraphicsBeginImageContext(itemSize);
CGRect imageRect = CGRectMake(0.0, 0.0, itemSize.width, itemSize.height);
[payload drawInRect:imageRect];
picture = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
else
{
picture = payload;
}
self.activeDownload = nil;
[payload release];
self.imageConnection = nil;
[delegate ThumbDidLoad:self.indexPathInTableView Image:[picture autorelease]];
}
Thx for helping,
Stephane
When you set picture = UIGraphicsGetImageFromCurrentImageContext() in your if statement or picture = payload in your else statement, you are loosing the pointer to the previously allocated UIImage you assigned in picture in the first lines, but you never released it.
You shouldn't alloc+init a new UIImage for picture, as you never use it and assign a new value to this variable later... but never used and released the previously allocated one.
UIImage *picture = [[UIImage alloc] init]; and picture = UIGraphicsGetImageFromCurrentImageContext();
You should not initialize picture at the beginning of the code. UIGraphicsGetImageFromCurrentImageContext returns a already initialized UIImage (autoreleased).
UIImage *payload = [[UIImage alloc] initWithData:self.activeDownload];, picture = payload;, [payload release];.
You should use [payload autorelease] instead, otherwise you're releasing the image without ever using it.
[delegate ThumbDidLoad:self.indexPathInTableView Image:[picture autorelease]];
You should remove [picture autorelease] and just use picture.
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
UIImage *payload = [[UIImage alloc] initWithData:self.activeDownload];
UIImage *picture;
if (payload.size.width != kAppIconHeight && payload.size.height != kAppIconHeight)
{
CGSize itemSize = CGSizeMake(kAppIconHeight, kAppIconHeight);
UIGraphicsBeginImageContext(itemSize);
CGRect imageRect = CGRectMake(0.0, 0.0, itemSize.width, itemSize.height);
[payload drawInRect:imageRect];
picture = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
else
{
picture = payload;
}
[payload autorelease];
self.activeDownload = nil;
self.imageConnection = nil;
[delegate ThumbDidLoad:self.indexPathInTableView Image:picture];
}

displaying images in fix size

in my application images are loaded from rss feed in table cell. they are of variant size how can i fix them to certain size. my code is
int blogEntryIndex1 = [indexPath indexAtPosition: [indexPath length] -1];
imgstring=[[blogEntries objectAtIndex: blogEntryIndex1] objectForKey: #"image"];
NSURL *url = [NSURL URLWithString:imgstring];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[UIImage alloc] initWithData:data];
cell.imageView.image=img;
you can view my application screen shot click here
Thanks i will be waiting for your response....
I think I understand what your'e asking...
What you want to do is to resize UIImages.
UIImage* resizeImageToSize(UIImage* image, CGSize size)
{
UIGraphicsBeginImageContext(size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
//Account for flipped coordspace
CGContextTranslateCTM(ctx, 0.0, size.height);
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextDrawImage(ctx,CGRectMake(0.0f, 0.0f, size.width, size.height), image.CGImage);
UIImage* scaled = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return scaled;
}

Xcode iPhone Programming: Loading a jpg into a UIImageView from URL

My app has to load an image from a http server and displaying it into an UIImageView
How can i do that??
I tried this:
NSString *temp = [NSString alloc];
[temp stringwithString:#"http://192.168.1.2x0/pic/LC.jpg"]
temp=[(NSString *)CFURLCreateStringByAddingPercentEscapes(
nil,
(CFStringRef)temp,
NULL,
NULL,
kCFStringEncodingUTF8)
autorelease];
NSData *dato = [NSData alloc];
dato=[NSData dataWithContentsOfURL:[NSURL URLWithString:temp]];
pic = [pic initWithImage:[UIImage imageWithData:dato]];
This code is in viewdidload of the view but nothing is displayed!
The server is working because i can load xml files from it. but i can't display that image!
I need to load the image programmatically because it has to change depending on the parameter passed!
Thank you in advance.
Antonio
It should be:
NSURL * imageURL = [NSURL URLWithString:#"http://192.168.1.2x0/pic/LC.jpg"];
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage * image = [UIImage imageWithData:imageData];
Once you have the image variable, you can throw it into a UIImageView via it's image property, ie:
myImageView.image = image;
//OR
[myImageView setImage:image];
If you need to escape special characters in your original string, you can do:
NSString * urlString = [#"http://192.168.1.2x0/pic/LC.jpg" stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
NSURL * imageURL = [NSURL URLWithString:urlString];
....
If you're creating your UIImageView programmatically, you do:
UIImageView * myImageView = [[UIImageView alloc] initWithImage:image];
[someOtherView addSubview:myImageView];
[myImageView release];
And because loading image from URL takes ages, it would be better to load it asynchronously. The following guide made it stupid-simple for me:
http://www.switchonthecode.com/tutorials/loading-images-asynchronously-on-iphone-using-nsinvocationoperation
Try this
NSURL *url = [NSURL URLWithString:#"http://192.168.1.2x0/pic/LC.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImageView *subview = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f,320.0f, 460.0f)];
[subview setImage:[UIImage imageWithData:data]];
[cell addSubview:subview];
[subview release];
All the Best.
This is the actual code.
UIImageView *myview=[[UIImageView alloc]init];
myview.frame = CGRectMake(0, 0, 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];
You should load the image in the background or the view will freeze.
Try this:
UIImage *img = [[UIImage alloc] init];
dispatch_async(dispatch_get_global_queue(0,0), ^{
NSData * data = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString:#"http://www.test.com/test.png"];
img = [UIImage imageWithData: data];
dispatch_async(dispatch_get_main_queue(), ^{
//PUT THE img INTO THE UIImageView (imgView for example)
imgView.image = img;
});
});