Am having UITableView and i need to list my saved images from document directory am using the code NSArray *sysPaths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES );
NSString *docDirectory = [sysPaths objectAtIndex:0];
dispatch_queue_t queue_=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue_, ^{
NSString *filePath=[docDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"MyFolder_New/%#",[[[tableArray objectAtIndex:indexPath.row] componentsSeparatedByString:#"/"] lastObject]]];
dispatch_async(dispatch_get_main_queue(), ^{
[img setImage:[UIImage imageWithData:[NSData dataWithContentsOfFile:filePath]]];
[indicator stopAnimating];
});
}); for displaying images Asynchronously into UITableView but the UITableView is lagging while scrolling to top and bottom.
You need use dispatch_asynch in method tableView:cellForRowAtIndexPath: when you customize cell before return.
Steps:
1. get cell from pool.
2. customise it.
3. start dispatch_asynch, what will set correct image (this need check if cell is still same) to cell.
We do it all time and we never have lags. But images appear in cells with delay (it is correct). Try it.
Related
I need to load image from server(url) to UITableView. So i tired below code, but no use.
UIImageView *img=[[UIImageView alloc]init];
img.frame=fr;
img.image=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:countimg]]];
[cell.contentView addSubview:img];
Here countimg is NSMutableArray. countimg contains url of all images to load. But its not working, because its not a string variable. I don't know how to change NSMutuableArray to String.
Anyone help me.
You can get string urls from countimg array like this,
[countimg objectAtIndex:index];
Where index is an integer of range between >=0 && < [countimg count]
Now if you're using countimg array in UITableView delegate then, you've replace index variable with indexPath.row.
So for now your code would look like this,
UIImageView *img=[[UIImageView alloc]init];
img.frame=fr;
img.image=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[countimg objectAtIndex:indexPath.row]]]]; //note this
[cell.contentView addSubview:img];
Update:
As #DavidAtkinson, suggestion, you should not use dataWithContentsOfURL method to load a NSURL to download a image. As its perform in main thread and will stuck the UI until download would not completes. Its better to load image in background.
Also, there's some asynchronous UIImageView's available, one which I am using is SDWebImage.
Use SDWebImage to load your image from server. here using this library you can put placeholder image in tableview cell's image view till the image loaded. You can even cache your image by just doing a single line code
[UIImageView setImageWithUrl:[pass your URL here] placeholderImage:[pass name of placeholder image] options:SDWebImageRefreshCached]
If you are trying to load your images from URL into a tableview,the SDWebImage code from Github does not specify how to do that.You have to create an object at index,then load the object for key name from the file you are parsing from.This will require you to change the SDWebImage code so that instead of parsing directly from a specific url,its parsing from
an object key name that contains an image url from your json or xml file.
Here is a sample code for loading an image from an object key in a json:
NSURL* url = [NSURL URLWithString:[dictionaryObject valueForKey:#"yourfile"]];
NSData *data = [NSData dataWithContentsOfURL:url];
dispatch_sync(dispatch_get_main_queue(), ^{
UIImageView *imgViewThumb=[[UIImageView alloc]initWithFrame:imgView.frame];
[imgViewThumb setImage:[UIImage imageWithData:data]];
[cell addSubview:imgViewThumb];
This problem has completely stumped me. This is for iOS 5.0 with Xcode 4.2
What's going on is that in my app I let user select images from their photo album and I save those images to apps document directory. Pretty straight forward.
What I do then is that in one of the viewController.m files I create multiple UIImageViews and I then set the image for the image view from one of the picture that user selected from apps dir. The problem is that after a certain number of UIImage sets I receive a "Received memory warning". It usually happens when there are 10 pictures. If lets say user selected 11 pictures then the app crashes with Error (GBC). NOTE: each of these images are at least 2.5 MB a piece.
After hours of testing I finally narrowed down the problem to this line of code
[button1AImgVw setImage:image];
If I comment out that code. All compiles fine and no memory errors happen. But if I don't comment out that code I receive memory errors and eventually a crash. Also note it does process the whole CreateViews IBAction but still crashes at the end. I cannot do release or dealloc since I am running this on iOS 5.0 with Xcode 4.2
Here is the code that I used. Can anyone tell me what did I do wrong?
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self CreateViews];
}
-(IBAction) CreateViews
{
paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask ,YES);
documentsPath = [paths objectAtIndex:0];
//here 15 is for testing purposes
for (int i = 0; i < 15; i++)
{
//Lets not get bogged down here. The problem is not here
UIImageView *button1AImgVw = [[UIImageView alloc] initWithFrame:CGRectMake(10*i, 10, 10, 10)];
[self.view addSubview:button1AImgVw];
NSMutableString *picStr1a = [[NSMutableString alloc] init];
NSString *dataFile1a = [[NSString alloc] init];
picStr1a = [NSMutableString stringWithFormat:#"%d.jpg", i];
dataFile1a = [documentsPath stringByAppendingPathComponent:picStr1a];
NSData *potraitImgData1a =[[NSData alloc] initWithContentsOfFile:dataFile1a];
UIImage *image = [[UIImage alloc] initWithData:potraitImgData1a];
// This is causing my app to crash if I load more than 10 images!
// [button1AImgVw setImage:image];
//If I change this code to a static image. That works too without any memory problem.
button1AImgVw.image = [UIImage imageNamed:#"mark-yes.png"]; // this image is less than 100KB
}
NSLog(#"It went to END!");
}
This is the error I get when 10 images are selected. App does launch and work
2012-10-07 17:12:51.483 ABC-APP[7548:707] It went to END!
2012-10-07 17:12:51.483 ABC-APP [7531:707] Received memory warning.
App crashes with this error when there are 11 images
2012-10-07 17:30:26.339 ABC-APP[7548:707] It went to END!
(gbc)
This situation (memory warnings and application quitting while attempting to load multiple full resolution UIImages into a view) has attempted to burn me a couple times in my iOS programming career.
You need to make a shrinked down copy of your original image before doing the "setImage" call.
For my own code, I use the "UIImage+Resize" category, the details for which can be found here.
Resize your image to something smaller before inserting into your view, then make sure the full resolution image is released (or set to nil if on ARC) and you should have a happier time of things.
Here is how I do it in my own code:
CGSize buttonSize = CGSizeMake(width, height);
// it'd be nice if UIImage took a file URL, huh?
UIImage * newImage = [[UIImage alloc] initWithContentsOfFile: pathToImage];
if(newImage)
{
// this "resizedimage" image is what you want to pass to setImage
UIImage * resizedImage = [newImage resizedImage: buttonSize interpolationQuality: kCGInterpolationLow];
}
I have a table view that displays a list of users. The avatar images in each cell are downloaded asynchronously using UIImageView+AFNetworking and displayed using UIImage+TPAdditions. Here is my code snippet, from cellForRowAtIndexPath:
if (cell==nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:SimpleTableIdentifier];
}
cell.textLabel.text = [[global.people objectAtIndex:indexPath.row]name];
// setImageWithUrl:placeholderImage: is taken from UIImageView+AFNetworking
NSString* imgURL = [[global.people objectAtIndex:indexPath.row]avatar_url];
UIImageView* imgV = [[UIImageView alloc]init];
[imgV setImageWithURL:[NSURL URLWithString:imgURL] placeholderImage:[UIImage imageNamed:#"icon.png"]];
//These are just for formatting and are taken from UIImage+TPAdditions
cell.imageView.image = [imgV.image imageScaledToSize:CGSizeMake(43,43)];
cell.imageView.layer.masksToBounds = YES;
cell.imageView.layer.cornerRadius = 5.0;
Now when the app loads we just see the placeholder images until the user scrolls the tableview up and down. Then the avatar images from the URLs are loaded into each cell's image view. I want to make it so that this scrolling is not required- I want the avatar images to "pop" into their respective cells' tableviews as soon as they are downloaded. I know NSNotification might help me, but I'm not really sure where/how to use that. I'm fairly new to iOS. Can anyone walk me through it?
Thanks
You'll want to call setNeedsDisplay on your view to force a refresh. You would call this in your asynchronous call's completion handler.
Currently, I'm working on the client for the website. I have tonne of images that I need to load to my TableView. Here is what I'm currectly doing:
NSDictionary *propertyItems = [self.items objectAtIndex:indexPath.row];
cell.fio.font = [UIFont boldSystemFontOfSize:17.0f];
if([propertyItems objectForKey:#"online"] == [NSNumber numberWithInt:1])
cell.fio.textColor = [UIColor colorWithRed:0.3 green:0.6 blue:0.3 alpha:1.0];
dispatch_queue_t downloadPhotosQueue = dispatch_queue_create("downloadPhotosQeue", NULL);
dispatch_async(downloadPhotosQueue, ^{
NSData *photosData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://www.example.com/%#", [propertyItems objectForKey:#"photo_trumb"]]]];
dispatch_async(dispatch_get_main_queue(), ^{
cell.pic.image = [UIImage imageWithData:photosData];
});
});
cell.fio.text = [propertyItems objectForKey:#"fio"];
I'm doing this in cellForRowAtIndexPath: method.
Everything is loading fast. But the problem is, when I'm scrolling my table down, and after again up, the images are reloading over and over again.
Question: Is there any way to easily cache my UIImages that I'm getting from the server? So if they are loaded once, they wouldn't reload over and over again, while I'm running the app. Maybe I'm doing something wrong?
Thanks in advance!
I strongly recommend AsyncImageView. I use it and it works like a charm. Just set the image url and it handles everything itself.
AsyncImageView *imageView = [[AsyncImageView alloc]init];
imageView.imageURL = [NSURL URLWithString:#"https://www.google.es/logos/classicplus.png"];
It caches the image in memory so it won't retrieve it from the server again. It will also release them when receiving a memory warning.
To load image from a website I use AFNetworking. It provides a class to load an image from an URL:
Start by adding #import "UIImageView+AFNetworking" to the top of a
controller or a view implementation file. This category adds methods
to UIImageView, like:
[imageView setImageWithURL:[NSURL URLWithString:#"…"]];
i recommend this library to accomplish what you want.
in cellForRowAtIndexPath:
[cell.imageView setImageWithURL:
[NSURL URLWithString:[NSString stringWithString:#"www.yourimagepath.path"]]
placeholderImage:[UIImage imageNamed:#"no_image.jpg"]];
the library will cache the image for you. you can also set the setHolder of the image, so it wont look like a blank image while the images are downloading.
The problem is here :
NSData *photosData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://www.example.com/%#", [propertyItems objectForKey:#"photo_trumb"]]]];
dataWithContentsOfURL
It launch a request to the Url everytime the function is called (everytime you scrolled).
You need to load all the picture before cellForRowAtIndexPath.
Like in ViewDidLoad.
You can just store them in an array and display your picture's array in cellForRowAtIndexPath.
If it's really fast to load like you say : jsut load picture Once in CellForRowAtIndexPath. Store them in a mutableArray. And check if the picture already exist .
in the UITableView that have some cells, and each cell have tow UIImage, and i will update the UIImage asynch for performance. but there is a question, how can i only reload the UIImageView in cell when a image pulled from the Web.
i kown can reload a whole cell with methoed "reloadRowsAtIndexPaths", but i just want to kown is there have a method can only reload the UIView object which is necessary to be reload (i.e. a image or a label) in the cell.
BTW, i found the methoed "reloadRowsAtIndexPaths" will execute the method "heightForRowAtIndexPath" for all cells when i just reload one cell. is there anything wrong?
Maybe the sample code LazyTableImages from apple is what you want.
Get a reference to your custom cell calling tableView:cellForRowAtIndexPath:. Then update its image property running this:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSData *imageData = [NSData dataWithContentsOfURL:someURL];
dispatch_async(dispatch_get_main_queue(), ^{
cell.someImage = [UIImage imageWithData:imageData];
});
});
You'll be loading at most 6 images concurrently because that's the limit of NSURLConnection.