How to use addSkipBackupAttributeToItemAtURL API? - iphone

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

Related

UIManagedDocument saveToURL always returns false

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

Not been able to writeToFile iphone

I am using following code to download an slqite file and storing it
self.responseData = NSMutableData
I receive responseData = 2048bytes. working well.
However white writing it does create a file myFile.sqlite but it is of Zero bytes.
What is wrong?
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *dbPath = [self getDBPath];
BOOL success = [fileManager fileExistsAtPath:dbPath];
if(!success)
{
if(self.responseData)
{
dbPath = [dbPath stringByAppendingPathComponent:[self.selectedBtn.dbPath lastPathComponent]];
[self.responseData writeToFile:dbPath atomically:YES];
[self performSegueWithIdentifier:#"list" sender:self];
}
}
[self.alertView removeFromSuperview];
}
-(NSString *) getDBPath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSURL *url = [[NSURL alloc] initWithString:[self.selectedBtn.dbPath lastPathComponent]];
return [documentsDir stringByAppendingPathComponent:[url lastPathComponent]];
}
I am getting error
`The operation couldn’t be completed. (Cocoa error 4.)`
dbPath : /Users/umar/Library/Application Support/iPhone Simulator/6.1/Applications/00027635-CE9C-48C3-8000-64CA1E6532F1/Documents/music.sqlite/music.sqlite
You are appending [self.selectedBtn.dbPath lastPathComponent] twice, once in getDBPath, and again ion connctionDidFinishLoading.
Pick one of those instances to remove.
Documents/music.sqlite/music.sqlite
Nah, this is not a valid path... You meant Documents/music.sqlite, didn't you? Also, I don't see why you're raping poor NSURL for an unrelated task.
return [documentsDir stringByAppendingPathComponent:[self.selectedBtn.dbPath lastPathComponent]];
Also, make sure self.selectedBtn.dbPath also is indeed a valid path and not junk (I could imagine it is).

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

iOS Copy SQLite Database and excluding it from iCloud

My application just rejected because I copied sqlite database in NSDocumentDirectory and didn't exclude it from being synced to iCloud. I tried to add code to exclude it from iCloud but it is still occupying same space in iCloud. Here is my code.
- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL {
if (&NSURLIsExcludedFromBackupKey == nil) { // iOS <= 5.0.1
const char* filePath = [[URL path] fileSystemRepresentation];
const char* attrName = "com.apple.MobileBackup";
u_int8_t attrValue = 1;
int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0);
return result == 0;
} else { // iOS >= 5.1
NSError *error = nil;
[URL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:&error];
return error == nil;
}
}
+ (void)copyDatabaseIfNeeded {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error = nil;
NSString *toPath = [self getDBPath];
BOOL success = [fileManager fileExistsAtPath:toPath];
if(!success) {
NSString *fromPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:databaseName];
NSURL *toURL = [NSURL fileURLWithPath:toPath];
NSURL *fromURL = [NSURL fileURLWithPath:fromPath];
[[NSFileManager defaultManager] addSkipBackupAttributeToItemAtURL:toURL];
[[NSFileManager defaultManager] addSkipBackupAttributeToItemAtURL:fromURL];
success = [fileManager copyItemAtURL:fromURL toURL:toURL error:&error];
if (!success)
NSLog(#"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
+ (NSString *)getDBPath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:databaseName];
}
Please help.
You set the skip back attribute to the file before coping it, since the file is not yet copied there the filemanager can't change the properties of that file:
Also you are not calling the addSkipBackupAttributeToItemAtURL: on self but on NSFileManager which does have this method declared.
You can addSkipBackupAttributeToItemAtURL: from a class method if you declared it as an instance methods, change it to + to make it a class method.
Change it to something like:
+ (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL {
if (&NSURLIsExcludedFromBackupKey == nil) { // iOS <= 5.0.1
const char* filePath = [[URL path] fileSystemRepresentation];
const char* attrName = "com.apple.MobileBackup";
u_int8_t attrValue = 1;
int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0);
return result == 0;
} else { // iOS >= 5.1
NSError *error = nil;
[URL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:&error];
return error == nil;
}
}
+ (void)copyDatabaseIfNeeded {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error = nil;
NSString *toPath = [self getDBPath];
BOOL success = [fileManager fileExistsAtPath:toPath];
if(!success) {
NSString *fromPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:databaseName];
NSURL *toURL = [NSURL fileURLWithPath:toPath];
NSURL *fromURL = [NSURL fileURLWithPath:fromPath];
success = [fileManager copyItemAtURL:fromURL toURL:toURL error:&error];
if (success) {
[self addSkipBackupAttributeToItemAtURL:toURL];
} else {
NSLog(#"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
}
Also a my comment stated I removed the [[NSFileManager defaultManager] addSkipBackupAttributeToItemAtURL:fromURL]; since that file will a not be included in an iCloud backup and b files in the bundle are readonly and can't there for be modified.
I was on the phone with an Apple support guy about this.
However, rather than repeating stuff, this answer covers it well: Setting NSDocumentDirectory so it doesn't backup to iCloud
Please refer to Technical Q&A QA1719 which describes that the technique you employ in addSkipBackupAttributeToItemAtURL is advised for iOS 5.0.1 and earlier. For iOS 5.1 and later, you should use the following:
- (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;
}
NSDocumentDirectory has nothing to do with iCloud. the documents directory for an iOS application is NOT automatically backed up to iCloud at all. Its the same as it ever was, just a sandbox directory for your app.
You only store things in iCloud if the following conditions are met:
Your app has entitlements specifying iCloud sandbox container name
Your user is logged into iCloud on their device
You explicitly get the ubiquity container's documents directory and store things there.
So if you dont want to store something in iCloud, dont get the documents directory for the ubiquity container, dont connect to iCloud at all...
Also the iCloud backup is not even an application level setting the user sets it, so I dont know why yo u even have iCloud enabled. Just put your data in the data directory and apple will have no problem with it.

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;