Saved photos don't appear on device after update - ios

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

Related

Image written through WriteToFile command is missing after app rerun

I am writing an app which downloads image from my server and stores them locally for offline viewing. The codes I use to store the image locally are shown below. Apart from storing the image, I am also able to read the image from the path (which I stored separately).
However when I re-run my code from Xcode to the iPhone (without uninstalling the app from the phone), the stored image file would be missing. Is this expected? Would I face similar issue when my app has been released on App Store and when the user updates the app? Is there a way to keep the file persistent when I re-run them when I update some codes in Xcode?
NSData *imageData = UIImageJPEGRepresentation(image, 1.0);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *imagePath =[documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"file.jpeg",]];
if (![imageData writeToFile:imagePath atomically:YES])
{
// Handling when there is an error
NSLog(#"Failed to store file at path %#",imagePath);
stored.text = #"";
}
else
{ // Handling when write is successful
NSLog(#"Imaged stored path is %#",imagePath);
stored.text = imagePath;
}
[imageView setImage:image];
The code to read the image is shown below:
NSString *imagePathToRead = stored.text;
NSLog(#"Retrieve image from %#",imagePathToRead);
UIImage *image = [UIImage imageWithContentsOfFile:imagePathToRead];
[imageView setImage:image];
I am posting the answer here from rmaddy which solved the issue I was facing. I am posting here so that others can benefit if they are facing similar issue.
For the storing portion:
The stored.text should never store the full path:
stored.text = imagePath;
Instead I should store #"file.jpeg" only.
For the Read portion:
I should always regenerate the full path below when I wanted to read the path instead of the code below:
NSString *imagePathToRead = stored.text;
The corrected codes are:
NSString *imagePathToRead = stored.text;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *imagePath =[documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:imagePathToRead]];
NSLog(#"Retrieve image from %#",imagePath);
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
This solved the issue and the image is able to be read even though the app is re-installed through Xcode.

Data not being written to file?

I'm using FastttCamera as a wrapper on AVFoundation in order to implement a camera in my app. Things appear to work fine until I try to save a captured image with the following code:
- (void)cameraController:(FastttCamera *)cameraController didFinishScalingCapturedImage:(FastttCapturedImage *)capturedImage
{
//Use the image's data that is received
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 stringByAppendingString:timeTag]; //Add the file name
NSLog(#"The picture was saved at %#",filePath);
[self.imageWell setImage:capturedImage.scaledImage];
}
and
...
[pngData writeToFile:filePath atomically:YES]; //Write the file
NSLog(#"The pngData is written to file at %#",filePath);
NSLog(#"2 The size of this file should be %lu",(unsigned long)pngData.length);
self.thisTransaction.picPath = filePath;
...
I try to retrieve the picture later for use in a tableview cell, but nothing shows up. So I started trying to track where things go wrong, and apparently the data is not actually being written to the file specified by the file path. I'm getting the following console readouts from strategically placed NSLogs:
The pngData is written to file at /var/mobile/Containers/Data/Application/114FC402-83E0-4D15-B1E0-68E09DAB34DC/Documents1431292149
The size of this file should be 213633
and this return from the file at the file path:
The size of fileSizeFromFilePath is 0
I've looked at quite a few SO questions, but haven't been able to figure it out. Can someone please show me where I'm going wrong?
The pngData is written to a incorrect path /path/to/sandbox/Documents1431292149 which is not exist.
You should replace
filePath = [documentsPath stringByAppendingString:timeTag];
with
filePath = [documentsPath stringByAppendingPathComponent:timeTag];

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

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.

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

How can I get the file path from a UIImage?

Usually it's the other way around, you use the path to display the image. I was wondering if you can get the path if you already have the image.
if you already have the image i.e. have added the file to your resources, you can use this to get the file path;
NSString *string = [[NSBundle mainBundle] pathForResource:#"IMAGE_FILE_NAME" ofType:#"jpg"]; // or ofType:#"png", etc.
I don't believe it is possible to get it directly from UIImage.
Best way is to save the image in a directory, then you will have the file path.
//image is your UIImage;
if (image != nil)
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:
#"test.png" ];
NSData* data = UIImagePNGRepresentation(image);
[data writeToFile:path atomically:YES];
}
path will be your filepath.
Once a UIImage is created, the image data is loaded into memory and no longer connected to the file on disk. As such, the file can be deleted or modified without consequence to the UIImage and there is no way of getting the source path from a UIImage.

Resources