I'm having a trouble dynamically adding UIButtons with background image as subviews to a UIScrollView. Its kind of a image gallery using UIButtons on a scrollView. I have used this method for couple of my apps, it works fine for me with the static contents.
But this time, Im loading images from a web service and saved to documents directory, then call the method to create the gallery. Logic is same with my other apps. But I cannot figure out what is the issue here.
I'll put here both the codes one is for retrieving data and other is the creating gallery.
Data retrieving from server
-(void)loadDataFromServer{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
arrCats = [[NSMutableArray alloc]init];
arrPromos = [[NSMutableArray alloc]init];
//[spinMenu startAnimating];
// load promo images from the server
for(int i=0;i<[arrPromos count];i++)
{
NSString *urlString = [Constants getImages:[[arrPromos objectAtIndex:i] objectForKey:#"image"]];
NSLog(#"Get Images API Call : %#", urlString);
NSURL *imageurl = [NSURL URLWithString:urlString];
//get a dispatch queue
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//this will start the image loading in bg
dispatch_async(concurrentQueue, ^{
NSData *imageData = [[NSData alloc] initWithContentsOfURL:imageurl];
//this will set the image when loading is finished
dispatch_async(dispatch_get_main_queue(), ^{
if(imageData != nil){
// save the images temporally
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0]; //Get the docs directory
NSString *filePath = [documentsPath stringByAppendingPathComponent:[[arrPromos objectAtIndex:i] objectForKey:#"image"]]; //Add the file name
[imageData writeToFile:filePath atomically:YES];
}
});
});
}
// Load promotions from server
dispatch_async(queue, ^{
NSLog(#"Promotions Loading Started");
NSString *urlString = [Constants getAllPromotions:#"GetPromo.php"];
NSLog(#"Get Promotions API Call : %#", urlString);
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// Specify that it will be a GET request
request.HTTPMethod = #"GET";
[request setHTTPShouldHandleCookies:NO];
NSURLResponse *responseURL;
NSError *error;
NSData *dataPromotions = [NSURLConnection sendSynchronousRequest:request returningResponse:&responseURL error:&error];
if (responseURL == nil)
{
// Check for problems
if (error != nil)
{
NSLog(#"Get Promtions Connection failed! Error - %#", [error localizedDescription]);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Connection Error!" message:#"Promotions data failed to load!" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
}
else
{
NSString *responseString = nil;
responseString = [[NSString alloc] initWithData:dataPromotions encoding:NSUTF8StringEncoding];
if ([responseString rangeOfString:#"error"].location == NSNotFound)
{
NSDictionary *response = [[NSDictionary alloc] init];
response = (NSDictionary *)[responseString JSONValue];
NSLog(#"Response : Promotions %#", response);
if(response != Nil){
if([response count]>0){
arrPromos = [NSMutableArray arrayWithArray:[response objectForKey:#"Promos"]];
NSLog(#"ArrPromos # loading %#", arrPromos);
// create promos galley
[self createPromosGallery];
}
}
}
}
});
Note: [self createPromosGallery]; is calling after download all the images and data.
Create Gallery
-(void) createPromosGallery{
// sort arrPromos based on priority
for(int i=0; i<[arrPromos count];i++){
[arrPromos sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSDictionary *dict1 = obj1;
NSDictionary *dict2 = obj2;
NSString *string1;
NSString *string2;
if(![[dict1 objectForKey:#"priority"] isKindOfClass: [NSNull class]])
string1 = [dict1 objectForKey:#"priority"];
if(![[dict2 objectForKey:#"priority"] isKindOfClass: [NSNull class]])
string2 = [dict2 objectForKey:#"priority"];
return [string1 compare:string2 options:NSNumericSearch];
}];
}
NSLog(#"ArrPromos %#", arrPromos);
// scrollView size
CGFloat screenHieght = [UIScreen mainScreen].bounds.size.height;
if(screenHieght>500){
scrollView.frame = CGRectMake(0, 0, 320, 568);
}
else{
scrollView.frame = CGRectMake(0, 0, 320, 480);
}
// define scrollview height
int scrollHieght;
scrollHieght = ([arrPromos count]-1)/2;
NSLog(#"Scroll height %d",scrollHieght);
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width , scrollHieght * 160 +200);
scrollView.pagingEnabled = NO;
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.scrollsToTop = NO;
scrollView.decelerationRate = UIScrollViewDecelerationRateFast;
scrollView.delegate = self;
for(int i=0;i<[arrPromos count];i++)
{
float x;
float y;
if(i%2==0)
{
x=30.0;
y=(i/2)*160+25;
}
if(i%2==1) {
x=170.0;
y=(i/2)*160+25;
}
// retreive saved images
NSString *strImgName;
UIImage *buttonUpImage;
// create buttons
button = [UIButton buttonWithType:UIButtonTypeCustom];
strImgName = [[arrPromos objectAtIndex:i] objectForKey:#"image"];
NSLog(#"Button image name %#", strImgName);
NSArray *sysPaths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES );
NSString *docDirectory = [sysPaths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/%#",docDirectory,strImgName];
buttonUpImage = [UIImage imageWithContentsOfFile:filePath];
[button setBackgroundImage:buttonUpImage forState:UIControlStateNormal];
button.frame = CGRectMake(x, y, 120,140);
[button setTag:i];
[button addTarget:self action:#selector(promoBtnPressed:)forControlEvents:UIControlEventTouchUpInside];
[self.scrollView addSubview:button];
}
}
Note: I tested on both iOS 7 and 6. In iOS 7, it takes very long time to appear images on scrollView(Currently have only 2 images). Or else, If I TAP on scroolView then the images appear.
In ios 6, nothing appear
//Make a method that has url (fileName) Param
NSArray *documentsDirectory =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *textPath = [documentsDirectory stringByAppendingPathComponent:url];
NSFileManager *fileManager =[NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:textPath])
{
return YES;
}
else
{
return NO;
}
UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage
imageNamed:#""]];//Placeholder image
if ([url isKindOfClass:[NSString class]])
{
imgView.image = [UIImage imageNamed:[url absoluteString]];
imgView.contentMode = UIViewContentModeScaleAspectFit;
}
else if ([fileManager fileExistsAtPath:url])
{
NSString *textPath = [documentsDirectory stringByAppendingPathComponent:url];
NSError *error = nil;
NSData *fileData = [NSData dataWithContentsOfFile:textPath options:NSDataReadingMappedIfSafe error:&error];
if (error != nil)
{
DLog(#"There was an error: %#", [error description]);
imgView.image=nil;
}
else
{
imgView.image= [UIImage imageWithData:fileData]
}
}
else
{ UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc]
initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
CGPoint center = imgView.center;
// center.x = imgView.bounds.size.width / 2;
spinner.center = center;
[spinner startAnimating];
[imgView addSubview:spinner];
dispatch_queue_t downloadQueue = dispatch_queue_create("iamge downloader", NULL);
dispatch_async(downloadQueue, ^{
NSData *imgData = [NSData dataWithContentsOfURL:url];
dispatch_async(dispatch_get_main_queue(), ^{
[spinner removeFromSuperview];
UIImage *image = [UIImage imageWithData:imgData];
NSError *error = nil;
[imgData writeToFile:url options:NSDataWritingFileProtectionNone error:&error];
if (error != nil)
}
else
{
}
imgView.image = image;
});
});
}
Thats UIImageView loading an image if it doesnot exist in document then it Save it , An Activity indicator is added to show image is loading to save,
Yes it is because you are downloading and then saving the images which takes time. I suggest you to use any library for downloading images and saving them.
Ex : SDWebImage
Related
I'm trying to encrypt the saved plist data using RNCryptor and decrypt it.
the output is all gibberish in encrypted file but am not able to get the anything after decryption.
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"data.plist"]];
NSError *error1;
bac = [RNEncryptor encryptData:data withSettings:kRNCryptorAES256Settings password:#"abcdef" error:&error1];
NSString *pathToDesktop = [NSString stringWithFormat:#"/Users/rajparmar/Desktop/encrypt.plist"];
[bac writeToFile:pathToDesktop atomically:YES];
Here is the code for decryption
NSError *error1;
NSData *decryptedData = [RNDecryptor decryptData:bac
withPassword:#"abcdef"
error:&error1];
NSString *pathToDesktop1 = [NSString stringWithFormat:#"/Users/rajparmar/Desktop/decrypt.plist"];
[decryptedData writeToFile:pathToDesktop1 atomically:YES];
Complete Example with code using RNEncryptor and RNDecryptor.
#import "ViewController.h"
#import <Security/Security.h>
#import "RNCryptor/RNEncryptor.h"
#import "RNCryptor/RNDecryptor.h"
#interface ViewController () {
UILabel* lable;
NSMutableDictionary* plistDict;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
UIButton* btn1 = [UIButton buttonWithType:UIButtonTypeCustom];
btn1.frame = CGRectMake(0, 0, 150, 60);
btn1.backgroundColor = [UIColor lightGrayColor];
[btn1 setTitle:#"SaveData" forState:UIControlStateNormal];
btn1.center = self.view.center;
[btn1 addTarget:self action:#selector(saveDataToPlist:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn1];
UIButton* btn2 = [UIButton buttonWithType:UIButtonTypeCustom];
btn2.frame = CGRectMake(btn1.frame.origin.x, btn1.frame.origin.y + 100, 150, 60);
btn2.backgroundColor = [UIColor lightGrayColor];
[btn2 setTitle:#"Show Data" forState:UIControlStateNormal];
[btn2 addTarget:self action:#selector(getDataFromPlist:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn2];
lable = [[UILabel alloc] initWithFrame:CGRectMake(btn2.frame.origin.x, btn2.frame.origin.y + 100, 300, 40)];
lable.text = #"";
[self.view addSubview:lable];
//create plist if not exits
[self createPlistIfNotExists];
}
#pragma mark - Button Events
- (void)saveDataToPlist:(id)sender
{
NSString* eString = #"Hello World How are you";
[self insertEncryptedDataIntoPlist:eString forKey:#"ENData"];
}
- (void)getDataFromPlist:(id)sender
{
NSString* dString = [self decryptDataFromPlistForKey:#"ENData"];
[lable setText:dString];
}
#pragma mark - Encryption and Decryption
- (void)insertEncryptedDataIntoPlist:(NSString*)aDataString forKey:(NSString*)aKey
{
NSError* error;
NSData* data;
data = [RNEncryptor encryptData:[aDataString dataUsingEncoding:NSUTF8StringEncoding]
withSettings:kRNCryptorAES256Settings
password:#"#ABC123"
error:&error];
if (error) {
NSLog(#"Failed: %#", error);
exit(1);
}
[plistDict setObject:data forKey:aKey];
[plistDict writeToFile:[self getPlistPath] atomically:YES];
}
- (NSString*)decryptDataFromPlistForKey:(NSString*)aKey
{
NSMutableDictionary* savedStock = [[NSMutableDictionary alloc] initWithContentsOfFile:[self getPlistPath]];
NSError* error;
NSData* data;
data = [RNDecryptor decryptData:[[NSData alloc] initWithData:[savedStock valueForKey:aKey]] withPassword:#"#ABC123" error:&error];
if (error) {
NSLog(#"Failed: %#", error);
exit(1);
}
NSString* string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return string;
}
- (void)createPlistIfNotExists
{
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:#"eplist.plist"];
NSFileManager* fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:path]) {
path = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"eplist.plist"]];
}
if ([fileManager fileExistsAtPath:path]) {
plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
}
else {
// If the file doesn’t exist, create an empty dictionary
plistDict = [[NSMutableDictionary alloc] init];
}
}
- (NSString*)getPlistPath
{
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:#"eplist.plist"];
return path;
}
#end
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"TableViewCell" forIndexPath:indexPath];
cell.tag = indexPath.row;
//cell.imageView.image = nil;
// Rounded Rect for cell image
CALayer *cellImageLayer = cell.imageView.layer;
[cellImageLayer setCornerRadius:25];
[cellImageLayer setMasksToBounds:YES];
[self getImages];
[self storeImages];
UIImage *image =_ResimSonHali[indexPath.row];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(queue, ^(void) {
if (image) {
dispatch_async(dispatch_get_main_queue(), ^{
if (cell.tag == indexPath.row) {
CGSize itemSize = CGSizeMake(50, 50);
UIGraphicsBeginImageContext(itemSize);
CGRect imageRect = CGRectMake(0.0, 0.0, itemSize.width, itemSize.height);
[image drawInRect:imageRect];
// cell.ThumbImage.image = image1;
cell.imageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[cell setNeedsLayout];
}
});
}
});
cell.TitleLabel.text = _TarifAdi[indexPath.row];
return cell;
}
-(void)getImages
{
NSMutableArray *fuckingArrayYemek = [[NSMutableArray alloc] init];
for (int i=0; i<[_ResimAdiBase count]; i++)
{
NSString *testString=_ResimAdiBase[i];
NSArray *ImageNames = [testString componentsSeparatedByString:#"."];
[self cacheImage: _ResimAdi[i] : ImageNames[0] ];
[fuckingArrayYemek addObject:ImageNames[0]];
}
_ResimSonAdi = fuckingArrayYemek;
}
-(void) storeImages
{
NSMutableArray *fuckingArrayYemekName = [[NSMutableArray alloc] init];
for (int i=0; i<[_ResimAdiBase count]; i++)
{
[fuckingArrayYemekName addObject:[self getCachedImage:_ResimSonAdi[i]]];
}
_ResimSonHali = fuckingArrayYemekName;
}
- (void) cacheImage: (NSString *) ImageURLString : (NSString *)imageName
{
NSURL *ImageURL = [NSURL URLWithString: ImageURLString];
// Generate a unique path to a resource representing the image you want
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex: 0];
NSString *docFile = [docDir stringByAppendingPathComponent: imageName];
// Check for file existence
if(![[NSFileManager defaultManager] fileExistsAtPath: docFile])
{
// The file doesn't exist, we should get a copy of it
// Fetch image
NSData *data = [[NSData alloc] initWithContentsOfURL: ImageURL];
UIImage *image = [[UIImage alloc] initWithData: data];
// Is it PNG or JPG/JPEG?
// Running the image representation function writes the data from the image to a file
if([ImageURLString rangeOfString: #".png" options: NSCaseInsensitiveSearch].location != NSNotFound)
{
[UIImagePNGRepresentation(image) writeToFile: docFile atomically: YES];
}
else if([ImageURLString rangeOfString: #".jpg" options: NSCaseInsensitiveSearch].location != NSNotFound ||
[ImageURLString rangeOfString: #".jpeg" options: NSCaseInsensitiveSearch].location != NSNotFound)
{
[UIImageJPEGRepresentation(image, 100) writeToFile: docFile atomically: YES];
}
}
}
- (UIImage *) getCachedImage : (NSString *)imageName
{
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* cachedPath = [documentsDirectory stringByAppendingPathComponent:imageName];
UIImage *image;
// Check for a cached version
if([[NSFileManager defaultManager] fileExistsAtPath: cachedPath])
{
image = [UIImage imageWithContentsOfFile: cachedPath]; // this is the cached image
}
else
{
NSLog(#"Error getting image %#", imageName);
}
return image;
}
When i load 20 data, our table do not lagging but when our try to increase data size table view getting lag how we can prove this problem. First we tried dispatch then we tried save images cache still we got lag. Approximately, we deal with this problem about 3 days.
This is the problem line inside cacheImage() method, which is called with every call of "cellForRowAtIndexPath" method
NSData *data = [[NSData alloc] initWithContentsOfURL: ImageURL];
So to resolve the problem use this line under dispatch_async section. And update your code according to it.
I want to download multiple images from URL to my device in iOS App.
//
// ImageDownload.m
//
#import "ImageDownload.h"
#implementation ImageDownload {
int *position;
NSArray *downloableImages;
}
- (void)start:(NSArray *)images delegate:(id)delegate
{
position = 0;
downloableImages = images;
NSUInteger *count = ((NSUInteger *)[downloableImages count]);
NSLog(#"%d", count);
[self startDownload];
}
- (void)startDownload
{
NSUInteger *imageDataCount;
NSArray *image;
NSString *filename;
NSString *fileurl;
NSURLRequest *imageUrlRequest;
image = [downloableImages objectAtIndex:position];
NSLog(#"%d", position);
NSArray *imageData = [image valueForKey:#"image"];
imageDataCount = ((NSUInteger *)[imageData count]);
if (imageDataCount > 0) {
filename = [imageData objectAtIndex:0];
fileurl = [imageData objectAtIndex:1];
NSLog(#"%#", fileurl);
imageUrlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:fileurl]];
NSURLConnection *imageUrlConnection = [[NSURLConnection alloc] initWithRequest:imageUrlRequest delegate:self startImmediately:TRUE];
} else {
NSUInteger *count = ((NSUInteger *)[downloableImages count]);
if (((NSUInteger *)position) < ((NSUInteger *)count - 1)) {
position = position + 1;
[self startDownload];
}
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"finish image...");
NSUInteger *count = ((NSUInteger *)[downloableImages count]);
if (((NSUInteger *)position) < ((NSUInteger *)count - 1)) {
position = position + 1;
[self startDownload];
}
}
#end
For now... I only check the position of the download and current URL,
Exists 27 files to download... but the download not go one by one... check this output:
Position: 0
http.....fichero00.jpg
Finish download
Position: 4
http.....fichero04.jpg
Finish download
Position: 8
http.....fichero08.jpg
Finish download
Create an ivar NSOperationQueue *operationQueue; in your .h file and init it in your .m file:
operationQueue = [[NSOperationQueue alloc] init];
operationQueue.maxConcurrentOperationCount = 1;
For downloading images, create a method that takes an image URL and call it for each image:
-(void)downloadImageAtURL:(NSURL *)imageURL {
[NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:imageURL] queue:operationQueue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
// Do something with your images here...
};
}
You can try this code.. Its 100 % Working for me
You can get more reference here
-(IBAction)startdownload
{
for (int i=0; i<[downloadarray count]; i++) //download array have url links
{
NSURL *URL = [NSURL URLWithString:[downloadarray objectAtIndex:i]];
NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc]initWithURL:URL];
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
if([data length] > 0 && [[NSString stringWithFormat:#"%#",error] isEqualToString:#"(null)"])
{
//make your image here from data.
UIImage *imag = [[UIImage alloc] initWithData:[NSData dataWithData:data]];
NSArray *array = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [array objectAtIndex:0];
NSString *imgstr=[NSString stringWithFormat:#"%d",i];
NSString *pngfilepath = [NSString stringWithFormat:#"%#sample%#.png",docDir,imgstr];
NSData *data1 = [NSData dataWithData:UIImagePNGRepresentation(imag)];
[data1 writeToFile:pngfilepath atomically:YES];
}
else if ([data length] == 0 && [[NSString stringWithFormat:#"%#",error] isEqualToString:#"(null)"])
{
NSLog(#"No Data!");
}
else if (![[NSString stringWithFormat:#"%#",error] isEqualToString:#"(null)"]){
NSLog(#"Error = %#", error);
}
}];
}
-(IBAction)viewfile
{
NSMutableArray *arr=[[NSMutableArray alloc]init];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pngfilepath = [NSString stringWithFormat:#"%#",documentsDirectory];
NSArray *filePathsArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:pngfilepath error:&error];
for (int i=0; i<[filePathsArray count]; i++){
NSString *pngfilepath = [NSString stringWithFormat:#"%#%#",documentsDirectory, [filePathsArray objectAtIndex:i]];
[arr addObject:[UIImage imageWithContentsOfFile:pngfilepath]];
}
myimageview = [[UIImageView alloc] initWithImage:[arr objectAtIndex:0]]; //Here myimageview is UIImageView
}
Hope This Helps!!!
Work around NSOperationQueue it allow you to control how much operation are run concurrently.
Create:
NSOperationQueue *queue = [NSOperationQueue new];
queue.maxConcurrentOperationCount = 1;
Then add operations :
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
... here is you code with converting image to data and addition it to NSURLConnection
}];
[operation setCompletionBlock:^{
....something that you want to do, after operation completes
}];
[queue addOperation:operation];
More about NSOperation:
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/NSOperation_class/Reference/Reference.html#//apple_ref/occ/cl/NSOperation
Here is my new code...
I have a delay when I try to update a UIProgressView
//
// ImageDownload.m
//
#import "ImageDownload.h"
#implementation ImageDownload {
NSMutableArray *downloableImages;
int position;
Sync *mySync;
}
- (void)start:(NSArray *)images sync:(Sync *)sync
{
NSArray *imageData;
int imageDataCount;
mySync = sync;
downloableImages = [[NSMutableArray alloc] init];
for (NSArray *image in images) {
imageData = [image valueForKey:#"image"];
imageDataCount = [imageData count];
if (imageDataCount > 0) {
[downloableImages addObject:imageData];
}
}
[self downloadAllFiles];
}
- (void)downloadAllFiles
{
NSString *filename;
NSString *fileUrl;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cacheDirectory = [paths objectAtIndex:0];
position = 0;
int count = [downloableImages count];
NSLog(#"%#", downloableImages);
NSLog(#"total files %d", count);
for (NSArray *image in downloableImages) {
filename = [image objectAtIndex:0];
fileUrl = [image objectAtIndex:1];
NSURL *url = [NSURL URLWithString:fileUrl];
NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc] initWithURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
position++;
float progress = (float)position / (float)count;
//update UIProgressView
[mySync setProgressImageDownload:progress];
if ([data length] > 0 && [[NSString stringWithFormat:#"%#", error] isEqualToString:#"(null)"]) {
UIImage *downloadedImage = [[UIImage alloc] initWithData:[NSData dataWithData:data]];
NSString *imageDestinationPath = [NSString stringWithFormat:#"%#%#", cacheDirectory, filename];
NSData *imageData = [NSData dataWithData:UIImageJPEGRepresentation(downloadedImage, 100.0)];
[imageData writeToFile:imageDestinationPath atomically:YES];
}
if (position == count) {
NSLog(#"all complete...");
[mySync downloadImagesComplete];
}
}];
}
}
#end
I want to retrieve a folder containing 10 images from server, then store that folder in my document directory. I did some code, but when I run it, I am getting the image urls, not the images themselves. Can anyone help me out?
My code:
-(void)viewWillAppear:(BOOL)animated
{
NSMutableData *receivingData = [[NSMutableData alloc] init];
NSURL *url = [NSURL URLWithString:#"http://Someurl.filesCount.php"];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:YES];
}
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[receivingData appendData:data];
}
-(void) connectionDidFinishLoading:(NSURLConnection *)connection
{
NSError *error = nil;
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
printf("\n the path is :%s",[path UTF8String]);
NSString *zipPath = [path stringByAppendingPathComponent:#"filesCount.php"];
[receivingData writeToFile:zipPath options:0 error:&error];
NSString *documentsDirectoryPath = [[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"] stringByAppendingPathComponent:#"filesCount"];
NSLog(#"the path %#",documentsDirectoryPath);
}
I made this function in my previous project. You need to pass your imageView and serverUrl, then its automatically show image in your imageView and save image to temp directory, when you want again to fetch same image, then next time it take image from disk.
+(void)downloadingServerImageFromUrl:(UIImageView*)imgView AndUrl:(NSString*)strUrl{
NSFileManager *fileManager =[NSFileManager defaultManager];
NSString* theFileName = [NSString stringWithFormat:#"%#.png",[[strUrl lastPathComponent] stringByDeletingPathExtension]];
NSString *fileName = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:#"tmp/%#",theFileName]];
imgView.backgroundColor = [UIColor darkGrayColor];
UIActivityIndicatorView *actView = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[imgView addSubview:actView];
[actView startAnimating];
CGSize boundsSize = imgView.bounds.size;
CGRect frameToCenter = actView.frame;
// center horizontally
if (frameToCenter.size.width < boundsSize.width)
frameToCenter.origin.x = (boundsSize.width - frameToCenter.size.width) / 2;
else
frameToCenter.origin.x = 0;
// center vertically
if (frameToCenter.size.height < boundsSize.height)
frameToCenter.origin.y = (boundsSize.height - frameToCenter.size.height) / 2;
else
frameToCenter.origin.y = 0;
actView.frame = frameToCenter;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSData *dataFromFile = nil;
NSData *dataFromUrl = nil;
dataFromFile = [fileManager contentsAtPath:fileName];
if(dataFromFile==nil){
dataFromUrl=[[[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:strUrl]] autorelease];
}
dispatch_sync(dispatch_get_main_queue(), ^{
if(dataFromFile!=nil){
imgView.image = [UIImage imageWithData:dataFromFile];
}else if(dataFromUrl!=nil){
imgView.image = [UIImage imageWithData:dataFromUrl];
// NSString *fileName = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:#"tmp/%#",theFileName]];
BOOL filecreationSuccess = [fileManager createFileAtPath:fileName contents:dataFromUrl attributes:nil];
if(filecreationSuccess == NO){
NSLog(#"Failed to create the html file");
}
}else{
imgView.image = [UIImage imageNamed:#"NO_Image.png"];
imgView.tag = 105;
}
[actView removeFromSuperview];
[actView release];
});
});
}
Try using this code.
NSURL* url = [NSURL URLWithString:#"http://imageAddress.com"];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * response,
NSData * data,
NSError * error) {
if (!error){
// do whatever you want with directory or store images.
NSImage* image = [[NSImage alloc] initWithData:data];
}
}];
Use this code to download the image using URL and store in document directory. Iterate the logic for set of images to download and store.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *imageURL = #"http://sampleUrl";
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imageURL]]];
NSString *imagePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"Image1.png"]];
if(image != NULL)
{
//Store the image in Document
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile: imagePath atomically:YES];
}
If you'll showing the images loaded from server on UI, then
try SDWebImageView, can be used with UIButton or UIImageView, very easy and efficient.
example,
[yourImageView setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
Read how to use it?
Okay, now for multiple images, you may need to run a loop, if you've a common base url for all your pictures (on server) something like http://yoururl/server/pictures/1.png will be replace by 2.png 3.png ... n.png, or you get different urls for pictures need to pass that url, you can load it into imageview objects, and later save them into document directory (remember, SDWebImageView by default doing this work for you). You can turn this off too.
P.S. It will load images once and stored into local (in cache) it self, next time when you pass the same image url, it won't load from server and directly load the image from local.
I'm trying to preview a downloaded file to system and the program crashes when performing the method called previewController:previewItemAtIndex:. From what I assumed is that is releasing the previewcontroller before it is displayed, but this error does not occur when the file is already in the documents folder. It only happens when trying to open the file right after it has been downloaded.
Here is the code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
NSUInteger count = [listSessionsST count];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
Signature *object = [listSessionsST objectAtIndex:row];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
UILabel *lblInComplete = (UILabel*)[cell viewWithTag:4];
UIImageView *imgCheck = (UIImageView*)[cell viewWithTag:3];
//Sets the File Name
self.File = [[[NSString stringWithFormat:#"%#_%#.%#",object.FileName,object.ModDate,object.Extension]
componentsSeparatedByCharactersInSet: [NSCharacterSet whitespaceCharacterSet]] componentsJoinedByString: #""];
//Shows the loading screen while the file is being downloaded
[DejalBezelActivityView activityViewForView:self.view withLabel:#"Downloading" width:0 LoadingType:#"Full"];
[DejalActivityView currentActivityView].showNetworkActivityIndicator = YES;
//Calls the method that will begin downloading the file
[self performSelector:#selector(startDownload:) withObject:object.Location afterDelay:0.2];
}
- (void)startDownload:(NSString *)strLocation{
NSString *filePath = [NSString stringWithFormat:#"%#/tmp/%#", NSHomeDirectory(),self.File];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:filePath];
if (fileExists)
{
[DejalBezelActivityView removeViewAnimated:YES];
//QuickLook APIs directly to preview the document
QLPreviewController *previewController = [[QLPreviewController alloc] init];
previewController.dataSource = self;
previewController.delegate = self;
[[self navigationController] pushViewController:previewController animated:YES];
[previewController release];
}
else
{
NSDictionary *dictionary = [Signature downloadFile:self.File Path:strLocation];
if ([dictionary valueForKey:#"Error"] == nil)
{
//If no error has occurred while downloading then preview the file.
//QuickLook APIs directly to preview the document
QLPreviewController *previewController = [[QLPreviewController alloc] init];
previewController.dataSource = self;
previewController.delegate = self;
[[self navigationController] pushViewController:previewController animated:YES];
[previewController release];
[DejalBezelActivityView removeViewAnimated:YES];
}
else
{
//If an error occurred while downloading then display message to user.
[DejalBezelActivityView removeViewAnimated:YES];
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#""
message:[dictionary valueForKey:#"Response"]
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alert show];
[alert release];
}
}
}
// Returns the number of items that the preview controller should preview
- (NSInteger)numberOfPreviewItemsInPreviewController:(QLPreviewController *)previewController{
return 1;
}
// returns the item that the preview controller should preview
- (id)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index{
NSString *path = [NSString stringWithFormat:#"%#/tmp/%#", NSHomeDirectory(),self.File];
return [NSURL fileURLWithPath:path];
}
The method that downloads the file and saves it to the tmp folder
---------------------------------------------------------------
+ (NSDictionary *)downloadFile:(NSString *)strFile Path:(NSString *)strPath{
float freeSpace = 0.0f;
NSError *error = nil;
NSDictionary *dictionary = [[NSFileManager defaultManager] attributesOfFileSystemForPath:[NSString stringWithFormat:#"%#/tmp", NSHomeDirectory()]
error: &error];
if (dictionary)
{
NSNumber *fileSystemFreeSizeInBytes = [dictionary objectForKey: NSFileSystemFreeSize];
freeSpace = [fileSystemFreeSizeInBytes floatValue];
}
else
{
//Handle error
NSLog(#"Error;%#",error);
return [NSDictionary dictionaryWithObjectsAndKeys:#"An error has occurred while downloading the file.",#"Response",#"Y",#"Error", nil];
}
if (freeSpace > 0.0f)
{
NSDictionary *dict = nil;
BOOL blnHasErroroccurred = NO;
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSString *encoded = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)strPath,
NULL,
(CFStringRef)#"!*'\"();:#&=+$,/?%#[]%",
kCFStringEncodingUTF8 );
NSString *strURL = [NSString stringWithFormat:#"%#/DataTransfer/DownloadFile?EMP_ID=%#&FilePath=%#",
appDelegate.ServerAddress,
appDelegate.UserId,
encoded];
[encoded release];
NSURL *url = [NSURL URLWithString:strURL];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy: NSURLRequestUseProtocolCachePolicy
timeoutInterval:20.0];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
NSURLResponse* response = nil;
NSError* resultError = nil;
NSData* dataResult = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&resultError];
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
if ([httpResponse statusCode] == 200)
{
#try
{
if (dataResult.length < freeSpace)
{
//Get the tmp directory
NSFileManager *fileManager =[NSFileManager defaultManager];
NSString *fileName = [NSString stringWithFormat:#"%#/tmp/%#", NSHomeDirectory(),strFile];
//Write the data to using the tmp directory
BOOL filecreationSuccess = [fileManager createFileAtPath:fileName contents:dataResult attributes:nil];
if(filecreationSuccess == YES)
{
dict = [NSDictionary dictionaryWithObjectsAndKeys:#"",#"Response",nil,#"Error", nil];
}
else
{
blnHasErroroccurred = YES;
}
}
}
#catch (NSException *exception)
{
blnHasErroroccurred = YES;
}
}
else
{
blnHasErroroccurred = YES;
}
if(blnHasErroroccurred == YES)
{
dict = [NSDictionary dictionaryWithObjectsAndKeys:#"An error has occurred while downloading the file.", #"Response", #"Yes",#"Error",nil];
}
[dataResult release];
return dict;
}
else
{
return [NSDictionary dictionaryWithObjectsAndKeys:#"Not enough disk space to download file.",#"Response",#"Y",#"Error", nil];
}
}