【问题标题】:iOS Copy SQLite Database and excluding it from iCloudiOS 复制 SQLite 数据库并将其从 iCloud 中排除
【发布时间】:2012-10-07 20:48:24
【问题描述】:

我的应用程序刚刚被拒绝,因为我在 NSDocumentDirectory 中复制了 sqlite 数据库并且没有将其排除在同步到 iCloud 之外。我尝试添加代码以将其从 iCloud 中排除,但它仍在 iCloud 中占用相同的空间。这是我的代码。

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

请帮忙。

【问题讨论】:

  • bundle中不需要排除数据库,可以去掉这行[[NSFileManager defaultManager] addSkipBackupAttributeToItemAtURL:fromURL];,因为文件是只读的,所以就不行了。

标签: iphone objective-c ios xcode icloud


【解决方案1】:

请参阅Technical Q&A QA1719,其中描述了您在addSkipBackupAttributeToItemAtURL 中采用的技术适用于iOS 5.0.1 及更早版本。对于 iOS 5.1 及更高版本,您应该使用以下内容:

- (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;
}

【讨论】:

    【解决方案2】:

    您在处理文件之前将其设置为跳过属性,因为该文件尚未复制到那里,文件管理器无法更改该文件的属性:

    另外,您不是在 self 上调用 addSkipBackupAttributeToItemAtURL:,而是在声明了此方法的 NSFileManager 上。

    如果您将类方法声明为实例方法,则可以将其从类方法中addSkipBackupAttributeToItemAtURL:,将其更改为+以使其成为类方法。

    将其更改为:

    + (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]);
            }
        }   
    }
    

    另外,我的评论说我删除了[[NSFileManager defaultManager] addSkipBackupAttributeToItemAtURL:fromURL];,因为该文件不会包含在 iCloud 备份中,并且捆绑包中的 b 文件是只读的,无法修改。

    【讨论】:

      【解决方案3】:

      NSDocumentDirectory 与 iCloud 无关。 iOS 应用程序的文档目录根本不会自动备份到 iCloud。它与以往一样,只是您应用的沙盒目录。

      只有满足以下条件时,您才能将内容存储在 iCloud 中:

      您的应用具有指定 iCloud 沙盒容器名称的权利

      您的用户已在其设备上登录 iCloud

      您显式获取 ubiquity 容器的文档目录并将内容存储在那里。

      因此,如果您不想在 iCloud 中存储某些内容,请不要获取 ubiquity 容器的文档目录,根本不要连接到 iCloud...

      另外,iCloud 备份甚至不是用户设置的应用程序级别设置,所以我不知道为什么你甚至启用了 iCloud。把你的数据放到data目录下,apple就没有问题了。

      【讨论】:

        【解决方案4】:

        我正在与 Apple 支持人员通电话。

        但是,这个答案并没有重复,而是很好地涵盖了它:Setting NSDocumentDirectory so it doesn't backup to iCloud

        【讨论】:

        • 这不是正确的答案,即使我将数据库文件复制到 NSApplicationSupportDirectory,我的应用程序也再次被拒绝。
        • @MarriamSara 你应该看答案而不是问题。另见他的最新编辑。 “iOS 5.1 引入了一个新的 API 来标记不应该备份的文件或目录。对于 NSURL 对象,添加 NSURLIsExcludedFromBackupKey 属性以防止相应的文件被备份。”
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多