Best way to persist an array of images? - ios

I'm looking for a way to persist images to an array (or similar) that can be accessed after the app has closed an relaunched -- sorting the images by date is also required. I'm currently able to store the the images to the app's NSDocumentDirectory with the following code:
-(NSString *)currentDateandTime
{
NSDate *today = [NSDate date];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"MMddyyyy_HHmmss"];
NSString *dateString = [dateFormat stringFromDate:today];
return dateString;
}
-(void)saveImageToDocuments
{
NSData *imageData = UIImagePNGRepresentation(image);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *date = [self currentDateandTime];
NSString *imagePath =[documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#_image.png",date]];
}
This means I've got images where the date/time is in the filenames of the image. What is the best way to go about storing these images in an array or dictionary AND sorting them by date/time. Thanks for reading!

I would save the file names and dates in a plist file which is an array of dictionaries of format: #{ #"filename" : imageFileName, #"date": imageDate }.
When you load that plist into an NSArray, you can easily sort it by date by specifying your own comparison method. e.g:
NSArray *filenames = [[NSArray alloc] initWithContentsOfFile:filePath];
NSArray *sortedFilenames = [filenames sortedArrayUsingComparator:
^NSComparisonResult(NSDictionary *dict1, NSDictionary *dict2)
{
NSDate *date1 = dict1[#"date"];
NSDate *date2 = dict2[#"date"];
return [date1 compare:date2];
}

Store the image data and the dates in some dictionaries, then store those dictionaries in an array, then use NSKeyedArchiver to archive the array.
[NSKeyedArchiver archiveRootObject:imageDictionary toFile:#"imagesArray"];
Then when you want to retrieve it:
NSArray * retrievedImages = [NSKeyedUnarchiver unarchiveObjectWithFile:#"imagesArray"];
Then just compare the dates in the various dictionaries in the retrieved array.

Related

Modified (filtered) UIImage doesn't save in document directory

When I save an image taken with the camera without filtering it goes smoothly, but if i filter the image, when I save it, it doesn't work.
i'm using : [CIFilter filterWithName:#"CIColorControls"] and its options to filter.
Here the code used to save the image (wether or not its been filtered).
- (IBAction)save:(id)sender {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
NSData *binaryImageData = UIImageJPEGRepresentation(_photo, 0.3); // PNG without compression paramenter works too
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:#"yyyy-MM-dd-HH-mm"];
NSString *imageName = [formatter stringFromDate:[NSDate date]];
[binaryImageData writeToFile:[basePath stringByAppendingPathComponent:imageName] atomically:YES];
}
EDIT :
When I use the breakpoint, the NSData receives (counter) data and becomes nil when I proceed to NSDateFormatter

How to get the data from a row in an NSArray using only part of the row to search

Lets say i have an array filled with several rows
dates = [NSArray arrayWithObjects:#"2012-05-01||Blue", #"2012-05-02||Red", #"2012-05-03||Green", #"2012-05-04||Orange", #"2012-05-05||Yellow", #"2012-05-06||Purple", #"2012-05-07||Silver", nil];
and then I have a date to search by 2012-05-01
How do i search for an object by only part of it without doing a big for( loop because this array will theoretically hold a few thousand cells.
EDIT:
if necessary how do i load the data into an NSDictionary? (i've never used them)
I know i can get the data like so
for(NSString *row in dates) {
NSString *date = [[row componentsSeperatedByString:#"||"] objectAtIndex:0];
NSString *color = [[row componentsSeperatedByString:#"||"] objectAtIndex:1];
}
NSMutableDictionary *colorsAndDates = [[NSMutableDictionary alloc] init];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd"];
for(NSString *row in dates) {
NSString *dateString = [[row componentsSeparatedByString:#"||"] objectAtIndex:0];
NSDate *date = [dateFormatter dateFromString:dateString];
NSString *color = [[row componentsSeparatedByString:#"||"] objectAtIndex:1];
[colorsAndDates setObject:color forKey:date];
}
If I am correct, this will format it into an NSDictionary, and then I can grab the color using:
NSString *dateToFind = #"2012-05-01";
NSDate *date = [dateFormatter dateFromString:dateToFind];
NSString *theColor = [colorsAndDates objectForKey:date];
Knowing this, I will have to go back and make it all revolve around NSDictionary instead of the strings they're in.
There's a couple of things you can do other than looping through the array:
1) Use a sorted array. Even if you need to keep the data in the initial order, you can make a sorted copy of it. Then you can do a binary search (if there are n items, check the n/2 item, if it's less than your date and repeat the process with only the data from n/2 to n, or if it's greater, then repeat with the data from 0 to n/2. Sort once, find many.
2) Create a dictionary on the fly using the data. You can use the the 10 character prefix of the data as the key. You'll have to maintain the dictionary along with the array, so this may not be practicable if you have a lot of changes. Create dictionary once, find many. (Note: despite the answers you've gotten, a dictionary may not be the best solution, particularly if you don't have unique keys (i.e. more than one record with the same date).
3) Forget the arrays and store your data in sqlite, and write a sql statement to get it. Most useful if you have a whole lot of data. You can use sqlite to build a primary key if you have duplicate dates in your data.
Creating a dictionary:
NSDictionary *dateDictionary = #{
#"2012-05-01" : #"Blue",
#"2012-05-02" : #"Red",
#"2012-05-03" : #"Green",
#"2012-05-04" : #"Orange",
#"2012-05-05" : #"Yellow",
#"2012-05-06" : #"Purple",
#"2012-05-07" : #"Silver"
};
NSString *date = #"2012-05-01";
NSString *dateColor = dateDictionary[date];
Using the example you gave (looping through the array to create a dictionary):
NSMutableDictionary *dateDictionary = [NSMutableDictionary dictionary];
for(NSString *row in dates) {
NSString *date = [[row componentsSeperatedByString:#"||"] objectAtIndex:0];
NSString *color = [[row componentsSeperatedByString:#"||"] objectAtIndex:1];
dateDictionary[date] = color;
}
NSString *date = #"2012-05-01";
NSString *dateColor = dateDictionary[date];

Save NSLog into a Local File

I'm learning how to develop for iPhone and i need to save de NSLog output on a local file on my machine to analyse the result in because I`ll run the application for a long time and I need to check after some hours running what was the output (and I want to save the output file on my machine from time to time, for example after every 30min).
How can I save the xcode output into a file?
Possibly not what you want, but I use this:
- (void)logIt:(NSString *)string {
// First send the string to NSLog
NSLog(#"%#", string);
// Setup date stuff
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"YYYY-dd-MM"];
NSDate *date = [NSDate date];
// Paths - We're saving the data based on the day.
NSString *path = [NSString stringWithFormat:#"%#-logFile.txt", [formatter stringFromDate:date]];
NSString *writePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:path];
// We're going to want to append new data, so get the previous data.
NSString *fileContents = [NSString stringWithContentsOfFile:writePath encoding:NSUTF8StringEncoding error:nil];
// Write it to the string
string = [NSString stringWithFormat:#"%#\n%# - %#", fileContents, [formatter stringFromDate:date], string];
// Write to file stored at: "~/Library/Application\ Support/iPhone\ Simulator/*version*/Applications/*appGUID*/Documents/*date*-logFile.txt"
[string writeToFile:writePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
}
This writes the data into a file on your device (a daily file). If you want it to reset after each session you can surely modify the code to do that.
And of course you'll have to change all your existing NSLog() calls to use [self logIt:] instead.
This also works on a real device (but the file location is different of course).

How to save unique image name in document directory

In my ios app i am stuck on a task. I need to take pic from camera and save it on document directory.Problem is that i want save unique name of image.I was try to add current time with a name. but there are length problem to save image.Please suggest me how can i do that task.
Thanks
Given a proposed name like NString *name = #"Lake":
NSString *myUniqueName = [NSString stringWithFormat:#"%#-%u", name, (NSUInteger)([[NSDate date] timeIntervalSince1970]*10.0)];
EDIT: updated so that the only chance of a duplicate is the same original name, submitted within 100 ms of the first (virtually impossible in my opinion, if this is a concern use 100 instead of 10)
-(NSString*)getFilePathToSaveUnUpdatedImage
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *directory = [paths objectAtIndex:0];
for (int i = 0 ; TRUE ; i++)
{
if(![[NSFileManager defaultManager]fileExistsAtPath:[NSString stringWithFormat:#"%#/UnUpdatedItems/Image%d.png", directory , i]])
return [NSString stringWithFormat:#"%#/UnUpdatedItems/Image%d.png", directory , i];
}
}
Try like this just formate the date and save the image
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSDate *now = [NSDate date];
NSString *theDate = [dateFormat stringFromDate:now];
[data writeToFile:[NSString stringWithFormat:#"%#.png",theDate] atomically:YES];
use this line of code to give name.
[NSDateFormatter localizedStringFromDate:[NSDate date] dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterShortStyle]]
This works for me for same problem.
-(NSString*)getImagePathName
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *directory = [paths objectAtIndex:0];
for (int i = 0 ; TRUE ; i++)
{
if(![[NSFileManager defaultManager]fileExistsAtPath:[NSString stringWithFormat:#"%#/Image%d.png", directory , i]])
return [NSString stringWithFormat:#"%#/Image%d.png", directory , i];
}
}

Log Accelerometer data to a file on Iphone IOS

Hi I am trying to write to a file from the accelerometer data. Here is my code:
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
//xax.text = [NSString stringWithFormat:#"X:[%2.6f]",acceleration.x];
//yax.text = [NSString stringWithFormat:#"Y:[%2.6f]",acceleration.y];
//zax.text = [NSString stringWithFormat:#"Z:[%2.6f]",acceleration.z];
NSString *acc_x = [[NSString alloc] initWithFormat:#"X:[%2.6f]",acceleration.x];
NSString *acc_y = [[NSString alloc] initWithFormat:#"Y:[%2.6f]",acceleration.y];
NSString *acc_z = [[NSString alloc] initWithFormat:#"Z:[%2.6f]",acceleration.z];
xax.text = acc_x;
yax.text = acc_y;
zax.text = acc_z;
[acc_x release];
[acc_y release];
[acc_z release];
//wfm == 2 //Initialization of Appending to the file
if (wfm == 2)
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *txtFileName = [[NSString alloc] initWithFormat:#"tmp/%#.txt",txtName.text];
NSString *fileName = [NSHomeDirectory() stringByAppendingPathComponent:txtFileName];
//NSString *fileName = [NSHomeDirectory() stringByAppendingPathComponent:#"tmp/acc_w_trial2.txt"];
//Current Contents of the file
NSString *fileCurrent = [[NSString alloc] initWithContentsOfFile:fileName];
//Date and Time of each Accelerometer Data
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd 'at' HH:mm:ss:SSS"];
NSDate *date = [NSDate date];
NSString *formattedDateString = [dateFormatter stringFromDate:date];
NSString *msg = [[NSString alloc] initWithFormat:#"%#%# %#%#%# \n",fileCurrent,formattedDateString,xax.text,yax.text,zax.text];
//Convert NSstring to NSData
NSData* data=[msg dataUsingEncoding: [NSString defaultCStringEncoding]];
//bool fileCreationSuccess = [fileManager createFileAtPath:fileName contents:data attributes:nil];
[fileManager createFileAtPath:fileName contents:data attributes:nil];
[msg release];
[dateFormatter release];
[fileCurrent release];
[txtFileName release];
}
}
I get the warning level 1 and level 2. Is there a way I can release the NSFileManager memory to prevent this from locking up?
Your handler method to collect accelerometer data seems not very performant. You are allocating the resources (memory, file) everytime which can take a long time.
You should allocate the needed resources only once (i.e. use dispatch_once) and keep the file open. Use a NSFileHandle (method fileHandleForWritingAtPath) in order to append the data at the end of the file.
Furthermore NSHomeDirectory() is not where you're supposed to save user data, as iOS apps are sandboxed.
Either use NSTemporaryDirectory() or write in the Documents or Library Folder. The following is from Apple's sample code, usually in application delegate class:
- (NSString *)applicationDocumentsDirectory {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
return basePath;
}
You can try using an Autorelease Pool.

Resources