Dynamic image height in tableview with using sdwebimage - ios

I want dynamic height image show in tableview, image is come from url so I am using the sdwebimage.
Sdwebimage set image in background thread.
[self.imageView sd_setImageWithURL:[NSURL URLWithString: encodedurl1] completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
}];
I am update the constraint height of image view in this thread.
[self.imageView sd_setImageWithURL:[NSURL URLWithString: encodedurl1] completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
CGFloat multiplier = (CGRectGetWidth(self.imageView.bounds) / image.size.width);
[self.imageViewHeightConstraint setConstant:multiplier * image.size.height];
}];
This code is helpful for me but I get image size in background thread
So, I take a time to update the height of constraint image view
I am search and goggling last 2 days.
This type issue get many developer, but not answer in any question in stack overflow.

do the update in main thread like
[self.imageView sd_setImageWithURL:[NSURL URLWithString: encodedurl1] completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
dispatch_async(dispatch_get_main_queue(), ^{
CGFloat multiplier = (CGRectGetWidth(self.imageView.bounds) / image.size.width);
[self.imageViewHeightConstraint setConstant:multiplier * image.size.height];
[self setNeedsUpdateConstraints];
});
}];

Try this Helper method which created for my project.
-(void)imageWithURL:(NSURL *)imageurl WithIndexPath:(NSIndexPath *)indexpath WithCallback:(void(^)(UIImage *downloadedImage,BOOL isCache , NSIndexPath *imageIndexPath))callback{
if (![[SDWebImageManager sharedManager ]diskImageExistsForURL:imageurl]) {
[[SDWebImageManager sharedManager]downloadImageWithURL:imageurl options:0 progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
// resize image here
callback(image , NO,indexpath);
}];
}
else{
UIImage *image = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:[imageurl absoluteString]] ;
// resize image here
callback(image, YES ,indexpath);
}
}
Call this method in cellForRowAtIndexPath
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self imageWithURL:[NSURL URLWithString:objPreparations.strImageURL] WithIndexPath:indexPath WithCallback:^(UIImage *downloadedImage, BOOL isCache, NSIndexPath *imageIndexPath) {
if (downloadedImage) {
dispatch_async( dispatch_get_main_queue(), ^{
UITableViewCell *existcell = [tableView cellForRowAtIndexPath:imageIndexPath];
if (existcell) {
// assign image to cell here
[tableView reloadRowsAtIndexPaths:#[imageIndexPath] withRowAnimation:UITableViewRowAnimationNone];
}
});
}
}];
});
Dont Forgot
In viewDidLoad
tblView.estimatedRowHeight = 44.0 ;
tblView.rowHeight = UITableViewAutomaticDimension;
And also Give top,bottom,leading,trailing constraints to imageview and greater than equal height constraint to imageview

Related

Download image using SDWebImage, error -999 (or) SDWebImageErrorDomain Code=0 "Downloaded image has 0 pixels

I am unable to download the image in Objective c Using SDWebImage 4.4.5 version., I tried the following , nothing worked.
Try 1:
[self.thumbnailImageView sd_setImageWithURL:[NSURL URLWithString:thumbnailURLString] completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
}];
Try 2:
[self.thumbnailImageView sd_setImageWithURL:[NSURL URLWithString:thumbnailURLString] placeholderImage:nil options:SDWebImageRefreshCached completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { if(image != nil){
self.thumbnailImageView.image = image;
} else {
NSLog(#"Photo Not Available, fetch");
[self.thumbnailImageView sd_setImageWithURL:[NSURL URLWithString:thumbnailURLString] placeholderImage:nil options:SDWebImageRefreshCached completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
if(image != nil) { NSLog(#"Lo Res Image Loaded by %ld from '%#'", (long)cacheType, imageURL);
self.thumbnailImageView.image = image;
} else {
self.thumbnailImageView.image = nil;
} }];
} }];
Try 3:
[[SDWebImageDownloader sharedDownloader] downloadImageWithURL:[NSURL URLWithString:thumbnailURLString] options:SDWebImageDownloaderUseNSURLCache progress:nil completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
}];
Try 4:
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager loadImageWithURL:[NSURL URLWithString:thumbnailURLString] options:SDWebImageDelayPlaceholder progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
} completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
}];
Try 5:
SDWebImageDownloader *manager = [SDWebImageManager sharedManager].imageDownloader;
[manager setValue:#"application/vnd.learning.events.v1+json" forHTTPHeaderField:#"Accept"];
[manager setValue:#"en-US" forHTTPHeaderField:#"Accept-Language"];
[manager setValue:#"application/json; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
//[manager setValue:savedEmail forHTTPHeaderField:#"Email"];
[manager setValue:savedToken forHTTPHeaderField:#"Authorization"];
[manager downloadImageWithURL:[NSURL URLWithString:thumbnailURLString] options:SDWebImageDownloaderHighPriority progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
} completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
self.thumbnailImageView.image = image;
}];
In all the above cases, getting the following error:
Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLStringKey=https://thisisnotcorrecturl.net/api/BAImage?ActionFlagId=97&id=615, NSErrorFailingURLKey=https://thisisnotcorrecturl.net/api/BAImage?ActionFlagId=97&id=615, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask <92586538-B07D-46FB-8694-3B29AA3F0CB4>.<7>"
), _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <92586538-B07D-46FB-8694-3B29AA3F0CB4>.<7>, NSLocalizedDescription=cancelled}
Earlier, we used v3.5.4 version used, able to download the image with the following code. It's working good.
[self.thumbnailImageView setImageWithURL:[NSURL URLWithString:thumbnailURLString]
placeholderImage:nil
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {
if (image != nil){
self.thumbnailImageView.image = [self imageResizingToAspetRatio:image];
}
}];
Kindly let me know if did any mistake, or any suggestions.
Update 1:
Tried to download the image using post man. Kindly check the image.
The same image URL is working on SDWebImage v3.5.4 after i upgraded to SDWebImage v4.4.5, it is not lodging the image.
Is there any configurations am i missing? Installed pod 'SDWebImage/WebP' also, added SD_WEBP=1 in Build settings -> Preprocessor macros.
Error: Error Domain=SDWebImageErrorDomain Code=0 "Downloaded image has 0 pixels" UserInfo={NSLocalizedDescription=Downloaded image has 0 pixels}
http://testingurl.net/api/Image?ActionFlagId=20&id=864
Authorization:
Email: kkk1#ler.com ,
Token: A-BE3D-WER3-847F-ER6YG5678G
Basically, SDWebImage has no issue for downloading them from any URL if the URL contains an image.
But in your case, you have tried to get an image from JSON. Your server API returns a JSON object that contains the image as base64String. When you get the JSON response then you need to get the base64String from json and then create an image from the base64String.
You can use this method for decoding string to image using Objective C.
- (UIImage *)decodeBase64ToImage:(NSString *)strEncodeData {
NSData *data = [[NSData alloc]initWithBase64EncodedString:strEncodeData options:NSDataBase64DecodingIgnoreUnknownCharacters];
return [UIImage imageWithData:data];
}
First, update pod and try SDWebImage pod version 3.8.2.
And the second thing is to check your image URL. because I personally test image download with this pod version and downloading functionality is working.
I faced the same issue and I was trying webP images. I realised later that I need to add webP coder to SDImageCodersManager. Something like
SDImageCodersManager.shared.addCoder(SDImageWebPCoder.shared)
I did this in AppDelegate.
If you are suffering such type issue from SDWebImage library you can go with other one as well which are supporting base64 string object
One of best library I found is "Kingfisher"
Hope you like this and it will solve your issue.

SDWebImageManager not showing image from long and special character URL

SDWebImage not displaying image from URL which is too long and with some special characters.
image URL is:
http://akns-images.eonline.com/eol_images/Entire_Site/2018223/rs_600x600-180323073745-600-michael-davidson-fdny-032218.jpg?fit=around%7C450:350&crop=450:350;center,top&output-quality=100
[albumImageview sd_setImageWithURL:[NSURL URLWithString:aboveURL] placeholderImage:[UIImage imageNamed:placeholder] options:SDWebImageRefreshCached];
Use the following method
[albumImageview sd_setImageWithURL:[NSURL URLWithString:#"http://akns-images.eonline.com/eol_images/Entire_Site/2018223/rs_600x600-180323073745-600-michael-davidson-fdny-032218.jpg?fit=around%7C450:350&crop=450:350;center,top&output-quality=100"] placeholderImage:[UIImage new] completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
albumImageview.image = image;
}];

Objective C: For loop is finished before image is finished

I have an arrayOfLinks that contains a lot of url links. I need to get images from these links. I am using the following code to do so.
- (void)getImages {
NSArray *links = arrayOfLinks;
for (NSString *link in links ) {
[self.picImage sd_setImageWithURL:[NSURL URLWithString:link] placeholderImage:nil options:SDWebImageHighPriority completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
NSLog(#"pic image set finished");
}];
}
[self finishSettingImages];
NSLog(#"for loop finished");
}
This almost works, but the problem is the for loop finishes before the images are set. I want to call the method finishSettingImages after each image is set. What would be the best way to do this?
Edit: I want the method 'finishSettingImages' called after ALL the images are set. Sorry for not clarifying this.
Just use GCD groups.
NSArray *links = arrayOfLinks;
dispatch_group_t group = dispatch_group_create();
for (NSString *link in links) {
dispatch_group_enter(group);
[self.picImage sd_setImageWithURL:[NSURL URLWithString:link] placeholderImage:nil options:SDWebImageHighPriority completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
dispatch_group_leave(group);
}];
}
// you can use dispatch_get_main_queue() or background here
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// all is done
});
If you only need to get images, you can use SDWebImageManager:
NSArray *links = arrayOfLinks;
__block NSMutableArray *images = [NSMutableArray new];
dispatch_group_t group = dispatch_group_create();
for (NSString *link in links) {
dispatch_group_enter(group);
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadImageWithURL:[NSURL URLWithString:link]
options:SDWebImageRetryFailed
progress:^(NSInteger receivedSize, NSInteger expectedSize) {}
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (image) {
[images addObject:image];
}
dispatch_group_leave(group);
}];
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// all is done
for (UIImage *image in images) {
//do something with images
}
});
Code example for Swift 3/4:
var arrayOfLinks = ... // you string links are here
let dispatchGroup = DispatchGroup()
for link in arrayOfLinks {
if let url = URL(string: link) {
dispatchGroup.enter()
self.imageView.sd_setImage(with: url) { (image, error, cacheType, url) in
dispatchGroup.leave()
}
}
}
dispatchGroup.notify(queue: .main) {
print("all is done ")
}
EDIT: this answer is bad, as Josh in the comments pointed out, I failed to see the race condition with the index == total check
Try this:
- (void)getImages
{
NSArray *links = arrayOfLinks;
NSUInteger total = [links count];
__block NSUInteger index = 0;
__weak id *weakSelf = self; //if your picImage retains the completion block as a property,
//then you will want to capture a weak reference to self, so you don't have a retain cycle
for (NSString *link in links ) {
[self.picImage sd_setImageWithURL:[NSURL URLWithString:link] placeholderImage:nil options:SDWebImageHighPriority completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
NSLog(#"pic image set finished");
index += 1;
if( index == total )
{
//again if you don't store this block as a property, you can just reference self instead of weakSelf
[weakSelf finishSettingImages];
}
}];
}
NSLog(#"for loop finished");
}
the __block attribute makes the block use a pointer to the variable so that it can modify the value across executions of the block. That's how we can increment the index variable. total is not __block so the current state of total when you define the block is what's going to be used every time the block executes. So even if you set total to 100 from 10 within the block, the next time the block executes it will still see total as 10.

How to get image size from SDWebImage?

I am using SDWebImage to get image from url. I want to get the size of remote image in order to do some layout calculation. Since I only know the url of the image, how can I get it from SDWebImage object?
please try this one, Its may be work for you
-(UIImage *)downloadImageAsync:(NSString *)imageKey
{
NSLog(#"image key : %#",imageKey);
__block UIImage *returnedImage;
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadWithURL:[NSURL URLWithString:imageKey] options:0 progress:^(NSUInteger receivedSize, long long expectedSize){
NSLog(#"received size %d expected size %lld", receivedSize, expectedSize);
}completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType,BOOL finished){
if(image && finished) {
returnedImage = image;
}
}];
if(returnedImage == nil) {
NSLog(#"Returned Image Nil");
}
return returnedImage;
}

Incompatible block pointer types - sd_setImageWithUrl

I've been trying to figure this out for the past hour and after endless searching can't seem to see the issue. I'm new to Objective-C development and have recently taken on a new codebase to use as a learning tool.
I'm trying to set an image to a cell which has a placeholder image and upon a completed request, sets the image to the bounds of the cell. However the code is failing because of the following error:
Incompatible block pointer types sending 'void (^)(UIImage *__strong, NSError *__strong, SDImageCacheType)'
Upon searching SO and other sources all I can find is ensuring that void is indeed returned. You can see from the code below that nothing is returned, thus it is void.
if(imageURL != nil)
{
cell.productImageView.contentMode = UIViewContentModeCenter;
__weak typeof(cell) weakCell = cell;
[cell.productImageView sd_setImageWithURL:imageURL placeholderImage:[UIImage sd_animatedGIFNamed:#"loading-indicator"] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) {
if (image)
{
[weakCell.productImageView setContentMode:UIViewContentModeScaleAspectFill];
}
}];
}
Here is the header code for that particular item:
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletionBlock)completedBlock;
Thanks in advance!
The latest API of SDWebImage is slightly different so change your code for this one:
if(imageURL != nil)
{
cell.productImageView.contentMode = UIViewContentModeCenter;
__weak typeof(cell) weakCell = cell;
[cell.productImageView sd_setImageWithURL:imageURL placeholderImage:[UIImage sd_animatedGIFNamed:#"loading-indicator"] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
if (image)
{
[weakCell.productImageView setContentMode:UIViewContentModeScaleAspectFill];
}
}];
}

Resources