6

在我的课堂上,我有一个dispatch_queue_t这样声明的属性:

@property (nonatomic, assign) dispatch_queue_t queue;

然后在我的初始化方法中我这样做:

- (id)initWithServerUrls: (NSString*)serverUrls
{
    if (self = [super init])
    {
        _queue = dispatch_queue_create("com.xxx.my_send_queue", DISPATCH_QUEUE_SERIAL);
    }

    return self;
}

在 Xcode 4.4.1 中它可以工作并且没有引起任何问题(应用程序在应用商店中测试过)。现在,在我升级到 Xcode 4.5 后,应用程序崩溃并出现 EXC_BAD_ACCESS并且 Xcode 在该行给我一个警告说:

将保留对象分配给 unsafe_unretained 变量;分配后对象将被释放

Apple 将 Xcode 4.5 中的编译器从 LLVM 4.0 更新到 LLVM 4.1,但我不知道为什么我的代码现在崩溃了。

我单步执行了代码,崩溃发生在该行之后。你有什么想法可能是错的,我该如何解决?

解决方案:

我设法让它与两个 SDK 一起工作。我刚刚补充说:

#if OS_OBJECT_USE_OBJC
@property (nonatomic, strong) dispatch_queue_t queue; // this is for Xcode 4.5 with LLVM 4.1 and iOS 6 SDK
#else
@property (nonatomic, assign) dispatch_queue_t queue; // this is for older Xcodes with older SDKs
#endif

希望有人觉得它有用

4

1 回答 1

13

首先,如果您的目标平台是 5+,那么我强烈建议使用 iOS 5 SDK 构建。使用更高版本的 SDK 构建并设置“目标”可以工作,但有很多问题(其中最重要的是您没有获得编译器帮助来查找您使用了不受支持的方法的地方)。所以回答 1:您需要 iOS 5,针对 iOS 5 构建,这无关紧要。

在 iOS 6 中,dispatch_queue_t是一个 ObjC 对象。这是一个很大的改进。这意味着您可以为其创建strong属性,而 ARC 将负责其余的工作。如果您以 iOS 6 为目标,这应该可以正常工作。

如果您需要为 iOS 5 和 iOS 6 构建相同的代码,那么您需要知道哪个是哪个,以便您可以在需要时放入内存管理并在不需要时将其保留。使用的正确测试是#if OS_OBJECT_USE_OBJC. 请记住,这是一个编译时检查。它仅适用于处理您要针对不同 SDK 编写的代码。对于给定的 SDK,行为将是一种方式或另一种方式。

关于“unsafe_unretained”与“assign”的混淆:在这种情况下它们是同一回事。“分配”仅适用于非对象。“unsafe_unretained”是“assign”应用于对象时转换为的内容。而在iOS6中,dispatch_queue_t是一个对象。

另一种解决方法,特别是如果您确实希望在使用 iOS 6 SDK 构建时保留旧的内存管理代码。您可以传递-DOS_OBJECT_USE_OBJC=0给编译器。这将选择退出新模型。但我建议将此作为最后的手段。详见os/object.hSDK。(Cmd-Shift-O,object.h)

于 2012-09-20T13:47:07.073 回答