Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

App crashes after Xcode upgrade to 4.5. Assigning retained object to unsafe_unretained variable

In my class I have a dispatch_queue_t property declared like this:

@property (nonatomic, assign) dispatch_queue_t queue;

Then in my init method I do:

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

    return self;
}

In Xcode 4.4.1 it worked and did not cause any problems (the app tested + in the appstore). Now after I upgraded to Xcode 4.5 the app crashes with EXC_BAD_ACCESS and Xcode gives me a warning on that line saying:

Assigning retained object to unsafe_unretained variable; object will be released after assignment

Apple updated the compiler in Xcode 4.5 from LLVM 4.0 to LLVM 4.1 but I have no clue why my code is crashing right now.

I stepped through the code and the crash happens just after that line. Do you have any ideas what can be wrong and how can I fix it?

SOLUTION:

I managed to get it working with both SDKs. I just added:

#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

Hope someone finds it useful

like image 554
Rafa de King Avatar asked Sep 20 '12 11:09

Rafa de King


1 Answers

First, if your target platform is 5+, then I strongly recommend building with the iOS 5 SDK. Building with a later SDK and setting the "target" can work, but has lots of problems (not the least of which is that you get no compiler help to find places that you've used unsupported methods). So answer 1: You need iOS 5, build against iOS 5 and this shouldn't matter.

In iOS 6, dispatch_queue_t is an ObjC object. This is a great improvement. It means you can just create strong properties for it and ARC will take care of the rest. If you target iOS 6, this should just work.

If you need to build the same code for iOS 5 and iOS 6, then you need to know which is which so that you can put in the memory management when you need it and leave it out when you don't. The correct test to use is #if OS_OBJECT_USE_OBJC. Remember, this is a compile-time check. It's only applicable for dealing with code you want to write against different SDKs. For a given SDK, the behavior will aways be one way or the other.

Regarding the "unsafe_unretained" versus "assign" confusion: They are the same thing in this case. "assign" only applies to non-objects. "unsafe_unretained" is what "assign" is converted to when applied to objects. And in iOS6, dispatch_queue_t is an object.

One more workaround, particularly if you really do want to keep the old memory management code while building with the iOS 6 SDK. You can pass -DOS_OBJECT_USE_OBJC=0 to the compiler. This will opt-out of the new model. But I would recommend this as a last resort. For details, see os/object.h in the SDK. (Cmd-Shift-O, object.h)

like image 122
Rob Napier Avatar answered Nov 14 '22 22:11

Rob Napier