I'm building an application that allows the user to take several pictures in a row with the device camera.
Every time a picture is taken, it is sent to an array as an NSData variable. The problem is: when the array gets like 30 pictures, it starts to create memory warnings and eventually crashes the application.
When I leave that view I save that array to NSUserDefaults, which can also lead to memory warnings and crashing.
I need to be able to save information of like 200 taken pictures. How can I achieve this without memory warnings?
Btw: I'm using the Apple's SquareCam sample code to take pictures with the camera.
Thanks in advance.
If you don't scale/save as jpg, a photo could be quite big. A solution would be to save it on "disk" in sandbox immediately (with jpeg format would be a good idea anyway) and store in your array only the path of the file you saved.
See a sample code:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* imgName = [NSString stringWithFormat:#"%#.jpg", self.uid];
NSString *imagePath = [documentsDirectory stringByAppendingPathComponent:imgName];
NSData *webData = UIImageJPEGRepresentation(self.theImage, 0.5);
[webData writeToFile:imagePath atomically:YES];
self.imageURL = imagePath;
Please don't save image just save only path of image.so, u can better manage them and better for your app. performance.
Related
I have a NSData value, generated from a byte array response. Now I need to save this as a .ppt file in iPhone/iPad, I learned from this link that there is no way to directly do it.
I already tried saving it as a PDF first, but failed in that too, since I'm unable to reproduce the charts from the nsdata.
Now is there another way to get this done other than sending the file through mail associated to the device?
Please do give out only the ways by which I can carry this out in the background without the help of the user? Any help will be appreciated.Thanks
I got it working, tried a lot but nothing worked and finally ran into some random code blocks, using which I got this wonderful piece of code,
//--------------------------------------------------------------------------------generating input URL
NSString *urlAddress = #"url containing the pdf data";
NSURL *theRessourcesURL = [NSURL URLWithString:urlAddress];
//--------------------------------------------------------------------------------defining file location details & writing a ppt file with a name "new.ppt"
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pathFloder = [[NSString alloc] initWithString:[NSString stringWithFormat:#"%#",#"new.ppt"]];
NSString *defaultDBPath = [documentsDirectory stringByAppendingPathComponent:pathFloder];
NSData *tmp = [NSData dataWithContentsOfURL:theRessourcesURL];
[tmp writeToFile:defaultDBPath atomically:YES];
This was working for me yesterday morning and now it doesn't. So, I suspect something else changed to cause it...but I can't find the change. I've spent hours reverting my code back almost a week and still it's not working (and I know it was working yesterday morning). So, I'm hoping that in posting this specific issue (a symptom?) some ideas will surface that I can evaluate. Thanks.
I download images as they're needed:
NSFileManager *filemgr;
filemgr = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [paths objectAtIndex:0];
NSString *targetFile = [NSString stringWithFormat:#"%#/%#.%#", documentDirectory, imageName, imageType];
// only download those where an image exists
if(![imageType isEqualToString:#""])
{
// only download the file if there is not already a local copy.
if([filemgr fileExistsAtPath:targetFile] == NO)
{
NSMutableData *imageData = [[NSMutableData alloc] initWithLength:0];
[imageData appendData:data];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *thumbNailFilename = [NSString stringWithFormat:#"%#.%#", imageName, imageType];
NSString *thumbNailAppFile = [documentsDirectory stringByAppendingPathComponent:thumbNailFilename];
}
}
Then display them:
NSString *imageFullName = [NSString stringWithFormat:#"%#%#", [greetingObject valueForKey:#"gid"], [greetingObject valueForKey:#"itp"]];
NSString *fullImagePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:imageFullName];
UIImage *greetingImage = [UIImage imageWithContentsOfFile:fullImagePath];
self.greetingImage.image = greetingImage;
The variables "imageFullName" and "fullImagePath" are populated with the correct data and the image files are present on the simulator in the specified directory. Yet, "greetingImage" equals nil.
Here's what I get for "fullImagePath": /Users/Steve2/Library/Application Support/iPhone Simulator/7.1/Applications/8C9F8417-F6E2-4B38-92B3-82A88477CB7F/Documents/165.jpg
Here are the image files:
I have also tried variations using initWithContentsOfFile and dataWithContentsOfFile and get the same result. The greetingImage variable is nil.
I appreciate your ideas. I've even reinstalled Xcode in hopes that something got corrupted. No dice.
Added: One thing I just thought of... I did add the SystemConfiguration.framework to the project yesterday for an unrelated feature. It's currently at the top of the Linked Frameworks and Libraries list. I have no experience working with this. Could it be causing the problem?
Thanks.
Your code looks correct.
I would check that the images themselves are still okay. Looking at the screenshot you posted Finder isn't showing previews of the images which it should do with a valid JPEG. You say that the images are being downloaded so I suspect that they are being corrupted somehow on the way down.
EDIT:
Didn't notice that you were using initWithContentsOfFile. Since you are saving the files as NSData objects you will need to load them into memory as NSData objects and then init a UIImage with the data object, like so:
NSData *imageData = [NSData dataWithContentsOfFile:filePath];
[UIImage imageWithData:imageData];
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I need to store and retrieve images in my app, I first thought of doing it like so:
[[NSUserDefaults standardUserDefaults] setObject:UIImagePNGRepresentation(image) forKey:key];
NSData* imageData = [[NSUserDefaults standardUserDefaults] objectForKey:key];
UIImage* image = [UIImage imageWithData:imageData];
But I read this isn't the recommended way. What is the best approach for this?
(I know there are duplicates of this question, but I haven't understood how to do it yet)
The best way to store images depends on what your app does.
If you have 100k+ images you probably want to save it manually to the iphone's hard disk over coredata since it will load images faster this way.
However, if you have less than that, then storing images as binary data in core data is what I would recommend.
The benefits of using coredata vs the file system:
Better iCloud Sync Support
No need to manage images on the hard disk as well as what ever you use as a 'persistence store' (coredata/nsuserdefaults/custom)
You can tie images to other data such as name, created date, ect.
Some interesting performance info with filesystem vs coredata: http://biasedbit.com/filesystem-vs-coredata-image-cache/
You'd have to take the data from UIImageJPEGRepresentation() and store it in an NSData object or some such in order for it to be "plist-serializable" to store in NSUserDefaults, but as others have said, you're much better off storing the image as an image file on the file system somewhere and storing the file path or file URL in NSUserDefaults.
Save the image in the Documents directory, then save the file name in a database (Core Data perhaps), another file format or NSUserDefaults.
NSUserDefaults is not really a great way to store app data.
From a UIImage instance get the data with
UIImagePNGRepresentation() or UIImageJPEGRepresentation(). Then save the data to a file. Use imageWithContentsOfFile: to recover the UIImage.
To obtain the path to the documents directory:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths firstObject];
The easiest way for you is to directly save the content to your iOS Device and store the path in the NSUserDefaults.
First convert the image to a file and save it to the phone.
UIImage *image = // your image
NSData *pngImageData = UIImagePNGRepresentation(image);
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths firstObject];
NSString *fileName = [NSString stringWithFormat:#"%#/imageName.png",
documentsDirectory];
[pngImageData writeToFile:fileName atomically:YES];
Some are against storing filePaths in NSUserDefaults because, you're not suppose to store anything in NSUserDefaults that is super dynamic, you're suppose to store things like session keys, or token values, user names even, things that don't change often or are very strict.
The suggestion is, if you absolutely refuse CoreData, to make a property list and store the string name there.
To store your imagePath in a plist you would do the following:
NSString *textPath = [[NSBundle mainBundle] pathForResource:#"propertyListName" ofType:#"plist"];
NSDictionary *thisDict = [NSDictionary dictionaryWithContentsOfFile:textPath];
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary:thisDict];
mutableDictionary[#"key"] = fileName;
[mutableDictionary writeToFile:resultsPath atomically:YES];
To retrieve your image from a plist you would do the following
NSString *textPath = [[NSBundle mainBundle] pathForResource:#"propertyListName" ofType:#"plist"];
NSDictionary *thisDict = [NSDictionary dictionaryWithContentsOfFile:textPath];
NSString *imagePath = thisDict[#"key"];
NSData *imageData = [NSData dataWithContentsOfFile:filePath];
UIImage *myImage = [UIImage imageWithData:imageData];
Do not use this NSUserDefaults option for it is wrong, but if you wanted to, this is how you would do it.
[[NSUserDefaults standardUserDefaults] setObject:fileName forKey:#"key"];
[[NSUserDefaults standardUserDefaults] synchronize];
now it's saved easily for you to retrieve. When you want to retrieve the image.
NSString *filePath = [[NSUserDefaults standardUserDefaults] objectForKey:#"key"];
NSData *imageData = [NSData dataWithContentsOfFile:filePath];
UIImage *myImage = [UIImage imageWithData:imageData];
then use myImage as the image. Remember the key must be the same when setting and retrieving.
The best way to store images depends on what your app does.
If you have 100k+ images you probably want to save it manually to the iphone's hard disk over coredata since it will load images faster this way.
However, if you have less than that, then storing images as binary data in core data is what I would recommend.
The benefits of using coredata vs the file system:
Better iCloud Sync Support
No need to manage images on the hard disk as well as what ever you use as a 'persistence store' (coredata/nsuserdefaults/custom)
You can tie images to other data such as name, created date, ect.
Some interesting performance info with filesystem vs coredata: http://biasedbit.com/filesystem-vs-coredata-image-cache/
What I've known:
How make requests to server for uploading I will use AFNetworking
How access photos and videos with help of ALAssetsLibrary
I think I must use CoreData to keep info about:last syncing, photos already uploaded, etc. I worked already with coreData it will no be a problem.
My problems are logic, flow how can achieve this auto back up and of course to be optimum(minimum requests, short way). What steps must follow to achieve this scope?
Any thoughts?
I think CoreData is too heavy in this situation. You may want to use plist to store your info data .here are some steps to follow .
After loading image from server, create a dictionary to store the message you want and create another dictionary to store these messages , and use image's url as the key of this dictionary. It might look like this:
imageUrl = {
lastSyncTime = xxxxxxxxxx,
photoUploaded = 0,
}
Create a plist file to save this dictionary:
- (NSString *)filePath:(NSString *) fileName{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:fileName];
}
[yourImageDictionary writeToFile:[self filePath:#"imageInfo.plist"] atomically:YES];
Read or write your plist file anytime you want:
if ([[NSFileManager defaultManager] fileExistsAtPath:[self filePath:#"imageInfo.plist"]]) {
NSDictionary *imageInfo = [NSDictionary dictionaryWithContentsOfFile:[self filePath:#"imageInfo.plist"]];
}
Which is the best way to store the downloaded images? From there I should be able to use them anywhere in my application, and images should not be deleted at any case (like low space). Any help please.
As per the standard, App related files(Data) need to be stored in document directory only. Once image get download store that images in document directory and maintain unique name for image identification.
-(NSString *)writeDataAsFile:(NSData *)imageData
{
NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * documentsDirectory = [paths objectAtIndex:0];
NSString * thumbNailFilename = [NSString stringWithFormat:#"%#.png",[self GetUUID]]; // Create unique iD
NSString * thumbNailAppFile = [documentsDirectory stringByAppendingPathComponent:thumbNailFilename];
if ([imageData writeToFile:thumbNailAppFile atomically:YES])
{
return thumbNailFilename;
}
return nil;
}
use this method to store the image(downloaded NSData) in document directory.
Retrieve image from the document directory like this
UIImage *thumbnailHomeImage = [UIImage imageWithContentsOfFile:[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:#"%#",imageName]];
take a look at this image caching library. ive used it quite a few times, its really useful