NSURLIsExcludedFromBackupKey crashes before iOS 5.

2019-05-06 02:24发布

问题:

Like many of iOS developers I have encountered the issue with application crashing on system before 5.1 when using NSURLIsExcludedFromBackupKey.

It was well described how to evaluate existence of this key on this thread:

Use NSURLIsExcludedFromBackupKey without crashing on iOS 5.0

One of samvermette's comments says that there is a bug in iOS simulator.

Nevertheless I have encountered the same issue with a Release build, even in 2 separate applications. After some investigation I have discovered that application crashed even before main() method beeing called. Which hinted me that this is connected with

NSString * const NSURLIsExcludedFromBackupKey;

evaluation at application launch.

I am not an expert in this field, but I have found out that, if any reference to const value occurs in code (even if it is not actually accessed in runtime) this const is evaluated at very application launch. And this simply causes that crash that many of us experience.

I would like to ask you for some help. Maybe you know a way how to 'weakly' refer to a const value, or maybe there is specific compiler flag. (Using Apple LLVM 3.1).

Thanks in advance.

Please do not comments to put this const's value directly which is @"NSURLIsExcludedFromBackupKey" in this case. I am aware of this workaround, reson for this story is to find a general solution.

回答1:

You can use this code on systems < 5.0.1

#include <sys/xattr.h>

- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL
{
    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;
}

Read more here.

edit

If you're only asking how to check for availability of an external constant you can compare its address to NULL or nil. This is the recommended way of doing it.

if (&NSURLIsExcludedFromBackupKey) {
    // The const is available
}


回答2:

I found a solution, thanks to https://stackoverflow.com/a/9620714/127493 !

NSString * const NSURLIsExcludedFromBackupKey;

is NOT weak-linked, even if Base SDK is set to iOS 5.1, unlike the SDK Compatibility Guide says.

The trick is to use the result of this const.
If I do

NSLog(@"%@", NSURLIsExcludedFromBackupKey);

the result is @"NSURLIsExcludedFromBackupKey"

So my resulting code is

#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)

NSError * error = nil;
BOOL success;
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"5.1")) {
    success = [storeURL setResourceValue:[NSNumber numberWithBool:YES] forKey:@"NSURLIsExcludedFromBackupKey" error:&error];
}