I am using SDWebImage for fetching images from server to my table view app in IOS.
But the problem is that when I scroll down in table view instead of waiting for the images to load it put the images downloaded in the first few rows of table view and repeat those images till the end row and when it downloads the images it changes those repeated images to the actual image for that row.
NSURL * url = [NSURL URLWithString:string];
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadImageWithURL:url
options:0
progress:^(NSInteger receivedSize, NSInteger expectedSize)
{
// progression tracking code
}
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished,NSURL * url)
{
if (finished && image )
{
NSArray *visibleIndexPaths = [tableView indexPathsForVisibleRows];
if ([visibleIndexPaths containsObject:indexPath]) {
cell.myImage.image = image;
}
}
}];
Actually, it is not a bug with SDWebImage, but rather it's the nature of how UITableView works. downloadImageWithURL, is an async process,so when your tableView delegate/datasource methods are called, the image isn't downloaded yet, therefore cellForRow doesn't have an image to display.
To overcome this issue you should first check image from cache as
[[SDWebImageManager sharedManager] diskImageExistsForURL:[NSURL URLWithString:ImageUrl]]
if yes then set image to UIImageView otherwise use downloadImageWithURL to download image and add cell tag(To display image to correct row) as
cell.tag = indexPath.row;
on successfull download first check correct row as
if(cell.tag == indexPath.row){
and set image to UIImageView.Here is setImage method.
-(void)setImage:(SLFirstTableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath{
SLFirstTableViewCellItem * slFirstTableViewCellItem = [self.categories objectAtIndex:indexPath.row]; // categories is array of items,replace with yours.
NSString *ImageUrl = slFirstTableViewCellItem.imageUrl; //assume image url is in slFirstTableViewCellItem object.
cell.tag = indexPath.row;
if([[SDWebImageManager sharedManager] diskImageExistsForURL:[NSURL URLWithString:ImageUrl]]){
[cell.imgItem setImage: [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:ImageUrl]];
[self hideProgressView:cell];
}else{
[self showProgressView:cell];
[SDWebImageDownloader.sharedDownloader downloadImageWithURL:[NSURL URLWithString:ImageUrl]
options:0
progress:^(NSInteger receivedSize, NSInteger expectedSize)
{
// progression tracking code
}
completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished)
{
if (image && finished)
{
[[SDImageCache sharedImageCache] storeImage:image forKey:ImageUrl]; // cache image
if(cell.tag == indexPath.row){ // check if correct row
[cell.imgItem setImage:image];
[self hideProgressView:cell];
}
}else{
cell.imgItem.hidden = YES;
cell.progressBar.hidden = YES;
}
}];
}
}
And define showProgressView and hideProgressView methods as
-(void)showProgressView:(SLFirstTableViewCell *)cell {
cell.progressText.hidden = NO;
cell.progressBar.hidden = NO;
cell.imgItem.hidden = YES;
[cell.progressBar startAnimating];
[cell.progressText setText:#"Loading Image..."];
}
-(void)hideProgressView:(SLFirstTableViewCell *)cell{
cell.progressBar.hidden = YES;
cell.progressText.hidden = YES;
cell.imgItem.hidden = NO;
[cell.progressBar stopAnimating];
}
finally call setImage from cellForRowAtIndexPath method(before returning cell) as
[self setImage:cell atIndexPath:indexPath];
Related
my replaceObjectatIndex:withObject: is not being called when I put it inside a block. I know this because when I NSLog in the outer block the value doesn't change. why is the method inside the inner block not being called while the method in the outer block does? what's the difference?
this is the code:
if (cell.selected) {
[[SDImageCache sharedImageCache] queryDiskCacheForKey:imageID
done:^(UIImage *image, SDImageCacheType cacheType)
{
// image is not nil if image was found
if (image == nil) {
//image is not found
[SDWebImageDownloader.sharedDownloader downloadImageWithURL:[NSURL URLWithString:link]
options:0
progress:^(NSInteger receivedSize, NSInteger expectedSize)
{
// progression tracking code
}
completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished)
{
if (image && finished)
{
// image is finished being downloaded
// resize image
UIImage *resizedImage = [self imageWithImage:image forRowAtIndexPath:indexPath];
// store resized image in cache
[[SDImageCache sharedImageCache] storeImage:resizedImage forKey:imageID];
//set image view to resized image
[textCell.testImage setImage:resizedImage];
[self.heightArray replaceObjectAtIndex:indexPath.row
withObject:[NSNumber numberWithFloat:image.size.height]];
}
//delete original sized image
image = nil;
}];
} else {
//image is found
[textCell.testImage setImage:image];
NSLog(#"image found %#", [self.heightArray objectAtIndex:indexPath.row]);
}
}];
} else {
//cell is not selected
textCell.testImage.image = nil;
}
By the way, the setImage: method works perfectly but not replaceObjectatIndex:withObject:
I don't know what you are doing but I found an issue in your code: you are using the image even after you set it to nil.
Correction:
//delete original sized image -
//??image = nil;
[self.heightArray replaceObjectAtIndex:indexPath.row
withObject:[NSNumber numberWithFloat:image.size.height]];
image = nil;
I have a class method which fetches images with a completion block. This fetched UIImage is added to an NSCache with a relevant key. This seems to work as expected, however, in the method which fetches images I am using a UIImage's imageWithData: method, which I have discovered does not cache it's data, only imageNamed: does.
I am understandably getting memory warnings because of this, how do I make sure the images loaded with UIImage's imageWithData: method are removed from memory when not needed anymore?
EDIT
Here is the code for the method which downloads the images.
- (void)imageForFootageSize:(FootageSize)footageSize withCompletionHandler:(void (^)(UIImage *image))completionBlock
{
if (completionBlock) {
__block UIImage *image;
// Try getting local image from disk.
//
__block NSURL *imageURL = [self localURLForFootageSize:footageSize];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
image = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageURL]];
dispatch_async(dispatch_get_main_queue(), ^{
if (image) {
completionBlock(image);
} else {
//
// Otherwise try getting remote image.
//
imageURL = [self remoteURLForFootageSize:footageSize];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
dispatch_async(dispatch_get_main_queue(), ^{
image = [UIImage imageWithData:imageData];
if (image) {
//
// Save remote image to disk
//
NSURL *photoDirectoryURL = [Footage localURLForDirectory];
// Create the folder(s) where the photos are stored.
//
[[NSFileManager defaultManager] createDirectoryAtPath:[photoDirectoryURL path] withIntermediateDirectories:YES attributes:nil error:nil];
// Save photo
//
NSString *localPath = [[self localURLForFootageSize:footageSize] path];
[imageData writeToFile:localPath atomically:YES];
}
completionBlock(image);
});
});
}
});
});
}
}
EDIT 2
Methods which use the above class method to fetch and process the UIImage in the completionHandler.
Method inside UICollectionViewCell subclass.
- (void)setPhoto:(Photo *)photo withImage:(UIImage *)image
{
[self setBackgroundColor:[UIColor blackColor]];
[self.imageView setBackgroundColor:[UIColor clearColor]];
if (photo && !image) {
[photo imageForFootageSize:[Footage footageSizeThatBestFitsRect:self.bounds]
withCompletionHandler:^(UIImage *image) {
if ([self.delegate respondsToSelector:#selector(galleryPhotoCollectionViewCell:didLoadImage:)]) {
[self.delegate galleryPhotoCollectionViewCell:self didLoadImage:image];
}
image = nil;
}];
}
[self.imageView setImage:image];
BOOL isPhotoAvailable = (BOOL)(image);
[self.imageView setHidden:!isPhotoAvailable];
[self.activityIndicatorView setHidden:isPhotoAvailable];
}
Method in UICollectionView data source delegate
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
DIGalleryPhotoCollectionViewCell *photoCell = [collectionView dequeueReusableCellWithReuseIdentifier:photoCellIdentifier forIndexPath:indexPath];
[photoCell setDelegate:self];
Footage *footage = [self footageForIndexPath:indexPath];
Photo *photo = ([footage isKindOfClass:[Photo class]]) ? (Photo *)footage : nil;
if (photo) {
//
// Photo
//
[photoCell setPhoto:photo withImage:[self.galleryCache objectForKey:photo.footageID]];
}
return photoCell;
}
Here are the other relevant methods:
- (void)galleryPhotoCollectionViewCell:(DIGalleryPhotoCollectionViewCell *)cell didLoadImage:(UIImage *)image
{
NSIndexPath *indexPath = [self.galleryCollectionView indexPathForCell:cell];
Footage *footage = [self footageForIndexPath:indexPath];
if ([footage isKindOfClass:[Footage class]]) {
Photo *photo = (Photo *)footage;
UIImage *cachedImage = [self.galleryCache objectForKey:photo.footageID];
if (!cachedImage) {
cachedImage = image;
[self.galleryCache setObject:image forKey:photo.footageID];
}
[cell setPhoto:photo withImage:image];
}
}
And also my getter method for the NSCache property galleryCache
- (NSCache *)galleryCache
{
if (!_galleryCache) {
_galleryCache = [[NSCache alloc] init];
}
return _galleryCache;
}
Instead of rolling your own image downloading and caching solution you might be better off using SDWebImage. Then you don't have to worry about the downloading, caching or anything. SDWebImage also using disk caching so you don't have to worry about freeing memory.
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadWithURL:imageURL options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize)
{
// progression tracking code
} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished)
{
if (image)
{
// do something with image
}
}];
I'm not sure but you also might have a retain cycle:
__weak typeof(self) weakSelf = self;
[photo imageForFootageSize:[Footage footageSizeThatBestFitsRect:self.bounds] withCompletionHandler:^(UIImage *image) {
if ([weakSelf.delegate respondsToSelector:#selector(galleryPhotoCollectionViewCell:didLoadImage:)])
{
[weakSelf.delegate galleryPhotoCollectionViewCell:weakSelf didLoadImage:image];
}
image = nil;
}];
I'm using AFNetworking to parse JSON to my app (using Rails as my backend). Right now my app is very slow so I'm trying to figure out a way to make it smoother. When I first load the app it takes a few seconds for it to populate (it shows the Nav items and a white page, then a few seconds later my "posts" appear).
Collection View Controller
- (void)viewDidLoad
{
[super viewDidLoad];
self.upcomingReleases = [[NSMutableArray alloc] init];
[self makeReleasesRequests];
[self.collectionView registerClass:[ReleaseCell class] forCellWithReuseIdentifier:#"ReleaseCell"];
}
-(void)makeReleasesRequests
{
NSURL *url = [NSURL URLWithString:#"http://www.soleresource.com/upcoming.json"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"#");
self.upcomingReleases = [responseObject objectForKey:#"upcoming_releases"];
[self.collectionView reloadData];
} failure:nil];
[operation start];
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [self.upcomingReleases count];
}
#pragma mark - Show upcoming release shoe
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = #"Cell";
ReleaseCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
NSDictionary *upcomingReleaseDictionary = [self.upcomingReleases objectAtIndex:indexPath.row];
NSString *thumbURL = nil;
cell.release_name.text = [NSString stringWithFormat:#"%# — $%#",[upcomingReleaseDictionary objectForKey:#"release_name"], [upcomingReleaseDictionary objectForKey:#"release_price"]];
if ([upcomingReleaseDictionary[#"images"] isKindOfClass:[NSArray class]] && [upcomingReleaseDictionary[#"images"] count]) {
thumbURL = upcomingReleaseDictionary[#"images"][0][#"image_file"][#"image_file"][#"thumb"][#"url"];
if (thumbURL)
{
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:thumbURL]];
UIImage *image = [UIImage imageWithData:imageData];
cell.thumb.image = image;
}
}
else {
cell.thumb.image = [UIImage imageNamed:#"air-jordan-5-fear.png"];
}
return cell;
}
Each of my posts has a text string and a image. Is there a way to load the text so that it appears right away and then load my image? Or is there another way to speed up my app load speed (Maybe loadin a certain of posts first and then loading the rest - the ones that the user cant see until they scroll down).
Thanks.
You should load your image lazily and asynchronously (DON'T block main thread) when coming from server. (AFNetworking already has caching category method on UIImageView. (Check out this for more)
if (thumbURL)
{
[cell.thumb setImageWithURL:[NSURL URLWithString:thumbURL] placeholderImage:[UIImage imageNamed:#"air-jordan-5-fear.png"]];
}
EDIT -
Ensure to pull UIKit+AFNetworking folder into your project and #import "UIKit+AFNetworking.h" into your .m file. The link to download complete AFNetworking can be found here and documentation specific to this question here.
Your problem is this:
if (thumbURL)
{
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:thumbURL]];
UIImage *image = [UIImage imageWithData:imageData];
cell.thumb.image = image;
}
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:thumbURL]];
UIImage *image = [UIImage imageWithData:imageData];
You should never be getting data in cellForItemAtIndexPath:. You should only be displaying what you have already. Your code makes it so no cell is returned until a thumbnail is downloaded. You can measure this using the Time Profiler in Instruments.
I'm assuming thumb is a UIImageView. Try this:
if (thumb) {
[thumb setImageWithURL:[NSURL URLWithString:#"http://i.imgur.com/r4uwx.jpg"]];
}
This method, also included with AFNetworking, will download the image, and update it in the cell once it's done downloading. Documentation and other similar methods are here.
here is my issue :
I have a UITableView containing custom UITableViewCells. Each of those UITableViewCell (called HomePicCell) is associated to a Pic object which has a property pointing to an image URL.
As soon as my cell is displayed, I start downloading this image using SDWebImage manager.
Everything is working smoothly, but after 20 to 80 seconds, some threads start hogging the CPU. The device then become a perfect hand heater for those cold winter nights, but I'd rather skip this feature for now !
I can't really put my finger on what would cause this issue. I don't think a retain loop would be the problem as it would only hog the memory. An experimented opinion would really help.
Here is my code :
UITableView Datasource
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString* cellIdentifier = [#"HomePicCell" stringByAppendingString:[Theme sharedTheme].currentTheme];
HomePicCell* cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[HomePicCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
if(self.pics.count>0){
Pic* pic = self.pics[indexPath.section];
[cell configureWithPic:pic];
}
return cell;
}
HomePicCell (configureWithPic:)
- (void)configureWithPic:(Pic*)pic
{
self.pic = pic;
// Reinit UI
[self.progressView setHidden:NO];
[self.errorLabel setHidden:YES];
[self.photoImageView setAlpha:0];
[self.progressView setProgress:0];
[self.pic downloadWithDelegate:self];
}
Pic
- (void) downloadWithDelegate:(id<PicDownloadDelegate>)delegate
{
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadWithURL:self.url options:0 progress:^(NSUInteger receivedSize, long long expectedSize) {
if(expectedSize>0){
float progress = [#(receivedSize) floatValue]/[#(expectedSize) floatValue];
[delegate pic:self DownloadDidProgress:progress];
}
} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) {
self.isGif = #(image.images.count>1);
if(image){
if(cacheType == SDImageCacheTypeNone){
[delegate pic:self DownloadDidFinish:image fromCache:NO];
}else{
[delegate pic:self DownloadDidFinish:image fromCache:YES];
}
}else{
[delegate pic:self DownloadFailWithError:error];
}
}];
}
HomePicCell (delegate methods)
- (void)pic:(Pic*)pic DownloadDidFinish:(UIImage *)image fromCache:(BOOL)fromCache
{
if(![pic isEqual:self.pic]){
return;
}
[self.progressView setHidden:YES];
self.photoImageView.image = image;
[self updateUI];
}
- (void)pic:(Pic*)pic DownloadFailWithError:(NSError *)error
{
if(![pic isEqual:self.pic]){
return;
}
[self.errorLabel setHidden:NO];
[self.progressView setHidden:YES];
}
- (void)pic:(Pic*)pic DownloadDidProgress:(float)progress
{
if(![pic isEqual:self.pic]){
return;
}
[self.progressView setProgress:progress+.01f];
}
Thanks !
The issue is apparently fixed by switching to SDWebImage 3.0 (instead of 3.3).
I'll go ahead and declare an issue on the project github page to see if some people have had the same problem.
I'm using SDWebImage and grabbing Images associated with a news article from a news API.
The problem is, the images for the cells on screen aren't loading until I start scrolling on the UITableView. Once I scroll past a cell, and it goes off screen, once I come back to it the Image will finally be loaded.
Here is my (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath code:
if ([feedLocal.images count] == 0) {
[cell.imageView setImage:[UIImage imageNamed:#"e.png"]];
}
else {
Images *imageLocal = [feedLocal.images objectAtIndex:0];
NSString *imageURL = [NSString stringWithFormat:#"%#", imageLocal.url];
NSLog(#"img url: %#", imageURL);
// Here we use the new provided setImageWithURL: method to load the web image
__weak UITableViewCell *wcell = cell;
[cell.imageView setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#", imageURL]]
placeholderImage:[UIImage imageNamed:#"115_64.png"]
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {
if(image == nil) {
[wcell.imageView setImage:[UIImage imageNamed:#"115_64.png"]];
//];
}
}
];
}
Any idea why this would be happening? It just seems like when the UITableView loads, the Images aren't being told to load or something until scrolling begins?
Any suggestion is much appreciated, thanks!
There is little chance this will solve your problem, but this is too long to fit in a comment:
Tip 1:
If you are reusing cells, you should not do [wcell.imageView setImage:] in the callback. At the time the callback code is executed, there a non-null chance that wcell will point to a different cell in the table view than the one you wanted to change the image.
Instead, use the indexPath to refer to the cell you wanted to modify:
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {
if(image == nil) {
UITableViewCell *actualCell = [tableView cellForRowAtIndexPath:indexPath];
[actualCell.imageView setImage:[UIImage imageNamed:#"115_64.png"]];
}
}
Note that if the cell you wanted to change the image is not shown anymore, cellForRowAtIndexPath: will return nil, which is absolutely fine:
Return Value
An object representing a cell of the table or nil if the cell is not visible or indexPath is out of range.
Tip 2:
There is no need to re-create a string when you already have one ;)
[NSURL URLWithString:[NSString stringWithFormat:#"%#", imageURL]]
[NSURL URLWithString:imageURL] // imageURL is already a string
Your problem:
I'm a little bit puzzled, the code you showed really is a simple application of SDWebImage "how-to" examples, and I just tested with the v3.3 of the framework, and my cells update just fine. So try to reduce your code to the bare minimum to identify the real issue.
I'd say get rid of all your application logic (the feedLocal.images for example), and just find out if the problem actually comes from SDWebImage or not.
Not sure if you have solved your problem, but I get my problem solved by the following code.
Basic idea is to set the cell reference usable inside block and manually set the cell's image in the completed method. Hope it helps.
__block UITableViewCell *cell2 = cell;
id data = [[self itemArray] objectAtIndex:[indexPath item]];
if ([data isKindOfClass:[MyItems class]]) {
MyItems *myData = (MyItems *)data;
[[cell2 imageView] setImageWithURL:[myData url]
placeholderImage:[UIImage imageNamed:#"placeHolder.png"]
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {
// do check that this is the right cell to put your image
// your methods here
if (image) {
[[cell2 imageView] setImage:image];
}
}];
}
For the checking if that is the right cell, I guess it is something like this (I don't have time to check it)
__block UITableViewCell *cell2 = cell;
id data = [[self itemArray] objectAtIndex:[indexPath item]];
if ([data isKindOfClass:[MyItems class]]) {
__block MyItems *myData = (MyItems *)data;
[[cell2 imageView] setImageWithURL:[myData url]
placeholderImage:[UIImage imageNamed:#"placeHolder.png"]
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {
// do check that this is the right cell to put your image
// your methods here
id currentData = [[self itemArray] objectAtIndex:[indexPath item]];
if ([currentData isKindOfClass:[MyItems class]] && [ [[(MyItems *)currentData url] absoluteString] isEqualToString:[[myData url] absoluteString] ]) {
// it is the right cell to put in :)
if (image) {
[[cell2 imageView] setImage:image];
}
}
}];
}
I have earlier encountered a similar issue and it turned out the images in the tableview were downloading correctly. The real issue you are facing is the refresh issue. When each image is downloaded, it has to be refreshed in order to be shown in the tableview. In my case, the downloading part was done in a separate file, so i used NSNotificationCenter to tell the tableview controller class to refresh it. Here is what you can do with your code:
if ([feedLocal.images count] == 0) {
[cell.imageView setImage:[UIImage imageNamed:#"e.png"]];
}
else {
Images *imageLocal = [feedLocal.images objectAtIndex:0];
NSString *imageURL = [NSString stringWithFormat:#"%#", imageLocal.url];
NSLog(#"img url: %#", imageURL);
// Here we use the new provided setImageWithURL: method to load the web image
__weak UITableViewCell *wcell = cell;
[cell.imageView setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#", imageURL]]
placeholderImage:[UIImage imageNamed:#"115_64.png"]
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {
if(image == nil) {
[wcell.imageView setImage:[UIImage imageNamed:#"115_64.png"]];
[[NSNotificationCenter defaultCenter] postNotificationName:#"ImageDownloaded" object:nil];
//];
}
}
];
}
and then you can call reload data using it as below:
- (void) imageDownloaded:(NSNotification *)notification{
[self.tableView reloadData];
}
This way you don't need to scroll in order to see the image, instead they will be shown right after they are downloaded.
Hope this helps!
NSString *mainimg=[NSString stringWithFormat:#"%#",[[xmlDataDictionary valueForKeyPath:#"eg.main.img1"]objectAtIndex:indexPath.row]];
NSURL *url = [NSURL URLWithString:mainimg];
NSData *imge = [[NSData alloc] initWithContentsOfURL:url];
cell.img.image=[UIImage imageWithData:imge];