I just read about NSURLSession and I used it to download images from a url.Here i.e. the method that I wrote :
-(void)startDownloadingWithURLString:(NSString*)urlString andDisplayOn:(UIImageView*)imageView{
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
NSURLSession *urlSession = [NSURLSession sessionWithConfiguration:configuration];
NSLog(#"%#",dataResponse);
NSURLSessionDownloadTask *task = [urlSession downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:location]];
dispatch_async(dispatch_get_main_queue(), ^{
imageView.image = image;
});
}];
[task resume];
}
Now the problem is that I am calling this method inside "cellForItemAtIndexPath:".So overtime I scroll,this method gets called again and again for each cell(reusability concept).Now,as the download process is asynchronous,I can't know when the downloading is complete.
So what should I do to avoid this problem?I just want to download images once.
There are third party libraries available to solve your purpose. I prefer using SDWebImage for the same. It worked like a charm for me.
Just import
#import<SDWebImage/UIImageView+WebCache.h>
and you can use the method to load the web image
sd_setImageWithURL:
It does the same work for you without hustle.
Refer this link https://github.com/rs/SDWebImage
Hope it helps. Hapy Coding..
Related
I am downloading a file from the web. File size is big some times may reach up to 100MBs some times, I want to continue downloading while to app goes to background or when the device is locked. For this i am using AFNetworking 3.0
[NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:myIdentifier];
It works fine as long as i am on WiFi. When i turn off WiFi and turn on my cellular network which is 4G, it stops responding and i get no data as a result of my download request. If i use
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
every thing was fine except my download will not continue when the app goes to background.
I have also checked allowsCellularAccess on NSURLSessionConfiguration and NSURLRequest and object which is YES, but my download does not work when on cellular network.
Here is my full code
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:myIdentifier];
configuration.discretionary = YES;
configuration.sessionSendsLaunchEvents = YES;
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSURL *URL = [NSURL URLWithString:downloadUrl];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSLog(#"Allow Cellular Network : %d",request.allowsCellularAccess);
NSLog(#"Allow Cellular Network for session: %d",configuration.allowsCellularAccess);
NSLog(#"Resource timneout interval: %f",configuration.timeoutIntervalForResource);
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
dispatch_async(dispatch_get_main_queue(), ^{
[self callProgressBlocksForUrl:lesson.archiveUrl withProgress:downloadProgress.fractionCompleted];
});
} destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
NSLog(#"Getting Path for File saving");
return [NSURL fileURLWithPath:fullPath];
} completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
NSHTTPURLResponse * myresponse = (NSHTTPURLResponse *)response;
NSLog(#"Video downloaded, headers: %#", [myresponse.allHeaderFields description]);
}];
You should not be setting the discretionary flag. That tells the OS to wait to download the data until a convenient time (which, IIRC, basically means when the device is A. asleep, B. on power, and C. connected to Wi-Fi).
I guess discretionary flag might create the problem.
As said by apple in documentation that discretionary flag allow the download when device have convenient time and convenient resources.
I have seen this question somewhat answered here but in my case I am using NSURLSession to display images. These images are uploaded by user or scanned into a database using a script.
In this case writing exception URL's (NSExceptionDomains) won't work because the image is hosted by a user on their site or some other site. If I allow NSAllowsArbitraryLoads will I still be able to be approve for App Store since I am not implementing the best practices of ATS?
I am not sure the best way to proceed. Any input would be appreciated!
Here is the code I am using.
NSString *thumbnail_url = [tempObject objectForKey:#"image"];
NSURL *url = [NSURL URLWithString:thumbnail_url];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDownloadTask *downloadPhotoTask = [session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
NSData *imageData = [[NSData alloc] initWithContentsOfURL:location];
dispatch_async(dispatch_get_main_queue(), ^{
cell.tableImageView.image = [UIImage imageWithData:imageData];
});
}];
[downloadPhotoTask resume];
Yes, you'll pass Review even with this parameter.
We have uploaded many builds since iOS9 SDK with NSAllowsArbitraryLoads set to YES.
P.S.: Your code should better look like this:
cell.thumbnailURL = URL;
__weak typeof(cell) weak
NSURLSessionDownloadTask *downloadPhotoTask = [session downloadTaskWithURL:URL completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
NSData *imageData = [[NSData alloc] initWithContentsOfURL:location];
UIImage *image = [UIImage imageWithData:imageData];
dispatch_async(dispatch_get_main_queue(), ^{
if (weakCell.thumbnailURL != URL) {
return;
}
weakCell.tableImageView.image = image;
});
}];
[downloadPhotoTask resume];
I have some code that gets an image from a web page and displays it in an ImageView. But the image loads very slowly for some reason I don't really understand! Through my logging I can see that all the data for the image (base64 string) arrives pretty instantly, yet it takes about 12 - 15 seconds for the image to appear in the ImageView.
I find this very strange because I used an NSStream to get the data for the image in a different method and the image loaded as soon as all the data arrived. But with this URLSession method its taking longer for the image to load. This doesn't really make sense! This method shouldn't affect how the ImageView loads that data.
Has anybody any ideas why this might be happening?
heres the code:
- (void)postMethod:(NSDictionary *)numDict
{
NSURL *url = [NSURL URLWithString:#"http://theWebAddress.com/aPage.php"]; // add url to page
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
request.HTTPMethod = #"POST";
NSError *error = nil;
NSData *data = [NSJSONSerialization dataWithJSONObject:numDict options:kNilOptions error:&error];
NSLog(#"%#", numDict);
if (!error)
{
NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:data completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *diction = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
for (id key in diction)
{
if ([key isEqualToString:#"text"])
{
NSLog(#"data is text");
self.messageLabel.text = diction[#"text"];
break;
}
else if ([key isEqualToString:#"image"])
{
NSLog(#"data is an image");
// gets the base64 string pretty instantly but takes 12 - 15 seconds to pop up in the imageView
NSData *ImgData = [[NSData alloc] init];
ImgData = [[NSData alloc] initWithBase64EncodedString:diction[#"image"] options:1];
self.ImageView.image = [UIImage imageWithData:ImgData];
break;
}
}
}];
[uploadTask resume];
}
}
many thanks!
Your completion handler might be operating on a background thread. UI updates should always work on the main thread. Put a break point at
self.ImageView.image = [UIImage imageWithData:ImgData];
and see if it is on the main thread. If not, dispatch it to the main thread before you set the ImageView.image:
dispatch_async(dispatch_get_main_queue(), ^{
self.ImageView.image = [UIImage imageWithData:ImgData];
});
You can try to use SDWebImage https://github.com/rs/SDWebImage and all you need is to set the image in imageView like this:
[cell.imageView setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
You are firstly downloading image and then showing image.You can download image by using lazy loading.
For this you can use EgoImageView not uiimageview.
self.ImageView.imageURL=[NSURL URLWithString:
here self.ImageView is of egoimageview type.
you can get this class from github.
https://github.com/enormego/EGOImageLoading
I've working with the new Today Extension available on iOS 8. Debugging seems to be very difficult on the device with inconsistent results so I've been using the simulator most of the time.
The extension I'm building is a very simple one that just display a different image on a daily basis, the flow is actually pretty simple:
iOS calls widgetPerformUpdateWithCompletionHandler
I download the image asynchronously
If the image was downloaded successfully I set the appropriate outlet on the storyboard and call the completion block with the constant: NCUpdateResultNewData
If an error occurred I call the completion block with the constant: NCUpdateResultFailed
According to Apple's reference documentation every time we call the completion block with the constant NCUpdateResultNewData the widget's snapshot should be updated to the current view, however, this doesn't work all the time, sometimes iOS seems to be using an older snapshot.
The code is straightforward, here's the widgetPerformUpdateWithCompletionHandler code:
-(void)widgetPerformUpdateWithCompletionHandler:(void (^)(NCUpdateResult))completionHandler {
__weak TodayViewController *weakSelf = self;
NSURL *URL = [NSURL URLWithString:#"http://www.muratekim.com/wp-content/uploads/apple-logo-small.png"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error) {
if (!error) {
UIImage *image = [UIImage imageWithData:data];
weakSelf.imageView.image = image;
weakSelf.img = image;
completionHandler(NCUpdateResultNewData);
}
else {
completionHandler(NCUpdateResultFailed);
}
}];
[task resume];
}
Thanks in advance!
Ze
I have been trying to download image/txt but i need to do it until that url exists & download that image/txt file,so i keep calling same method again & when i set debug point i see this .
If url is right than i do not see any queue in debug navigator because it is not calling method again. i referred AFNetworking library to the same but i guess it`s working in same way as i am doing in NSURLSession,right?
Case:- I check for url if exists or not, so if it`s exists than load both urls(time.txt & image.png), otherwise call WebService(XmlParser) & keep check for urls for following files.
time.txt+image.png
or
tryagain.txt
show whichever exists.
Also checked this AFNetworking Question but it didnt helped because i do not want to add number of operations. i want to load file whichever exists.
Because Operations will be completed whether it is success or fail in AFNetworking/NSURLSession.
-(void)downloading
{
NSString *imageUrl = [NSString stringWithFormat:#"%#",txtNumber.text];
NSURLSessionConfiguration *sessionConfig =[NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session =[NSURLSession sessionWithConfiguration:sessionConfig
delegate:self
delegateQueue:nil];
NSURLSessionDownloadTask *getImageTask = [session downloadTaskWithURL:[NSURL URLWithString:imageUrl]
completionHandler:^(NSURL *location,
NSURLResponse *response,
NSError *error)
{
UIImage *downloadedImage =[UIImage imageWithData:[NSData dataWithContentsOfURL:location]];
dispatch_async(dispatch_get_main_queue(), ^{
// do stuff with image
if (downloadedImage)
{
carImgView.image = downloadedImage;
result = TRUE;
}
else
{
result = FALSE;
[self tryagain];
}
});
}];
[getImageTask resume];
}
-(void)tryagain
{
NSString *strImg = [[NSString stringWithFormat:#"%#",gblPolicyNo] stringByAppendingString:FilePolStatus];
NSString *apiImage = [NSString stringWithFormat:#"http://moviepoint.info/%#/%#",FolderPolStatus,strImg];
NSURL *aImgUrl = [NSURL URLWithString:apiImage];
// 2
NSURLSessionConfiguration *sessionConfig =
[NSURLSessionConfiguration defaultSessionConfiguration];
// 3
tryAgainSession =[NSURLSession sessionWithConfiguration:sessionConfig
delegate:self
delegateQueue:nil];
// 1
getTryAgainTask = [tryAgainSession downloadTaskWithURL:aImgUrl
completionHandler:^(NSURL *location,
NSURLResponse *response,
NSError *error)
{
// 2
UIImage *downloadedImage =[UIImage imageWithData:[NSData dataWithContentsOfURL:location]];
//3
dispatch_async(dispatch_get_main_queue(), ^{
// do stuff with image
if (downloadedImage)
{
[policyImgWebView loadData:[NSData dataWithContentsOfURL:location] MIMEType:nil textEncodingName:nil baseURL:nil];
NSLog(#"YES");
}
else
{
NSLog(#"NO");
[self performInBackground];
}
});
}];
// 4
[getTryAgainTask resume];
}
Please Correct me if i am doing wrong & Help me to solve this problem.
Solved by taking One Global NSURLSession