Writing/reading NSData to file failing - iphone

I have an in-memory cache that I would like to write out to file on viewWillDisappear and read in back into memory on viewDidLoad. My code:
- (void)viewDidLoad
{
[super viewDidLoad];
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSArray *fileArray = [fileManager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask];
NSString *filePath = [NSString stringWithFormat:#"%#cache_%d", [fileArray lastObject], self.index];
NSURL *fileUrl = [NSURL URLWithString:filePath];
if ([fileManager fileExistsAtPath:filePath]) {
self.thumbnailsCache = [NSDictionary dictionaryWithContentsOfURL:fileUrl];
}
}
- (void)viewWillDisappear:(BOOL)animated
{
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSArray *fileArray = [fileManager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask];
NSString *filePath = [NSString stringWithFormat:#"%#cache_%d", [fileArray lastObject], self.index];
NSURL *fileUrl = [NSURL URLWithString:filePath];
[self.thumbnailsCache writeToURL:fileUrl atomically:YES];
}
Based on some NSLog and debugging, it seems to write the file successfully, but on trying to read it simply says file not found. What am I doing wrong? Thanks.
Edit: self.thumbnailsCache is an NSDictionary of NSData objects.

You're creating your filePath incorrectly.
fileArray is an array of URL's and not NSStrings (which is what your code is assuming).
So if you're taking the last URL as being the cache directory you want to use, you can create the cache file via something like this:
NSURL * cacheURL = (NSURL *)[fileArray lastObject];
if(cacheURL)
{
NSURL * fileToWrite = [cacheURL URLByAppendingPathComponent: [NSString stringWithFormat:#"%#cache_%d", self.index]];
}
Or, in the context of your code:
- (void)viewDidLoad
{
[super viewDidLoad];
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSArray *fileArray = [fileManager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask];
NSString *filePath = [NSString stringWithFormat:#"%#cache_%d", [fileArray lastObject], self.index];
NSURL * cacheURL = (NSURL *)[fileArray lastObject];
if(cacheURL)
{
NSURL * fileToRead = [cacheURL URLByAppendingPathComponent: [NSString stringWithFormat:#"%#cache_%d", self.index]];
if(fileToRead && ([fileManager fileExistsAtPath:fileToRead]) {
self.thumbnailsCache = [NSDictionary dictionaryWithContentsOfURL:fileToRead];
}
}
}
- (void)viewWillDisappear:(BOOL)animated
{
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSArray *fileArray = [fileManager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask];
NSString *filePath = [NSString stringWithFormat:#"%#cache_%d", [fileArray lastObject], self.index];
NSURL * cacheURL = (NSURL *)[fileArray lastObject];
if(cacheURL)
{
NSURL * fileToWrite = [cacheURL URLByAppendingPathComponent: [NSString stringWithFormat: #"%#cache_%d", self.index]];
if(fileToWrite)
{
[self.thumbnailsCache writeToURL:fileToWrite atomically:YES];
}
}
}

Related

Convert ImagePath in DocumentDirectory to NSURL Iphone

I am using following code
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSURL *myUrl = [[NSURL alloc] initWithString:self.selectedRing.ringThumbNailImagePath];
[Utilities responseDataFromURL:myUrl completionBlock:^(NSData *fileData, NSError *err)
{
if (err != nil)
{
[self.indicator stopAnimating];
[Utilities errorDisplay:#""];
}
else
{
NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"Test.igo"];
NSLog(#"FilePath: %#", filePath);
if ([fileData writeToFile:filePath atomically:YES])
{
CGRect rect = CGRectMake(0 ,0 , 0, 0);
NSURL *igImageHookFile = [[NSURL alloc] initWithString:[[NSString alloc] initWithFormat:#"file://%#", filePath]];
NSLog(#"JPG path %#", filePath);
filePath is
Users/umar/Library/Application Support/iPhone Simulator/6.1/Applications/B45223CF-B437-4617-A02D-DCA91C965A5A/Documents/Test.igo
however i get Nil igImageHookFile NSURL. What is wrong?
Use fileURLWithPath for converting your Path of Document Directory to NSURL like this in piece of code:
NSURL *myImagePath = [NSURL fileURLWithPath:filePath]; //here filePath is your document directory full path with extantionm
For Example:
NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"Test.igo"];
NSLog(#"FilePath: %#", filePath);
if ([fileData writeToFile:filePath atomically:YES])
{
CGRect rect = CGRectMake(0 ,0 , 0, 0);
NSURL *igImageHookFile = [NSURL fileURLWithPath:filePath];
NSLog(#"URL from path %#", igImageHookFile);
OUTPUT of path URL something like this:-
file://localhost/Users/umar/Library/Application Support/iPhone Simulator/6.1/Applications/B45223CF-B437-4617-A02D-DCA91C965A5A/Documents/Test.igo
Try this:
NSURL *url = [NSURL URLWithString:[Request stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
Hope it Helps!!

getting too much memory allocation with no leaks, app crashes more likely on ipad

I have this code of getting two video frames each of two different video. I am merging them into single frame and then creating a movie with merged frames. But the problem is app crashes due to memory warning. Here is my code:
NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:#"/Documents/movie.mp4"]];
NSURL *outputURL = [NSURL fileURLWithPath:filePath];
player = [[MPMoviePlayerController alloc]initWithContentURL:outputURL];
float frame = 0.00;
int count = 10;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
docPath = [docPath stringByAppendingPathComponent:#"OutPut"];
BOOL success = [fileManager fileExistsAtPath:docPath];
if (success) {
[fileManager removeItemAtPath:docPath error:nil];
}
[fileManager createDirectoryAtPath:docPath withIntermediateDirectories:YES attributes:nil error:nil];
for (frame = (frameStartTime); frame < (frameStartTime+5); frame+=0.033) {
UIImage * singleFrameImage = [player thumbnailImageAtTime:frame timeOption:MPMovieTimeOptionExact];
[player pause];
NSString *imageName = [NSString stringWithFormat:#"export2%d.png",count];
NSString * file = [[NSBundle mainBundle]pathForResource:imageName ofType:nil];
UIImage *overlayImage = [UIImage imageWithData:[NSData dataWithContentsOfFile:file]];
count = count + 1;
NSString *imagePath = [NSString stringWithFormat:#"%#/%#", docPath, imageName];
if (overlayImage) {
UIImage * outImage = [self mergeImage:singleFrameImage withImage:overlayImage];
NSData *imgData = [[NSData alloc] initWithData:UIImagePNGRepresentation(outImage)];
[fileManager createFileAtPath:imagePath contents:imgData attributes:nil];
[imgData release];
}
else {
NSData *imgData = UIImagePNGRepresentation(singleFrameImage);
[fileManager createFileAtPath:imagePath contents:imgData attributes:nil];
}
[outputFramesArray addObject:imagePath];
}
[player release];
if([fileManager fileExistsAtPath:filePath]) {
[fileManager removeItemAtPath:filePath error:nil];
}
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:#"/Documents/movie1.mp4"]];
NSLog(#"filePath %#", path);
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
[[NSFileManager defaultManager] removeItemAtPath:path error:nil];
}
[self writeImageAsMovie:outputFramesArray toPath:path size:CGSizeMake(480, 320) duration:10];
NSLog(#"hello Your layering is completed");
[outputFramesArray removeAllObjects];
[outputFramesArray release];
The allocation in instrument is maximum in this line (90%):
NSData *imgData = [[NSData alloc] initWithData:UIImagePNGRepresentation(outImage)];
In my whole app, the allocation level rise at only this point of code reaches to 130MB.
Could any of you suggest any solution?
It's most like because you are consuming memory within your loop and the allocated memory in the current stack gets too big before you return to the main loop where things get deallocated.
Read this blog post for more details.
Do this:
...
for (frame = (frameStartTime); frame < (frameStartTime+5); frame+=0.033)
{
#autoreleasepool {
// Do whatever you do in your for loop...
}
}
...
It will create a local pool that gets drained at each iteration.

How to avoid overwriting files on iPhone Documents folder?

I need to write files containing NSArrays into the Documents folder of my iPhone application. Next time I need to create a new file, not overwriting the previous one.
I tried like this, but it only writes doc0 and doc1.
allDocs in an NSArray declared elsewhere.
What's wrong? Thank you!
NSString *myDoc;
NSString *temp;
for (int i = 0; i < [allDocs count]; ++i){
NSFileManager* fileMgr = [NSFileManager defaultManager];
myDoc = [NSString stringWithFormat:#"doc%d.dat", i];
NSString* currentFile = [documentsDirectory stringByAppendingPathComponent:myDoc];
BOOL fileExists = [fileMgr fileExistsAtPath:currentFile];
if (fileExists == NO){
temp = [NSString stringWithFormat:#"doc%d.dat", i];
break;
} else {
temp = [NSString stringWithFormat:#"doc%d.dat",i++];
break;
}
}
NSString *myArray = [documentsDirectory stringByAppendingPathComponent:myDoc];
NSMutableArray *myMutableArray = [[NSMutableArray alloc] initWithContentsOfFile: myArray];
if(myMutableArray == nil)
{
myMutableArray = [[NSMutableArray alloc] initWithCapacity:10];
myMutableArray = anotherArray;
}
[myMutableArray writeToFile:myArray atomically:YES];
You break out of the for loop on the first iteration each time whether the file is found or not. You should be looping with incremented values for i until fileExists is false.
- (BOOL) workFileExists:(NSString *)name {
NSFileManager *fm = [NSFileManager defaultManager];
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
NSString *filename = [name stringByAppendingString:#".swrk"];
return [fm fileExistsAtPath:[path stringByAppendingPathComponent:filename]];
}
- (NSString *)uniqueUntitledName {
NSString *untitled = #"Untitled";
NSString *name = untitled;
int i = 1;
while ([self workFileExists:name]) {
name = [NSString stringWithFormat:#"%#%d", untitled, i];
i++;
}
return name;
}
UIImage *imageForShare = [UIImage imageNamed:#"anyImage.jpg"];
NSString *stringPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0]stringByAppendingPathComponent:#"New Folder"];
// New Folder is your folder name
NSError *error = nil;
//in this method you are checking the path is exist or not for Folder Name
if (![[NSFileManager defaultManager] fileExistsAtPath:stringPath])
[[NSFileManager defaultManager] createDirectoryAtPath:stringPath withIntermediateDirectories:NO attributes:nil error:&error];
//now checking the image name already exist or not
NSString *fileName = [stringPath stringByAppendingFormat:#"/image.jpg"];
if (![[NSFileManager defaultManager] fileExistsAtPath:fileName])
{
NSLog(#"Path is available.");
NSData *data = UIImageJPEGRepresentation(imageForShare, 1.0);
[data writeToFile:fileName atomically:YES];
}
else
{
NSLog(#"Path doesn't exist, same name of image is already exist.");
}
Thank You!!

how to save data in plist in iphone through iphone app [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to write data in plist?
hi i am now in iphone programming. i want ti add data and save it in plist ....-
i am using following code...
(void)viewDidLoad {
[super viewDidLoad];
NSLog(#"i amin did load");
temp =[self readPlist:data];
NSLog(#"dict data is %#",temp);
[self writeToPlist];
temp =[self readPlist:data];
NSLog(#"dict data is %#",temp);
}
//
// NSError *error;
// NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //1
// NSString *documentsDirectory = [paths objectAtIndex:0]; //2
// NSString *path = [documentsDirectory stringByAppendingPathComponent:#"data.plist"]; //3
//
// NSFileManager *fileManager = [NSFileManager defaultManager];
//
// if (![fileManager fileExistsAtPath: path]) //4
// {
// NSString *bundle = [[NSBundle mainBundle] pathForResource:#"data" ofType:#"plist"]; //5
//
// [fileManager copyItemAtPath:bundle toPath: path error:&error]; //6
// }
// NSMutableDictionary *savedStock = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
//
// NSLog(#"dictionary value is %#",savedStock);
//
// value = [[savedStock objectForKey:#"india"] intValue];
// NSLog(#"value in plist is %d",value);
// [savedStock release];
- (NSDictionary *)readPlist:(NSString *)fileName
{ NSLog(#"i am in readlist method");
NSLog(#"file paased is %#",fileName);
//NSData *plistData;
// NSString *error;
// NSPropertyListFormat format;
// NSDictionary *plist;
NSString *filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:#"plist"];
NSMutableDictionary *plistDict=[[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
return plistDict;
}
- (void)writeToPlist
{
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"data" ofType:#"plist"];
NSMutableDictionary* plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
[plistDict setValue:#"karachi" forKey:#"pakistan"];
[plistDict setObject:#"lahore" forKey:#"amerika"];
[plistDict setObject:#"jabalpur" forKey:#"mp"];
[plistDict writeToFile:filePath atomically: YES];
/* This would change the firmware version in the plist to 1.1.1 by initing the NSDictionary with the plist, then changing the value of the string in the key "ProductVersion" to what you specified */
}
When you call writeToFile:atomically you don't need to give the full path, just the file name. It will automatically put it in the documents directory.
Basically, everywhere where you have written the variable filePath just write #"whatever.plist".

load web pages form Array for iphone

i can load web view on button press like this
-(void)buttonEvent:(UIButton*)sender{
NSLog(#"new button clicked!!!");
if (sender.tag == 1) {
NSLog(#"1");
}
if (sender.tag == 2) {
NSLog(#"2");
NSString *path;
NSBundle *thisBundle = [NSBundle mainBundle];
path = [thisBundle pathForResource:#"index2" ofType:#"html"];
NSURL *instructionsURL = [[NSURL alloc] initFileURLWithPath:path];
[webView loadRequest:[NSURLRequest requestWithURL:instructionsURL]];
}
}
but i want to load the path value from my string NSString *filepat=[listItems objectAtIndex:2];
whose value is tab0/index1.html where tab0 is a folder
so how to load from that string plz help
Thanks
// get the app's base directory
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
// get the dir/filename
NSString *filepat=[listItems objectAtIndex:2];
// concatenate for full path
NSString *filePath = [basePath stringByAppendingString:filepat];
NSURL *instructionsURL = [[NSURL alloc] initFileURLWithPath:filePath];
[webView loadRequest:[NSURLRequest requestWithURL:instructionsURL]];
You could also use a cache like I use - SimpleDiskCache.m - which will fetch URLs from the internet, and cache and fetch them from disk.
// SimpleDiskCache.h
#interface SimpleDiskCache : NSObject { }
+ (void) cacheURL:(NSURL*) url forData:(NSData*)data;
+ (NSData*) getDataForURL:(NSURL*) url;
#end
// SimpleDiskCache.m
#import "SimpleDiskCache.h"
#import "util.h"
#implementation SimpleDiskCache
+ (NSCharacterSet*) getNonAlphaNumericCharacterSet {
static NSCharacterSet* cs;
if (!cs) {
cs = [[NSCharacterSet alphanumericCharacterSet] invertedSet];
cs = [cs retain];
}
return cs;
}
+ (void) cacheURL:(NSURL*) url forData:(NSData*)data {
NSString* filename = [[[url absoluteString] componentsSeparatedByCharactersInSet:
[NSCharacterSet punctuationCharacterSet]] componentsJoinedByString:#""];
NSString * storePath = [NSTemporaryDirectory() stringByAppendingPathComponent:filename];
[data writeToFile:storePath atomically:NO];
}
+ (NSData*) getDataForURL:(NSURL*) url {
NSString* filename = [[[url absoluteString] componentsSeparatedByCharactersInSet:
[NSCharacterSet punctuationCharacterSet]] componentsJoinedByString:#""];
NSString * storePath = [NSTemporaryDirectory() stringByAppendingPathComponent:filename];
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:storePath]) {
return [NSData dataWithContentsOfFile:storePath];
}
return nil;
}
#end