UIManagedDocument saveToURL always returns false - iphone

I'm trying to create a UIManagedDocument that doesn't yet exists. Here is my code:
url = [NSURL URLWithString:#"file://ProjectSSDB"];
document = [[UIManagedDocument alloc] initWithFileURL:url];
if ([[NSFileManager defaultManager] fileExistsAtPath:[url path]]) {
[document openWithCompletionHandler: ^(BOOL success) {
if (success) [ProjectSSViewController documentIsReady];
if (!success) NSLog(#"Couldn't open document at %#", url);
}];
} else {
[document saveToURL:url forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
NSLog(#"Returned %d", success);
if (success) [ProjectSSViewController documentIsReady];
if (!success) NSLog(#"Couldn't create document at %#", url);
}];
}
My problem is that the file doesn't exist yet, and the saveToURL operation always seems to be returning false. Is there anyway I can debug this further as to why this is happening?
EDIT:
Ok, so I can't write to that URL. I've now tried doing this:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSURL *url = [NSURL URLWithString:documentsDirectory];
NSLog(#"The URL is %#", [url absoluteString]);
When it runs, the log seems to return that the URL is null. Is there something else that I'm doing wrong?

You can't write at this path "file://ProjectSSDB", you don't have the permission, you need to get the root of your application in this way:
NSString* rootPath = NSHomeDirectory();
and save the the data in one of the sub folder as specified by Apple file system guide line
NSString* fullPath = [rootPath stringByAppendingPathComponent:#"subFoldeder/file.extension"];

I've been successfully using following code snippet for generating UIManagedDocument's URL for quite a while:
NSURL *url = [NSFileManager.defaultManager URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask].firstObject;
url = [url URLByAppendingPathComponent:#"ARBITRARY_NAME"];
self.document = [UIManagedDocument.alloc initWithFileURL:url];
P.s.: it's iOS 5+ solution.
Let me know if that works for you ;)

Related

Warning in iCloud integration

I am trying to integrating iCloud.
Everything works fine but when I try to read a file from iCloud I get a warning Like:
Foundation called mkdir("/var/mobile/Library/Mobile Documents/.ubd/peer-E8A60A8F-FB9D-8721-F47C-hdffgdfg-v23/ftr/(A Document Being Saved By XYZ)"), it didn't return 0, and errno was set to 1.
My Code to fetch Data:
for (NSMetadataItem *item in results)
{
NSString *filename = [item valueForAttribute:NSMetadataItemDisplayNameKey];
NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];
MyDocument *doc = [[MyDocument alloc] initWithFileURL:url];
[doc openWithCompletionHandler:^(BOOL success) {
if (success) {
NSData *file = [NSData dataWithContentsOfURL:url];
NSString *docDir = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:#"Import/iCloud"];
if (![[NSFileManager defaultManager] fileExistsAtPath:docDir])
[[NSFileManager defaultManager] createDirectoryAtPath:docDir withIntermediateDirectories:YES attributes:nil error:nil];
NSString *pdfFile = [docDir stringByAppendingPathComponent:filename];
if(![[NSFileManager defaultManager] fileExistsAtPath:pdfFile])
[[NSFileManager defaultManager] createFileAtPath:pdfFile contents:file attributes:nil];
NSLog(#"Successfully loaded data from cloud file name %#", filename);
}
else
{
NSLog(#"Failed to load data");
}
}];
}
}
It looks like you have a partially written file in iCloud (based on the A Document Being Saved By XYZ in the error), and your meta data query has returned that to you since it also matches the filename. I ran into a similar situation a few weeks ago and solved it by using the exact path to the file, as in:
NSString *filepath = [containerURL.path stringByAppendingPathComponent:#"MyFileName"];
NSPredicate *pred = [NSPredicate predicateWithFormat: #"%K == %#", NSMetadataItemPathKey, filepath];
[query setPredicate:pred];

How to use addSkipBackupAttributeToItemAtURL API?

my application rejected due to this issue :
http://i.imgur.com/yajQh.png
My application is a dictionary which uses SQL DBs , with bookmarking and etc ...
so I copied this code from Apple docs in appDelegate.m :
- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL
{
assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]);
NSError *error = nil;
BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES]
forKey: NSURLIsExcludedFromBackupKey error: &error];
if(!success){
NSLog(#"Error excluding %# from backup %#", [URL lastPathComponent], error);
}
return success;
}
but used like this :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self addSkipBackupAttributeToItemAtURL:[NSURL URLWithString:#"<myApplication>/Library/Caches"]];
}
but crashes with this reason :
Assertion failed: ([[NSFileManager defaultManager] fileExistsAtPath:
[URL path]]), function -[AppDelegate
addSkipBackupAttributeToItemAtURL:], file /iData/Development 2011/My
iPhone Project/APPNAME/APPNAME/AppDelegate.m, line 27.
According to that picture is this my only problem for rejection ? because this is my first time I work with data base .
Thanks .
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
EDITED :
- (NSString *) getDBPath
{
NSInteger kValue = [[[NSUserDefaults standardUserDefaults] stringForKey:#"Bv"] intValue];
NSString *documentsDir = [[NSString alloc] init];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
documentsDir = [paths objectAtIndex:0];
switch (kValue) {
case 0:
documentsDir = [NSString stringWithFormat:#"%#/eng-per.sqlite", documentsDir];
break;
case 1:
documentsDir = [NSString stringWithFormat:#"%#/eng-per.sqlite", documentsDir];
break;
case 2:
documentsDir = [NSString stringWithFormat:#"%#/per-eng.sqlite", documentsDir];
break;
}
return documentsDir
}
and then changed to this in app delegate.m :
[self addSkipBackupAttributeToItemAtURL:[NSURL fileURLWithPath:dbClass.getDBPath]];
now app lunches fine without crash
Your app is "crashing" because you're hitting that assert on line:
assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]);
And I suspect your problem is actually in how you are setting up the URL:
[NSURL URLWithString:#"<myApplication>/Library/Caches"];
How are you getting the path to "<myApplication>"?
You need to get your application's true Cache's folder, which you can do via:
[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask]; (for the location passed back via file URL's)
or
NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); (for the path in the form of a NSString)
So ultimately, what you need to do is not assert if the key has already been set in defaults and you need to properly set the file URL for the file you're saving.
Create your URL (a file URL, to be precise) using something like:
NSArray * arrayOfURLs = [[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask];
// make certain there's at least one file url returned by the above call
if([arrayOfURLs count] > 0)
{
// and this would just be the URL to the cache directory...
NSURL * cacheDirectoryPath = [arrayOfURLs objectAtIndex: 0];
// ... to create a file url to your actual dictionary, you'd need to add a
// filename or path component.
// Assuming you save this as a property within your object
self.cacheFileURL = [cacheDirectoryPath URLByAppendingPathComponent: #"myDatabase.db"];
}

How to read & write to an NSArray to plist?

I'm having several issues based around reading and writing an NSArray to and from a plist.
I have created a plist file in the 'Supporting Files' folder which I want to use to initialise the app data with upon the first load.
Here is what my plist looks like:
I then use this code to try load the plist into the app:
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
filePath = [documentsDirectory stringByAppendingPathComponent:kDataFile];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:filePath])
{
NSString *bundle = [[NSBundle mainBundle] pathForResource:#"Data" ofType:#"plist"];
[fileManager copyItemAtPath:bundle toPath:filePath error:&error];
}
I then try to load the data from the plist file like so, however nothing seems to be displayed.
NSMutableDictionary *savedData = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
NSMutableArray *myNSArray = [[savedData objectForKey:#"KEY_Level_1"] mutableCopy];
savedData = nil;
Sorry if this is a simple task, however I've been looking at lots of tutorials and trying to work out how to do this with no luck. I'm getting really frustrated now - I would have thought it should be a simple thing to do.
NOTE: My NSArray will contain a whole bunch of NSDictionaries.
You need to check the return value of copyItemAtPath:toPath:error: and at least log the error if the method returns false:
if (![fileManager copyItemAtPath:bundle toPath:filePath error:&error]) {
NSLog(#"error: copyItemAtPath:%# toPath:%# error:%#", bundle, filePath, error);
return;
}
-[NSDictionary initWithContentsOfFile:] has no way to report errors, so if it's failing, you cannot easily figure out why. Try reading the file into an NSData and using -[NSPropertyListSerialization propertyListWithData:options:format:error:] to parse it:
NSData *data = [NSData dataWithContentsOfFile:filePath options:0 error:&error];
if (!data) {
NSLog(#"error: could not read %#: %#", filePath, error);
return;
}
NSMutableDictionary *savedData = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListMutableContainers format:NULL error:&error];
if (!savedData) {
NSLog(#"error: could not parse %#: %#", filePath, error);
return;
}
NSMutableArray *myNSArray = [savedData objectForKey:#"KEY_Level_1"];
savedData = nil;
if (!myNSArray) {
NSLog(#"error: %#: object for KEY_Level_1 missing", filePath);
return;
}
If you do this, you'll be able to more easily see why your data is not being loaded.
UPDATE
On further inspection, it looks like the top-level dictionary in your plist contains the key "Root". The value for "Root" is a dictionary containing the key "KEY_Level_1". So you need to do this:
NSMutableArray *myNSArray = [[savedData objectForKey:#"Root"] objectForKey:#"KEY_Level_1"];

What's wrong with my copy here?

I'm trying to copy a file from my application bundle to my app's documents directory. I'm getting an error, "Cocoa Error 262". What am I doing wrong? Here's my code:
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"CoreData.sqlite"];
NSURL *initialURL = [NSURL URLWithString:[[NSBundle mainBundle] pathForResource:#"CoreData" ofType:#"sqlite"]];
NSError *error = nil;
if (![[NSFileManager defaultManager] fileExistsAtPath:[initialURL absoluteString]]) {
NSLog(#"Original does not exist. \nPath: %#", [initialURL absoluteString]);
}
if (![[NSFileManager defaultManager] fileExistsAtPath:[storeURL absoluteString]]) {
NSLog(#"Destination file does not exist. \nPath: %#", [storeURL absoluteString]);
[[NSFileManager defaultManager] copyItemAtURL:initialURL toURL:storeURL error:&error];
NSLog(#"Error: %#", [error description]);
}
The problem is you're initializing a URL with a plain old file path.
NSURL *initialURL =
[NSURL URLWithString:[[NSBundle mainBundle] pathForResource:#"CoreData"
ofType:#"sqlite"]];
Use [NSURL fileURLWithPath:] instead.
The error you are getting is
NSFileReadUnsupportedSchemeError
Read error because the specified URL scheme is unsupported
which I believe would mean one of your paths is not forming correctly. perhaps write these paths to the log and see if they are coming out as you expect them to.
I've solved the problem, although to be honest, I'm not sure what it was. I have to go over the working code again, but here it is:
NSError *error = nil;
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#", #"CoreData", #"sqlite"]];
//if file does not exist in document directory, gets original from mainbundle and copies it to documents.
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSString *defaultFilePath = [[NSBundle mainBundle] pathForResource:#"CoreData" ofType:#"sqlite"];
[[NSFileManager defaultManager] copyItemAtPath:defaultFilePath toPath:filePath error:&error];
if (error != nil) {
NSLog(#"Error: %#", error);
}
}
Edit:
I suspect that the path to the application directory was incorrect, given that the body of the generated applicationDocumentsDirectory looks different than the method used for the value of the documentsDorectory variable shown above.
Error 262 is defined in FoundationErrors.h to be NSFileReadUnsupportedSchemeError.
I'd suggest that you use NSLog() to write out the literal values of the two URLs that you're using and make sure that they are file:// URLs and that they look complete.

NSFileManager createDirectoryAtPath EXC_BAD_ACCESS

I have been working at this one for quite some time now but can't seem to resolve it. I have a core data application that also supports document sharing, therefore I'm trying to create a directory in the library folder for the sqlite db.
- (NSURL *)applicationPrivateDocumentsDirectory {
NSString *libraryDirectory = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
NSString *privateDocs = [libraryDirectory stringByAppendingPathComponent:#"PrivateDocuments"];
NSFileManager *fileMgr = [[NSFileManager alloc] init];
if (![fileMgr fileExistsAtPath:privateDocs]) {
NSLog(#"Does not exist");
NSError *error;
[fileMgr createDirectoryAtPath:privateDocs withIntermediateDirectories:YES attributes:nil error:&error];
NSLog(#"%#", [error description]);
}
NSURL *retURL = [NSURL fileURLWithPath:privateDocs];
return retURL;
}
The debug console outputs "Does not exist" followed by "EXC_BAD_ACCESS"
Any help is greatly appreciated.
Try to add this:
NSError *error = nil;