Reading and Writing NSMutableArray to iPhone not working (Works on iOS Simulator) - ios

In an app I am working on I want to have an NSMutableArray (called pathsArray) that I can read from a file in the app's directory, be able create an instance of that array that I can add objects to and/or remove objects from, and then I want to write it back to the file. I have a UILabel that shows the number of contents in this array. My problem: my code below works fine on Xcode's iOS Simulator but when I try to run the app on my actual iPhone the data isn't saved. I know there are a lot of questions on here related to this issue but i can't seem to see what I am doing wrong. Any help would be greatly appreciated.
- (void) loadArrayContents {
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
NSString* filePath = [documentsDirectory stringByAppendingString:#"theArray"];
//Objects contained in an array returned by 'initWithContentsOfFile' are immutable even if the array is mutable
NSArray* contentsArray = [[NSMutableArray alloc] initWithContentsOfFile:filePath];
pathsArray = [[NSMutableArray alloc] initWithArray:contentsArray];
}
and...
- (void) saveArrayContents {
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
NSString* filePath = [documentsDirectory stringByAppendingString:#"theArray"];
[pathsArray writeToFile:filePath atomically:YES]);
}

NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"theArray"];
should solve the issue. The problem with
NSString *filePath = [documentsDirectory stringByAppendingString:#"theArray"];
is that it does not add / in the file path.

Related

Saved photos don't appear on device after update

On my iPhone app, I'm saving pictures associated with an event via this code:
[pngData writeToFile:filePath atomically:YES]; //Write the file
self.thisTransaction.picPath = filePath;
Later I retrieve and display the photo with this code:
UIImage * image = [UIImage imageWithContentsOfFile:thisTransaction.picPath];
Works great on my iPad (I don't have an iPhone).
However, if I update the app by connecting the iPad to my MB Pro after an Xcode code modification not involving the above lines, then disconnect and run it independently, the picture at the expected picPath is not retrieved. All other data associated with thisTransaction in Core Data is intact and unchanged, but the expected picture doesn't appear on the device after the update.
Can someone please tell me where I'm going wrong?
Edit to clarify file path construction
pngData = UIImagePNGRepresentation(capturedImage.scaledImage);
NSLog(#"1 The size of pngData should be %lu",(unsigned long)pngData.length);
//Save the image someplace, and add the path to this transaction's picPath attribute
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0]; //Get the docs directory
int timestamp = [[NSDate date] timeIntervalSince1970];
NSString *timeTag = [NSString stringWithFormat:#"%d",timestamp];
filePath = [documentsPath stringByAppendingPathComponent:timeTag]; //Add the file name
NSLog(#"1 The picture was saved at %#",filePath);
The console log shows this filePath:
/Users/YoursTruly/Library/Developer/CoreSimulator/Devices/65FB33E1-03A7-430D-894D-0C1893E03120/data/Containers/Data/Application/EB9B9523-003E-4613-8C34-4E91B3357F5A/Documents/1433624434
The issue you are having is that the location of an app's sandbox can change over time. Typically this happens when an app is updated. So the worst thing you can do is persist absolute file paths.
What you need to do is persist just the part of the path relative to the base path (the "Documents" folder in this case).
Then when you want to reload the file again, append the persisted relative path to the current value of the "Documents" folder.
So your code needs to be something like this:
Save the file:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0]; //Get the docs directory
int timestamp = [[NSDate date] timeIntervalSince1970];
NSString *timeTag = [NSString stringWithFormat:#"%d",timestamp];
filePath = [documentsPath stringByAppendingPathComponent:timeTag]; //Add the file name
[pngData writeToFile:filePath atomically:YES]; //Write the file
self.thisTransaction.picPath = timeTag; // not filePath
Load the file:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0]; //Get the docs directory
NSString *filePath = [documentsPath stringByAppendingPathComponent:thisTransaction.picPath];
UIImage *image = [UIImage imageWithContentsOfFile:filePath];

XCode - file not found in document directory

I am having random error while reading saved photos from document directory in iPhone. I save photos taken from my app to document directory and then read it from there next time when user come back. However, after XCode 6 & base SDK change to 8.1, this document directory path keeps changing. So sometime I found photos and sometime not.
I read few posts online thats says that not Apple differentiate App from Data and that's why this issue coming up. Anyone has any thoughts on this? Any solution?
This is how I save file to document Directory
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [path firstObject];
NSString *filePath = [documentDirectory stringByAppendingPathComponent:#"key"];
[image writeToFile:path atomically:YES];
And this is how I read it:
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [path firstObject];
NSString *filePath = [documentDirectory stringByAppendingPathComponent:#"key"];
UIImage *cellImage = [[UIImage alloc] initWithContentsOfFile:filePath];
Go to Product - Scheme - Edit Scheme - Options - Working Directory and specify working directory

This used to work: Displaying image using imageWithContentsOfFile

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];

"invalid" results from NSArray arraywithcontentsoffile

I have these plist files that I have used without problem, converting them into arrays with either arraywithcontentsoffile or initwithcontentsoffile. All of a sudden it stopped working, when I inspect the arrays in the debugger i get this as elements.
" Printing description of [0]:(<invalid>) [0] = <error: expected ']'error: 1 errors parsing expression>"
Does anyone have a clue? strange thing is that the command has completely stopped working. I even made a new project using a new file and it still throws me this error.
This is what i do:
NSArray *name = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"example" ofType:#"plist"]];
and the plist is just a simple plist of type array and element-type string
Just Try it...
NSURL *url = [[NSBundle mainBundle] URLForResource:#"YOURPLIST" withExtension:#"plist"];
NSArray *playDictionariesArray = [[NSArray alloc ] initWithContentsOfURL:url];
NSLog(#"Here is the Dict %#",playDictionariesArray);
or you can use following also
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Sample.plist"];
This appears to be a very old Xcode bug. Do an NSLog dump to see if the values are there. This inspector doesn't function even as late as Xcode 6.1! I'll make a radar.

NSURL is always nil dispite encoding

I'm generating a PDF file and am attempting to preview it as shown below, but URL routinely returns NIL despite my formatting (which is what seems to resolve everyone else's issue with this common problem). I must be missing something more. Any ideas?
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDirectory = [path objectAtIndex:0];
docDirectory = [docDirectory stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *URL = [[NSBundle mainBundle] URLForResource:docDirectory withExtension:#"pdf"];
if (URL) {
// Initialize Document Interaction Controller
self->documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:URL];
// Configure Document Interaction Controller
[self->documentInteractionController setDelegate:self];
// Preview PDF
[self->documentInteractionController presentPreviewAnimated:YES];
}
Your path creation seems all out of whack. Try something like this:
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDirectory = [path objectAtIndex:0];
NSString *filename = #"myfile.pdf"; // replace with the actual filename you used
NSString *fullPath = [docDirectory stringByAppendingPathComponent:filename];
NSURL *fullURL = [NSURL fileURLWithPath:fullPath];
In the code you posted you don't provide a filename. You have the Documents directory and the pdf extension. And there is no need to "percent escape" the URL in this case.
You are probably confused of how to obtain the path to your file: NSSearchPathForDirectoriesInDomains is used to get an absolute path to (for example) your documents directory. NSBundle's URLForResource:withExtension: on the other hand searches the app wrapper for a file with the provided name.
Mixing the two would do no good. You should probably just look into the documents directory.

Resources