在 iOS 5.0 上使用 NSURLIsExcludedFromBackupKey 而不会崩溃

Posted

技术标签:

【中文标题】在 iOS 5.0 上使用 NSURLIsExcludedFromBackupKey 而不会崩溃【英文标题】:Use NSURLIsExcludedFromBackupKey without crashing on iOS 5.0 【发布时间】:2012-03-08 15:56:43 【问题描述】:

可用性检查似乎工作正常,但我似乎无法设置NSURLIsExcludedFromBackupKey 键而不会在启动时出现此崩溃:

dyld:未找到符号:_NSURLIsExcludedFromBackupKey 引用自: /用户/山姆/图书馆/应用程序支持/iPhone 模拟器/5.0/Applications/B0872A19-3230-481C-B5CE-D4BDE264FBDF/Transit.app/Transit 预计在: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk/System/Library/Frameworks/Foundation.framework/Foundation 在 /Users/sam/Library/Application Support/iPhone 模拟器/5.0/Applications/B0872A19-3230-481C-B5CE-D4BDE264FBDF/Transit.app/Transit

这是我的方法:

- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL     
    if (&NSURLIsExcludedFromBackupKey == nil)
        return NO;

    NSError *error;
    [URL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:&error];
    return (error != nil);

如果我注释掉这一行,崩溃就会消失:

[URL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:&error];

我必须弱链接 Foundation 吗?

编辑:不确定它是否有区别,但此方法放在NSFileManager 类别中。

【问题讨论】:

您确定没有调用该行吗?你能在 ios 5 中使用调试器单步调试吗? @kevboh 应用程序在启动时崩溃,但实际上从未调用过该行。尝试设置断点,它永远不会被调用。我得到的堆栈跟踪是cl.ly/ErTK 很奇怪。你的基础 SDK 是 5.1 吗?也许尝试删除应用程序的派生数据并清理? 基础 SDK 为 5.0。删除了派生数据并清理了构建文件夹,仍然没有变化:( 啊,你的Base SDK应该是最新的(5.1)。 【参考方案1】:

这里是 iOS = 5.1 的代码,包括@Cocoanetics 提到的迁移技术。

- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL

    const char* filePath = [[URL path] fileSystemRepresentation];
    const char* attrName = "com.apple.MobileBackup";
    if (&NSURLIsExcludedFromBackupKey == nil) 
        // iOS 5.0.1 and lower
        u_int8_t attrValue = 1;
        int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0);
        return result == 0;
     else 
        // First try and remove the extended attribute if it is present
        int result = getxattr(filePath, attrName, NULL, sizeof(u_int8_t), 0, 0);
        if (result != -1) 
            // The attribute exists, we need to remove it
            int removeResult = removexattr(filePath, attrName, 0);
            if (removeResult == 0) 
                NSLog(@"Removed extended attribute on file %@", URL);
            
        

        // Set the new key
        return [URL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:nil];
    

【讨论】:

这也不适用于用户从 5.0.1 升级到 5.1 时出现的文件。然后这些将具有文件属性,但没有键。您必须检查这种情况并迁移文件。更安全的方法是同时设置并使用实际的 NSString。 我分叉了通过检测和删除属性来添加迁移的要点:gist.github.com/2002382 您不应该使用错误的存在来检测故障;使用 setResourceValue:forKey:error 返回的 BOOL。 Cocoa 约定是错误可能在成功时包含某些内容(您应该忽略)。 @tim,我只是建议了一个您可以批准的编辑。它几乎处理了 Cocoanetics 指出的迁移技术,它包括 Jesse Rusak 对 NSError 问题的修复。我也是提交 ShareKit 2.0 以包含备份属性代码的人。感谢大家的建议,我会在以后的 pull request 中更新那里的代码。 别忘了#import 【参考方案2】:

这似乎是 iPhone 5.0 模拟器的一个错误。我尝试在 5.0 设备上运行代码并且没有崩溃。将此错误报告为rdar://11017158。

编辑:这已在 Xcode 4.5 DP2 中修复(不确定是否在 4.4 中)。

【讨论】:

不错的收获。我会在模拟器中#define 代码,这样你仍然可以在 5.0 中对其进行测试。 恐怕问题不仅出现在模拟器上。构建发布版本时我遇到了同样的崩溃。实际上,在模拟器上一切正常。我认为问题在于应用程序启动时的 const 评估,因为应用程序甚至在主方法调用之前就崩溃了。 我可以确认,当使用发布版本时,它实际上会在 5.0.1 设备上崩溃。【参考方案3】:

添加此行以强制符号为弱导入:

extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import));

【讨论】:

就我而言,这并不能解决 5.0.1 设备上的问题。我还是会崩溃。 @Martin :我将它添加到引用 NSURLIsExcludedFromBackupKey 的代码文件中。 Olivier :我从未测试过 5.0.1,我将不得不进一步调查。【参考方案4】:

根据您的操作,此快速修复可能对您有用。它对我有用。

CoreFoundation 框架添加到您的项目中并将其标记为 OPTIONAL(非必需)。

【讨论】:

【参考方案5】:

问题是这个键只存在于 5.1 及以上版本。对于 5.0.1,您需要设置扩展文件属性。唯一向后兼容的方法是找出该键的 NSString 值并将其设置为低于 5.1。

【讨论】:

我什至没有在寻找向后兼容的解决方案。我只想在 iOS 5.1 上设置属性,而不是在 5.0 上做任何事情(这就是检查的作用)。但即使最后一行从未被调用,应用程序也会因“未找到符号”错误而崩溃。 是的,但问题是NSURLIsExcludedFromBackupKey 不是弱链接!我想如果我们找出 NSURLIsExcludedFromBackupKey 的 NSString 值,它就会起作用。但是怎么找呢?? 哦,我太笨了……NSLog(@"%@", NSURLIsExcludedFromBackupKey); 来找到它的价值。所以它给出了@"NSURLIsExcludedFromBackupKey",并通过将NSURLIsExcludedFromBackupKey 替换为@"NSURLIsExcludedFromBackupKey" 它可以工作! 感谢 Cocoanetics,我在此处发布了该问题的解决方案:***.com/a/11647534/127493 它适用于我,如果适用,请随时通知我。【参考方案6】:

在更新 ShareKit 并重做一个以 iOS 5.1 为目标的项目后,我遇到了同样的问题,我会在编译或与 NSURLIsExcludedFromBackupKey 相关的链接时遇到错误。 ShareKit 人似乎建议您可以通过确保您的项目与 CoreFoundation 框架链接并将其设置为“可选”而不是“必需”来解决问题。但是,这对我不起作用。

最终我通过使用预处理器解决了这个问题:

- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL

    #ifndef NSURLIsExcludedFromBackupKey                   
    // 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
    // First try and remove the extended attribute if it is present
    int result = getxattr(filePath, attrName, NULL, sizeof(u_int8_t), 0, 0);
    if (result != -1) 
        // The attribute exists, we need to remove it
        int removeResult = removexattr(filePath, attrName, 0);
        if (removeResult == 0) 
            NSLog(@"Removed extended attribute on file %@", URL);
        
    
    return [URL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:nil];
    #endif

【讨论】:

NSURLIsExcludedFromBackupKey 不是预处理器宏,#ifdef 将始终为 false。

以上是关于在 iOS 5.0 上使用 NSURLIsExcludedFromBackupKey 而不会崩溃的主要内容,如果未能解决你的问题,请参考以下文章

在开发人员设备上安装以前版本的 iOS(当前为 5.0 -> 想要 4.3.5)

UIToolbar 在 ios 5.0 和 ios 6.0 模拟器上显示不同的颜色

4.2.x 设备上奇怪的 iOS 5.0 SDK GCC 副作用

由 xcode 4.6 与 xcode 5.0 创建时,iOS 应用程序在 iOS 7.0 设备上的行为不同

iOS 5.0 查看生命周期问题

无法让 Stencil Buffer 在 iOS 4+ 中工作(5.0 工作正常)。 [OpenGL ES 2.0]