How to save data locally in app? [duplicate] - objective-c

This question already has answers here:
Working with data in iOS Apps (What to choose? NSData, CoreData, sqlite, PList, NSUserDefaults)
(2 answers)
Closed 9 years ago.
I've been struggling with this for ages now and I really need some good help here. :)
I have an app where I'm parsing a quite big JSON into appdelegate's didFinishLaunchingWithOptions.
My Model Objects are:
Tab:
NSString *title
NSMutableArray *categories
Category:
NSString *title
NSMutableArray *items
Item
NSString *title
NSString *description
UIImage *image
I need to save the data locally, cause the parsing takes about 15 seconds every time my app starts. I'm using the SBJSON framework.
Here's my code for parsing:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"json_template" ofType:#"json"];
NSString *contents = [NSString stringWithContentsOfFile: filePath encoding: NSUTF8StringEncoding error: nil];
SBJsonParser *jsonParser = [[SBJsonParser alloc] init];
NSMutableDictionary *json = [jsonParser objectWithString: contents];
tabs = [[NSMutableArray alloc] init];
jsonParser = nil;
for (NSString *tab in json)
{
Tab *tabObj = [[Tab alloc] init];
tabObj.title = tab;
NSDictionary *categoryDict = [[json valueForKey: tabObj.title] objectAtIndex: 0];
for (NSString *key in categoryDict)
{
Category *catObj = [[Category alloc] init];
catObj.name = key;
NSArray *items = [categoryDict objectForKey:key];
for (NSDictionary *dict in items)
{
Item *item = [[Item alloc] init];
item.title = [dict objectForKey: #"title"];
item.desc = [dict objectForKey: #"description"];
item.url = [dict objectForKey: #"url"];
if([dict objectForKey: #"image"] != [NSNull null])
{
NSURL *imgUrl = [NSURL URLWithString: [dict objectForKey: #"image"]];
NSData *imageData = [NSData dataWithContentsOfURL: imgUrl];
item.image = [UIImage imageWithData: imageData];
}
else
{
UIImage *image = [UIImage imageNamed: #"standard.png"];
item.image = image;
}
[catObj.items addObject: item];
}
[tabObj.categories addObject: catObj];
}
[tabs addObject: tabObj];
}
What is the best way of doing this? Using Core Data or NSFileManager?
If you have som code example too it will make me very happy.
This is the last thing i need to fix before the app is ready for app store and it just kills me! I can't solve this problem.

If you are working on iOS then you save a file to the Documents folder. On Mac OS X it would be in the Application Support folder. Since you are on iOS, read this answer for how to access the Documents folder.
All of the objects that you want to store should implement NSCoding. The above variables already do. Should you want to store the tabs, categories and items directly they would need to implement NSCoding. Then all you need is to serialize them to a file. When opening you app you can look for this file and get your objects back without parsing.
The code should look something like this (untested and error checking is ommited for brevity):
- (void) saveStateToDocumentNamed:(NSString*)docName
{
NSError *error;
NSFileManager *fileMan = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docPath = [paths[0] stringByAppendingPathComponent:docName];
if ([fileMan fileExistsAtPath:docPath])
[fileMan removeItemAtPath:docPath error:&error];
// Create the dictionary with all the stuff you want to store locally
NSDictionary *state = #{ ... };
// There are many ways to write the state to a file. This is the simplest
// but lacks error checking and recovery options.
[NSKeyedArchiver archiveRootObject:state toFile:docPath];
}
- (NSDictionary*) stateFromDocumentNamed:(NSString*)docName
{
NSError *error;
NSFileManager *fileMan = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docPath = [paths[0] stringByAppendingPathComponent:docName];
if ([fileMan fileExistsAtPath:docPath])
return [NSKeyedUnarchiver unarchiveObjectWithFile:docPath];
return nil;
}

Related

What causes a "Virtual Memory exhausted" error?

Alright.. Here's the thing.. I am building an app in which when the user taps on download button it downloads a bunch on images (296, to be exact).
In simulator everything works flawless, on my iPhone (4S) on around 100th image it crashes with error:
malloc: * mach_vm_map(size= "some random number") failed (error code= 3)* error: can't allocate region
libBacktraceRecording.dylib: allocate_free_list_pages() -- virtual memory exhausted!
Here's the code I wrote for downloading those images:
-(void)getData
{
NSError *error;
int i;
NSArray *brojLinije = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"linije" ofType:#"plist"]];
NSArray *urlSlike = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"urlSlike" ofType:#"plist"]];
NSArray *pocetno = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"pocetno" ofType:#"plist"]];
NSArray *sortiranje = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"sort" ofType:#"plist"]];
NSArray*paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *desktopDir = [paths firstObject];
UIImage *image1 = [[UIImage alloc] init];
for (i = 0; i<296; i++) {
NSString *brojLinije1 = [NSString stringWithFormat:#"%#",[brojLinije objectAtIndex:i]];
NSString *pocetno1 = [NSString stringWithFormat: #"%#", [pocetno objectAtIndex:i]];
NSString *tableSort = [NSString stringWithFormat: #"%#", [sortiranje objectAtIndex:i]];
image1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat: #"http://www.busevi.com/images/stories/Red-Voznje/Gradski-Prevoz-BG/linija.%#.png", [urlSlike objectAtIndex:i ] ]]]];
NSData *data1 = [NSData dataWithData:UIImageJPEGRepresentation(image1, 0.1)];
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
NSString *pngFilePath = [NSString stringWithFormat:#"%#%#.jpg",desktopDir,[urlSlike objectAtIndex:i]];
[data1 writeToFile:pngFilePath atomically:YES];
[newManagedObject setValue:brojLinije1 forKey:#"brojLinije"];
[newManagedObject setValue:data1 forKey:#"imageData"];
[newManagedObject setValue:pocetno1 forKey:#"pocetnoStajaliste"];
[newManagedObject setValue:tableSort forKey:#"sort"];
NSLog(#"%d / 296", i);
}
[self.managedObjectContext save:&error];
}
Only thing I know is that the image allocation frequency (too much allocating and no time to automatically release) is making the problem, AND that I have tried every method I know so far, AND I HAVE watched A LOT of "Instruments" app tutorials and only one helped (to find the source of filling virtual memory) but I still can't solve my problem.
You can use a local autorelease pool inside of the loop to immediately release any objects that were created in the body of the loop.
for (i = 0; i<296; i++) {
#autoreleasepool {
// loop body goes here...
}
}
While using SDWebImage framework I encountered a lot of bugs and unanswered crashes from the app. SDWebImage is awesome if the count of images that are about to be downloaded is lower that, let's say 50. Because, when downloading one by one image that are showed in TableViewCell + fast scrolling (fast flicking), the app receives memory warning a couple of times while the TableView is still scrolling (SDWebImage will clear memory ONLY when TableView is slowly scrolling or not scrolling at all) so it crashes the app.
So my only solace with app crashing while downloading 300+ images was simple Apple's method called dispatch_async. More about it here.
And this is how I solved my problem (I just had to move everything from my original -(void)getdata method to dispatch_async block. DONE!
So now it looks like this:
-(void)getData {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(#"Downloading Started");
slike = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"slike" ofType: #"plist"]];
brojevi = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"linije" ofType:#"plist"]];
pocetnaStajalista = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"pocetno" ofType:#"plist"]];
sort = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"sort" ofType:#"plist"]];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Linija" inManagedObjectContext:self.managedObjectContext];
NSString *brojLinije;
NSString *pocetnoStajaliste;
NSString *sortiranje;
NSData *data;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory,#"filename.png"];
for (int i = 0; i<314; i++) {
NSManagedObject *novaLinija = [[NSManagedObject alloc]initWithEntity:entity insertIntoManagedObjectContext:self.managedObjectContext];
brojLinije = [NSString stringWithFormat:#"%#",brojevi[i]];
pocetnoStajaliste = [NSString stringWithFormat:#"%#",pocetnaStajalista[i]];
data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat: #"http://www.busevi.com/images/stories/Red-Voznje/Gradski-Prevoz-BG/linija.%#.png",slike[i]]]];
[data writeToFile:filePath atomically:YES];
sortiranje = [NSString stringWithFormat: #"%#", sort[i]];
[novaLinija setValue:data forKey:#"slikaLinije" ];
[novaLinija setValue:brojLinije forKey:#"brojLinije"];
[novaLinija setValue:pocetnoStajaliste forKey:#"pocetnoStajaliste"];
[novaLinija setValue:sortiranje forKey: #"sort"];
NSLog(#"%d / 314", i+1);
NSError *error;
[self.managedObjectContext save:&error];
} }
Hope this helps others with same problem. Good Luck and Happy Coding!
Used all of your and my suggestions and possible solutions, but, I'm sorry, none worked.
The point in this case, when app needs to download A LOT of photos, you really should use SDWebImageDownloader Class Reference.
I know It's frustrating to change the whole method and to realize the previous method (of downloading photos) is useless, so HERE is the tutorial and example on how to use SDWebImageDownloader Class. Good Luck.

How to write and read data from plist to tableview

Hi I am trying to make bookmarks for my browser.
Title of Page, Url of Page, any Comments related to page.
I tried to save it in plist, but unsuccessful. Can anyone can help me to save these thing to plist and retrive in table view. So, when user tap on title it will open url in UIWebView.
Here is the code I have tried, so far:
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"bookmarks.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: path])
{
NSString *bundle = [[NSBundle mainBundle] pathForResource:#"bookmarks" ofType:#"plist"];
[fileManager copyItemAtPath:bundle toPath: path error:&error]; //6
}
NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
NSString *writeUrl = #"Page URL One";
NSString *writeTitle = #"Page Title One";
NSString *writeComment = #"Page comments";
[data setObject:[NSString stringWithString:writeUrl] forKey:#"url"];
[data setObject:[NSString stringWithString:writeTitle] forKey:#"title"];
[data setObject:[NSString stringWithString:writeComment] forKey:#"comment"];
[data writeToFile: path atomically:YES];
NSMutableDictionary *savedUrl = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
NSString *value;
value = [[savedUrl objectForKey:#"url"] stringValue];
NSLog(#"%#", value);
UPDATE: I successfully saved and retrieved data to and from plist. Issue is comming in this line
value = [[savedUrl objectForKey:#"url"] stringValue];
By removing stringValue solve the problem.
value = [savedUrl objectForKey:#"url"];
Now My second issue. I make three items named url, title, comment, types String in plist file.
How can i store different urls. Like
name website: inforains
url: inforains.com
title: Info Rains
comment: good website articles
name website: hitechnology
url: hitechnology.com
title: Hitechnology
comment: hmmm
ans soo on..
how can I store data like this.. so all name website will show on tableview and when user click on anyone, data related to that website will show. I hope i clear my question.
To store multiple records as three items named url, title, comment, types String in plist file
change types from string to dictionary and store data in each dictionary individually for key as 1,2,3 ...
OR
Use three mutable array for each url,title and comment and add object at index 0 at the time of saving it.
and access them when required as nsmutable array.
Change this line
value = [[savedStock objectForKey:#"url"] stringValue];
to
value = [savedUrl objectForKey:#"url"];
because you are saving NSString in dictionary... not NSNumber.
Second issue:
//create mutable array to save all objects
NSMutableArray *objectsArray = [data objectForKey:#"objectsArray"];
if(!objectsArray) {
objectsArray = [[NSMutableArray alloc] init];
}
//create and add dictionary into array
NSDictionary *dictionary = [[NSDictionary alloc] initWithObjects:[NSArray arrayWithObjects:#"url1", #"title1", #"comment2",nil] forKeys:[NSArray arrayWithObjects:#"url", #"title", #"comment",nil]];
[objectsArray addObject:dictionary];
[data setObject:objectsArray forKey:#"objectsArray"];
[data writeToFile: path atomically:YES];
// to read data
NSMutableDictionary *savedUrl = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
NSMutableArray *objectsArraySAved = [savedUrl objectForKey:#"objectsArray"];
for (NSMutableDictionary *dic in objectsArraySAved) {
NSLog(#"URL %#", [dic valueForKey:#"url"]);
}
Are you sure [data writeToFile: path atomically:YES]; works? It returns a BOOL, you should check it.
Are you sure savedURL != nil?
For your new problem, you should put all your dictionaries in a mutable array.
NSMutableArray *bookmarkArray = [[NSMutableArray alloc]init];
[bookmarkArray addObject:data];

Overwrite with remote .plist a local .plist file

My application loads a local list.plist file at launch.
Then it has a refreshTable button which fetch a remote version of the .plist file from my website.
App Launch
local list.plist loads
user hits refreshList button
local list.plist is overwritten by remote list.plist
local list.plist updated until remote list.plist updates again
Method to initialize data:
//Remote data
list = [[NSMutableArray alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://mywebsite.com/list.plist"]];
NSSortDescriptor *descriptor = [[[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)] autorelease];
sortedList = [[list sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]] retain];
//Local data
NSString *localPath = [[NSBundle mainBundle] pathForResource:#"list" ofType:#"plist"];
localList = [[NSMutableArray alloc] initWithContentsOfFile:localPath];
NSSortDescriptor *localDescriptor = [[[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)] autorelease];
localSortedList = [[localList sortedArrayUsingDescriptors:[NSArray arrayWithObject:localDescriptor]] retain];
This is the method to refresh:
- (void) refreshTable:(id)sender
{
//Remote .plist
list = [[NSMutableArray alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://mywebsite.com/list.plist"]];
NSSortDescriptor *descriptor = [[[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)] autorelease];
sortedList = [[list sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]] retain];
[self.tableView reloadData];
//now write remote plist to local plist
}
After i downloaded the remote plist how can i write over the local plist?
I was thinking to empty the local array containing the local plist and fill it with the remote array and i did it this way:
I solved in the way i thought:
//Remote .plist
list = [[NSMutableArray alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://phillipapps.com/mntlion/list.plist"]];
NSSortDescriptor *descriptor = [[[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)] autorelease];
sortedList = [[list sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]] retain];
NSLog(#"list: %#",list);
[localList removeAllObjects];
[localList addObjectsFromArray:list];
localSortedList = [[localList sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]] retain];
NSLog(#"locallist: %#",localList);
[self.tableView reloadData];
It works, but how can i write over localList with the contents of list?
so … after a view hours in chat we got the problem solved.
- (NSArray*)readPlist
{
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *plistPath = [[documentPaths lastObject] stringByAppendingPathComponent:#"localFile.plist"];
NSFileManager *fMgr = [NSFileManager defaultManager];
if (![fMgr fileExistsAtPath:plistPath]) {
plistPath = [[NSBundle mainBundle] pathForResource:#"template" ofType:#"plist"];
}
return [NSArray arrayWithContentsOfFile:plistPath];
}
- (void)writePlist:(NSArray*)arr
{
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *plistPath = [[documentPaths lastObject] stringByAppendingPathComponent:#"localFile.plist"];
NSFileManager *fMgr = [NSFileManager defaultManager];
if (![fMgr fileExistsAtPath:plistPath])
[fMgr removeItemAtPath:plistPath error:nil];
[arr writeToFile:plistPath atomically:YES];
}
initializing the ivar:
self.plistArray = [self readPlist];
and after loading the new plist from the server you have to call this code:
self.plistArray = [NSArray arrayWithContentsOfURL:[NSURL URLWithString:#"http://mywebsite.com/list.plist"]];
[self writePlist:plistArray]; // e.g. for caching
[self.tableView reloadData];
I do almost the exact thing you're looking for in an application of mine. You can't write to the NSBundle so the steps are something like this:
Try to load plist from cache directory, if it succeeds go to 3.
Load plist from bundle
Check if loaded plist is up to date (or, trigger further steps by the press of a button)
Download new plist
Save to cache directory
The code looks something like this:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cache = [paths objectAtIndex:0];
ratios = [NSDictionary dictionaryWithContentsOfFile:[cache stringByAppendingPathComponent:#"devices.plist"]];
if (ratios == nil) {
ratios = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"devices" ofType:#"plist"]];
}
NSString *device = [[UIDevice currentDevice] machine];
NSDictionary *d = [ratios objectForKey:device];
if (d!=nil) {
pixelInchRatio = [[d objectForKey:#"pixelInchRatio"] doubleValue];
bezelWidth = [[d objectForKey:#"bezelWidth"] doubleValue];
bezelHeight = [[d objectForKey:#"bezelHeight"] doubleValue];
} else if (fetch) {
[[[[RulerDimensionDownload alloc] init] autorelease] startDownload];
}
Then in the downloader it saves like so:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cache = [paths objectAtIndex:0];
[[NSFileManager defaultManager] createDirectoryAtPath:cache withIntermediateDirectories:YES attributes:nil error:nil];
[ratios writeToFile:[cache stringByAppendingPathComponent:#"devices.plist"] atomically:YES];
Some explanations:
The first few lines in each sample, the paths and cache definition, simply get the location of the cache directory for the application. I use this to store the most up-to-date version I'm my plist.
So, in the loading code, I first try to load the plist from the cache directory. If this fails (ratios is null) I then load it from my application bundle (this is the version of the plist that I ship with the app).
After that, I check to see if the plist has the information needed. (the plist has a definition for each device type. If the device isn't in the plist then I know I need to try to update the plist)
If the plist is out of date I start the download using a class I wrote: RulerDimensionDownload. Once it completes the download I save the file into the cache directory. Then, next time the plist needs to be loaded it will be loaded first and the shipped plist will never be looked at. (I also send a notification with the new plist)

Can't figure out about saving files

I am trying to save my object to the file system on an iPad, but I seem to be doing something wrong. Here is how I have archived the object:
NSString *localizedPath = [self getPlistFilePath];
NSString *fileName = [NSString stringWithFormat:#"%#.plist", character.infoName];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:character];
fileName = [fileName stringByReplacingOccurrencesOfString:#" " withString:#"_"];
localizedPath = [localizedPath stringByAppendingPathComponent:fileName];
NSLog(#"File Path: %#", localizedPath);
if(data) {
NSError *writingError;
BOOL wasWritten = [data writeToFile:localizedPath options:NSDataWritingAtomic error:&writingError];
if(!wasWritten) {
NSLog(#"%#", [writingError localizedDescription]);
}
}
Now, this creates a plist file that I can see and read on the file system. When I try to use the following to unarchive it though:
NSError *error;
NSString *directory = [self getPlistFilePath];
NSArray *files = [[NSFileManager defaultManager]contentsOfDirectoryAtPath:directory error:&error];
NSMutableArray *characters = [[NSMutableArray alloc]init];
for(NSString *path in files) {
if(![path hasSuffix:#"plist"]) {
continue;
}
NSString *fullPath = [directory stringByAppendingPathComponent:path];
NSData *data = [NSData dataWithContentsOfFile:fullPath];
IRSkillsObject *object = [NSKeyedUnarchiver unarchiveObjectWithData:data]; // get EXEC_BAD_ACCESS here...
[data release];
[characters addObject:object];
}
I get an EXEC_BAD_ACCESS error.
The IRSkillsObject conforms to the NSCoding protocol. You can see, I commented the line that I get the error on.
I am sure it's something I am doing wrong, but I just can't see it. I have tried to step through with the debugger (placing a break point in the initWithCoder: method of the object) but I don't get any errors then. In fact, it places the data in the object properly as I watch. But once it's done loading the data, it gives the error. I have tried using the retain method, but that doesn't help.
Any help that you can provide would be greatly appreciated!
You are releasing data without allocating it.
NSData *data = [NSData dataWithContentsOfFile:fullPath];
IRSkillsObject *object = [NSKeyedUnarchiver unarchiveObjectWithData:data];
[data release];
So try this:
NSData *data = [[NSData alloc] initWithContentsOfFile:fullPath];
IRSkillsObject *object = [NSKeyedUnarchiver unarchiveObjectWithData:data];
[data release];
When an EXEC_BAD_ACCESS error is found. Usually is because some data has been released but it is still needed in the code.
Maybe there is a property inside your IRSkillsObject not retained in -initWithCoder:

Retrieve all images from NSDocumentDirectory and storing into an array

Currently i'm using these codes to save my images into NSDocumentDirectory. I use this counter as the naming convention for them.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)selectedImage editingInfo:(NSDictionary *)editingInfo
{
[self.popoverController dismissPopoverAnimated:YES];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDir stringByAppendingPathComponent:[NSString stringWithFormat:#"%d.png", counter]];
UIImage *image = imageView.image;
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savedImagePath atomically:NO];
}
I use this method because it's easier for me to retrieve all of them by using a loop. I want to retrieve all the images from the NSDocumentDirectory so that i can display them in another view. The following codes show how i retrieve them.
-(NSMutableArray *)GetImage:(NSMutableArray *)arrayImgNames
{
NSMutableArray *tempArray;
for(int i=0;i<[arrayImgNames count]; i++)
{
NSArray *paths1 = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths1 objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent: [arrayImgNames objectAtIndex:i]];
[tempArray addObject:[[UIImage alloc] initWithContentsOfFile:filePath]];
return tempArray;
}
}
However, i do not wish to use the counter as a naming convention for my images. I want to use proper names for them but if i do so, i will have to change my method of retrieving all the images.
Is there any other way that i can retrieve all images other than this method i mentioned?
You can retrieve files using next approach:
NSURL *url = [[AppDelegate sharedAppDelegate] applicationDocumentsDirectory];
NSError *error = nil;
NSArray *properties = [NSArray arrayWithObjects: NSURLLocalizedNameKey, NSURLLocalizedTypeDescriptionKey, nil];
NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:url
includingPropertiesForKeys:properties options:(NSDirectoryEnumerationSkipsPackageDescendants)
error:&error];
In files paths to all files of documents directory will be stored. Next code will help you to get there names:
NSURL *url = [files objectAtIndex:index];
NSString *localizedName = [url lastPathComponent];