Issue saving to NSApplicationSupportDirectory - ios

I'm having a strange issue saving to NSApplicationSupportDirectory on my iPad app.
I've been using this data structure for a long time with no issues, it only appears during the first two loads of the program.
The first time the app opens, I open up a file from the mainBundle and re-save it as a default settings file, which is then used to store any changes to settings in the application.
The second time I open the app, the file doesn't seem to exist yet, so it creates it again! The third time and after, all is well. I can't figure out why it isn't saving it the first time.
Sorry if this is messy - it's a part of hundreds of pages of code!
Here's my initialization:
///inside the init of the object
NSFileManager* fileManager = [[NSFileManager alloc] init];
NSError* err = nil;
NSURL* dir = [fileManager URLForDirectory:NSApplicationSupportDirectory
inDomain:NSUserDomainMask
appropriateForURL:nil
create:YES
error:&err];
if (err) {
NSLog(#"error finding app support directory %#", err);
}
currentSettingsURL = [NSURL URLWithString:kCurrentSettingsFilename relativeToURL:dir];
if(![fileManager fileExistsAtPath:[currentSettingsURL path]])[self createDefaultFile];
NSArray* files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[dir path] error:&err];
NSLog(#"files %#", files);
where the file is created if it doesn't exist.
-(void)createDefaultFile{
NSURL* readURL = [[NSBundle mainBundle] URLForResource:#"smooth" withExtension:nil];
NSMutableData* tempData = [NSMutableData dataWithContentsOfURL:readURL];
NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:tempData];
///re archive
[self setCurrentPresets:[unarchiver decodeObjectForKey:#"presetData"]];
}
-(void)setCurrentPresets:(NSMutableArray*)presets{
currentPresets = presets;
[self saveCurrentSettings];
}
here is where the file is saved
-(void)saveCurrentSettings{
data = [[NSMutableData alloc] init];
NSKeyedArchiver* archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:currentPresets forKey:kCurrentSettingsFilename];
[archiver finishEncoding];
if(![data writeToURL:currentSettingsURL atomically:YES])NSLog(#"error saving file");
}

I simply needed to tell it my NSApplicationSupportDirectory was a folder..
NSURL* dir = [fileManager URLForDirectory:NSApplicationSupportDirectory
inDomain:NSUserDomainMask
appropriateForURL:nil
create:YES
error:&err];
if (err) {
NSLog(#"error finding app support directory %#", err);
}
NSURL* folder = [[NSURL alloc] initFileURLWithPath:[dir path] isDirectory:YES];
currentSettingsURL = [NSURL URLWithString:kCurrentSettingsFilename relativeToURL:folder];

Related

iCloud data uploading is not working when .sqlite file is uploaded in ios

I am trying to upload sqlite file on iCloud. I am using NSFileCoortinator for coping the file from one file to another file but schema of sqlite file is only get copied, I am not getting data in sqlite file….Also sometimes the data is appearing in the sqlite file on iCloud. I don’t understand why this is happening. Is this sqlite file issue or I did wrong in code. If anyone has solution please help me out.
-(void)uploadFile
{
//-------code for uploading data to icloud
NSArray *paths =
NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory,
NSUserDomainMask, YES);
NSString *applicationSupportDirectory = [paths firstObject]
NSString *str=[NSString stringWithFormat:#"%#/XMPPMessageArchiving.sqlite",applicationSupportDirectory]; //copy this file
NSString *fileName = [NSString stringWithFormat:#"XMPPMessageArchiving.sqlite"];
NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
NSFileCoordinator *coordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
NSURL *fromURL = [NSURL fileURLWithPath:str];
NSURL *toURL = [[ubiq URLByAppendingPathComponent:#"Documents"]
URLByAppendingPathComponent:fileName];;
[coordinator coordinateReadingItemAtURL:fromURL options:0 writingItemAtURL:toURL options:NSFileCoordinatorWritingForReplacing error:nil byAccessor:^(NSURL *newReadingURL, NSURL *newWritingURL)
{
NSError *error=nil;
NSData *data = [[NSFileManager defaultManager] contentsAtPath:fromURL.path];
//if file is already present on icloud replace that file with new file
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:newWritingURL.path];
if (fileExists)
{
[[NSFileManager defaultManager] removeItemAtPath:toURL.path error:NULL];
}
BOOL isCopied= [[NSFileManager defaultManager] copyItemAtPath:newReadingURL.path toPath:newWritingURL.path error:nil];
NSLog(#"file copied= %d",isCopied);
}];
}
The value for file copied is always 1 but still data is not available.

Reading NSData in parts

I am implementing extensions in ios8. In this import function returns a url. I need to read data from it and save in my app.
Here is the code.
NSFileCoordinator *fileCoordinator = [[NSFileCoordinator alloc] init];
NSError *error;
__block NSData *data;
[fileCoordinator coordinateReadingItemAtURL:url options:0 error:&error byAccessor:^(NSURL *newURL) {
data = [NSData dataWithContentsOfURL:newURL];
//saving in document directory
}];
My question is, if file is too big, dataWithContentsOfURL results in crash due to out of memory.
I wanted a method to read data from that url in parts, save in my documents, then read next part and keep appending. Thus it won't have memory issue.
Can someone help.
Found two solutions.
1- Used NSURLConnection. Using NSFileHandle wrote data in file.
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data1{
// [data appendData:data1];
[self.currentFileHandle seekToEndOfFile];
[self.currentFileHandle writeData:data1];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
[self.currentFileHandle closeFile];
self.currentFileHandle = nil;
}
Instead of converting it in data and then saving. Used following to copy file.
NSFileCoordinator* fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
[fileCoordinator coordinateReadingItemAtURL:url options:NSFileCoordinatorReadingWithoutChanges error:nil byAccessor:^(NSURL *newURL) {
NSFileManager * fileManager = [[NSFileManager alloc] init];
NSError * error;
NSArray *paths = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
NSURL *urlDestination = [paths lastObject];
urlDestination = [urlDestination URLByAppendingPathComponent:[url lastPathComponent]];
if([[NSFileManager defaultManager] fileExistsAtPath:[urlDestination relativePath]]){
[[NSFileManager defaultManager] removeItemAtPath:[urlDestination relativePath] error:nil];
}
BOOL success = [fileManager copyItemAtURL:url toURL:urlDestination error:&error];
if (success) {
}
}];
I used 2nd solution. Sorry for wrong alignment. I tried a lot, but not
coming properly.

Get data contents of iCloud URL without UIDocument

Is it possible to get the contents of an iCloud URL without having to go through UIDocument?
You can use the following code for downloding the contents of icloud url without creating the object of NSDocument. This will be worked for me...
-(void)loadData:(NSMetadataQuery *)query
{
if ([query resultCount] == 1)
{
NSMetadataItem *item = [query resultAtIndex:0];
NSURL *fromURL = [item valueForAttribute:NSMetadataItemURLKey];
NSURL *toURL=[NSURL fileURLWithPath:#"PATH_OF_FILE_TO_STORE_DATA"];
NSFileCoordinator *coordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
[coordinator coordinateReadingItemAtURL:fromURL options:0 writingItemAtURL:toURL options:NSFileCoordinatorWritingForReplacing error:nil byAccessor:^(NSURL *newReadingURL, NSURL *newWritingURL)
{
[[NSFileManager defaultManager] removeItemAtPath:newWritingURL.path error:NULL];
[[NSFileManager defaultManager] copyItemAtPath:newReadingURL.path toPath:newWritingURL.path error:nil];
}];
}
}

iCloud Folder Creating and Saving in iOS

I need to create Folder in Cloud and save my .txt Text File into that Folder.
So i created folder with following codes in AppDelegate
NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
NSError *error = nil;
if(ubiq)
{
NSFileManager *fm = [NSFileManager defaultManager];
NSURL *rootURL = [fm URLForUbiquityContainerIdentifier:nil];
NSURL *newFolder = [NSURL URLWithString:#"Notes" relativeToURL:rootURL];
[fm createDirectoryAtURL:newFolder withIntermediateDirectories:YES attributes:nil error:&error];
if(error)
{
NSLog(#"Error");
}
else
{
NSLog(#"NO Error");
}
}
After i test it , It show No Error.
So i assumed that it created Notes Folder in iCloud.
However when i save my text document into that folder with following codes , it showing error and not save.
NSString *file = [NSString stringWithFormat:#"%#.txt",fileName];
NSURL *ubiq = [[NSFileManager defaultManager]
URLForUbiquityContainerIdentifier:nil];
NSURL *ubiquitousPackage =
[[[ubiq URLByAppendingPathComponent:#"Documents"] URLByAppendingPathComponent:#"Notes"]
URLByAppendingPathComponent:file];
Note *doc = [[Note alloc] initWithFileURL:ubiquitousPackage];
[doc saveToURL:[doc fileURL] forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
if (!success)
{
NSLog(#"Error");
}
else
{
doc.noteContent = self.txtView.text;
[doc updateChangeCount:UIDocumentChangeDone];
}
}];
And the error message is
Foundation called mkdir("/private/var/mobile/Library/Mobile Documents/35QNLTQU29~com~myapp~iCloudTest/Documents/Notes/(A Document Being Saved By iCloudTest)"), it didn't return 0, and errno was set to 2.
How can i solve it?

NSFileManager not saving Data

I am trying to save data into a directory created by NSFileManager but when I try and retrieve the data and NSLog it I get null. Also, when you create a directory does that mean you create a folder at a specified url path? Heres the code I am using
NSError *error = nil;
NSFileManager *manager = [[NSFileManager alloc] init];
NSArray *urlsArray = [manager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
NSLog(#"%#", urlsArray);
// This will create a new url and append a photo title to the end
NSURL *url = [[urlsArray lastObject] URLByAppendingPathComponent:[NSString stringWithFormat:#"%#", [self.recentPhoto objectForKey:FLICKR_PHOTO_TITLE]]];
NSLog(#"%#", url);
NSString *urlString = [NSString stringWithFormat:#"%#", [url absoluteString]];
NSLog(#"%#", urlString);
//create the directory
if(![manager fileExistsAtPath:urlString isDirectory:YES]){
BOOL success = [manager createDirectoryAtURL:url withIntermediateDirectories:YES attributes:nil error:&error];
if (!success) {
NSLog(#"Error creating data path: %#", [error localizedDescription]);
}
}
//get url for a photo image and then store it.
NSURL *imageURL = [FlickrFetcher urlForPhoto:self.recentPhoto format:FlickrPhotoFormatLarge];
NSData *imageData = [[NSData alloc] initWithContentsOfURL:imageURL];
[imageData writeToURL:url atomically:YES];
//get data to check if its stored
NSData *checkImageData = [[NSData alloc] initWithContentsOfURL:url];
//This returns null
NSLog(#"%#", checkImageData);
//this returns 0
NSLog(#"%d", [manager isReadableFileAtPath:urlString]);
There are several issues with your code.
This:
NSURL *url = [[urlsArray lastObject] URLByAppendingPathComponent:[NSString stringWithFormat:#"%#", [self.recentPhoto objectForKey:FLICKR_PHOTO_TITLE]]];
should be:
NSURL *url = [[urlsArray lastObject] URLByAppendingPathComponent:[self.recentPhoto objectForKey:FLICKR_PHOTO_TITLE]];
This:
NSString *urlString = [NSString stringWithFormat:#"%#", [url absoluteString]];
should be:
NSString *urlString = [url path];
This:
BOOL success = [manager createDirectoryAtURL:url withIntermediateDirectories:YES attributes:nil error:&error];
should be:
BOOL success = [manager createDirectoryAtURL:[url URLByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:&error];
This:
[imageData writeToURL:url atomically:YES];
should be:
NSError *error = nil;
BOOL res = [imageData writeToURL:url options:NSDataWritingAtomic error:&error];
if (!res) {
NSLog(#"Unable to write to %#: %#", url, error);
}
The primary issue was the use of absoluteString instead of path to convert the URL to a file path. Secondary was passing the filename instead of the path when creating the directory. The needless use of stringWithFormat: didn't cause any issues but please break that habit now. Only use stringWithFormat: when you actually need to format a string. It is NOT needed to assign a string to a string variable.
You didn't specify a file name for your image inside the directory, this can be solved by adding this line right after the directory is created :
// Right after the directory is created (I suppose the format is png) :
url = [url URLByAppendingPathComponent:#"image.png"];
// Now you can continue with the rest of your code :
//get url for a photo image and then store it.
NSURL *imageURL = [FlickrFetcher urlForPhoto:self.recentPhoto format:FlickrPhotoFormatLarge];
NSData *imageData = [[NSData alloc] initWithContentsOfURL:imageURL];
[imageData writeToURL:url atomically:YES];
//get data to check if its stored
NSData *checkImageData = [[NSData alloc] initWithContentsOfURL:url];
//This returns null
NSLog(#"%#", checkImageData);
//this returns 0
NSLog(#"%d", [manager isReadableFileAtPath:urlString]);
I have never created an instance of a file manager. I have always simply used the default.
See if this helps:
NSFileManager *manager = [NSFileManager defaultManager];

Resources