Search code examples
iphoneobjective-ciosxcodeicloud

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.


Solution

  • 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.