I'm trying to cast from an id __autoreleasing * to a CFTypeRef * (void **).
I've tried:
id __autoreleasing *arg = [OCMArg setTo:mockData];
CFTypeRef expectedResult = (__bridge CFTypeRef) *arg;
[[[self.mockSecItemService expect] andReturnValue:OCMOCK_VALUE(mockCopyStatus)] copyItemMatching:queryCheck
result:&expectedResult];
But the code crashes when the autorelease pool is drained.
How does one convert to void** in an ARC environment?
I do not know the APIs you are using, so I'm not 100% sure of what's going on. I googled and they seem to be part of OCMock. I downloaded it and (without installing it as I'm not interested) I rapidly browsed the source.
I see something very fishy in that code. Here's how they implement the first method you call:
#implementation OCMArg
....
+ (id *)setTo:(id)value
{
return (id *)[[[OCMPassByRefSetter alloc] initWithValue:value] autorelease];
}
So they are returning an id* which is really just an id.
To me that's either a nonsense/error or an attempt to manipulate ObjC internals (even if undocumented, the first thing an ObjC object stores is in fact a pointer to the object class and is therefore of type Class which is compatible with id, therefore it somehow is valid to cast a pointer to an object or an id that refers to an object, to Class* or id*). I have no time or interest in going and studying the whole API to figure out why they do that. They may actually have a good reason (for example if you only pass that result to another API that knows what it's supposed to be, but you are doing more than that here). Instead of studying OCMock I'll try to explain you what is happening as far as I can say (ObjC and ARC).
id __autoreleasing *arg = [OCMArg setTo:mockData];
ARC will do absolutely nothing in this line of code.
What that method does you can see above. Class OCMPassByRefSetter is a simple class that just stores the argument after retaining it, so mockData is retained. The OCMPassByRefSetter is autoreleased and will disappear at the next drain (releasing the mockData and making *arg reference to released memory).
Note that arg in fact points to the isa of the OCMPassByRefSetter (the isa is the "first" ivar of any object, it's of type Class and points to the class of the object. But this is undocumented and may change at any time).
CFTypeRef expectedResult = (__bridge CFTypeRef) *arg;
*arg is of type id which is compatible with CFTypeRef, so the cast is valid. You use __bridge so ARC does absolutely nothing.
If arg pointed to a "toll free bridged" CF/Cocoa class this would be perfectly valid code but you'd have to be careful that expectedResult would become invalid at the next drain (it's not retained, but it's live as an autoreleased instance).
[[[self.mockSecItemService expect] andReturnValue:OCMOCK_VALUE(mockCopyStatus)] copyItemMatching:queryCheck
result:&expectedResult];
No idea what this line does. Given the prototype you posted in the comment above, ARC does nothing on the part result:&expectedResult.
You say it's a wrapper around SecItemCopyMatching, but as I understand it it's more than that. If it was just immediately calling SecItemCopyMatching passing it the result: argument, you'd likely be messing things up. But the name expectedResult and the fact that this is OCMock makes me think this is a little more complex than that.
You'll have to investigate it yourself a bit. But remember:
as soon as the current function exits, the argument you passed (&expectedResult) will become invalid as it's a local variable.
as soon as there is a drain, the value of expectedResult will become invalid, as that address points to memory that is going to be deallocated by the drain.
doing anything with the value of expectedResult is likely do be going very wrong as I do not think that a Class qualifies as "toll free bridged".
I suspect, but I may be very wrong, that you are not using the OCMock apis the way they are intended to be used. But on this front I cannot help you, and maybe you are actually doing it right.
Rather than try and figure out how to cast the variable into the correct format (OCMock is doing some complex things internally), I added another method, to handle the conversion.
- (OSStatus)findItemMatching:(NSDictionary *)query result:(id __autoreleasing *)outResult {
NSAssert(outResult, #"outResult is required");
CFTypeRef result = nil;
OSStatus status = [self copyItemMatching:query result:&result];
if (result) {
*outResult = CFBridgingRelease(result);
}
return status;
}
Related
I think I have a pretty good understanding of ARC and the proper use cases for selecting an appropriate lifetime qualifiers (__strong, __weak, __unsafe_unretained, and __autoreleasing). However, in my testing, I've found one example that doesn't make sense to me.
As I understand it, both __weak and __unsafe_unretained do not add a retain count. Therefore, if there are no other __strong pointers to the object, it is instantly deallocated (with immutable strings being an exception to this rule). The only difference in this process is that __weak pointers are set to nil, and __unsafe_unretained pointers are left alone.
If I create a __weak pointer to a simple, custom object (composed of one NSString property), I see the expected (null) value when trying to access a property:
Test * __weak myTest = [[Test alloc] init];
myTest.myVal = #"Hi!";
NSLog(#"Value: %#", myTest.myVal); // Prints Value: (null)
Similarly, I would expect the __unsafe_unretained lifetime qualifier to cause a crash, due to the resulting dangling pointer. However, it doesn't. In this next test, I see the actual value:
Test * __unsafe_unretained myTest = [[Test alloc] init];
myTest.myVal = #"Hi!";
NSLog(#"Value: %#", myTest.myVal); // Prints Value: Hi!
Why doesn't the __unsafe_unretained object become deallocated?
[EDIT]: The object is being deallocated... if I try to substitute lines 2 - 3 with NSLog(#"%#", myTest); the app crashes (and an overridden dealloc in Test is being called immediately after the first line). I know that immutable strings will continue to be available even with __unsafe_unretained, and that a direct pointer to the NSString would work. I am just surprised that I could set a property on a deallocated object (line 2), and that it could later be dereferenced from a pointer to the deallocated object it belonged to (line 3)! If anyone could explain that, it would definitely answer my question.
I am just surprised that I could set a property on a deallocated object (line 2), and that it could later be dereferenced from a pointer to the deallocated object it belonged to (line 3)! If anyone could explain that, it would definitely answer my question.
When the object is deallocated it is not zeroed. As you have a pointer to the deallocated object and the property value is stored at some offset to that pointer it is possible that storing and retrieving that property value will succeed after deallocation, it is also quite possible that everything will blow up for some reason or other.
That your code works is quite fragile, try debugging it with "Show Disassembly While Debugging" and stepping through, you'll probably hit an access violation, or take down Xcode itself...
You should never be surprised that strange things happen in C, Objective-C, C++ or any of the family; instead reserve your surprise for so few strange things happening!
Because the constant string in objc is a constant pointer to a heap address and the address is still valid.
edited after comment:
Maybe because the memory at the test objects address hasn't been overwritten and still contains that object? Speculating....
You can see when Test is deallocated by implementing its -dealloc method and adding some simple logging.
However, even if Test is deallocated immediately, the memory it occupied in RAM may remain unchanged at the time you call myVal.
#"hi!" produces a static global constant string instance that is, effectively, a singleton. Thus, it'll never be deallocated because it wasn't really allocated in the first place (at least, it really isn't a normal heap allocation).
Anytime you want to explore object lifespan issues, always use a subclass of NSObject both to guarantee behavior and to make it easy to drop in logging hooks by overriding behavior.
Nothing strange there…
You need to have at least 1 strong reference to object to keep it alive.
Test * anTest = [[Test alloc] init];
Test * __weak myTest = anTest;
myTest.myVal = #"Hi!";
NSLog(#"Value: %#", myTest.myVal); // Prints Value: (Hi)
Can someone please explain to me the purpose of having __autoreleasing in the following sample code block?
- (void)execute:(NSError * __autoreleasing *)error {
// do stuff, possibly assigning error if something went wrong
}
I removed the __autoreleasing and everything still seems to compile/run fine. I started using obj-c post ARC so I never really learned/understood all those double underscore thingamajigs. I've read the ARC transition guide, but I don't fully understand their NSError example.
Consider how ARC works with variables - each reference variable has a mode (implicit or explicit): strong, weak, etc. This mode let's ARC know how to handle reads and writes to that variable; e.g. for a strong variable reading requires no additional action while writing requires releasing the existing reference in the variable before it is replaced by the new one. ARC needs to know the mode of any variable in order to function.
Now consider variables that themselves are passed by reference, e.g. for your execute you'll have a call along the lines of:
NSError *myError = nil;
...
[someObject execute:&myError]; // pass the variable itself by reference, not the variables value
and the body of execute will contain an assignment along the lines of:
- (void)execute:(NSError * __autoreleasing *)error
{
...
if (error != NULL)
*error = [NSError ...]; // assign indirectly via the reference to a variable
...
}
Now for that indirect assignment ARC needs to know the mode of the referenced variable so it knows how to read and write. That is what the __autoreleasing is in the declaration, it tells ARC that it has been passed a reference to a variable whose mode is autoreleasing, and that tells ARC how to read and write the contents of the variable. Remove the __autoreleasing and a default mode will be assumed, and in this case I'd suggest being explicit is certainly good.
The autoreleasing mode means the variable contains a reference which is not owned, reads should retain if necessary and writes can just write. It is used mainly for variables passed by reference.
You might notice that in the example above the variable myError has mode strong (implicitly) and yet it is passed by reference as autoreleasing - the compiler handles this automatically by introducing a temporary autoreleasing variable, copying without retaining the current reference in myError into it, and passing the temporary by reference as the argument to execute:. After the call returns the compiler does a normal assignment from the temporary to myError, which results in any old reference being released and the returned one retained.
For more details see Apple's Transitioning to ARC Release Notes
Followup to Comments
Q: Is __autoreleasing implicitly set?
A: Well Apple's document is not specific, but the Clang documentation says it is implicit for indirect parameters. As above I'd recommend being explicit, clarity is a Good Thing™.
Q: Does the placement matter?
A: Yes, and no... This is a C declaration, the stuff of quiz questions ("What does the following declare..."). The qualifier should be between the two asterisks as it is a pointer to a (variable of type) autoreleasing pointer to an object, but Apple state the compiler is "forgiving" without being specific of what it forgives. Play it safe, put it in the right place.
Q: Should you not test for error being NULL before doing the indirect assignment?
A: Of course you should, somewhere before you do the indirection. The code shown is just an outline and such detail was elided and covered by the ...’s. However as it has been raised a few times over the years maybe I elided too much, a suitable if has been added.
I'm in the process of converting my project to using ARC. I have a category on NSColor with a method that returns an autoreleased CGColor representation:
#implementation NSColor (MyCategory)
- (CGColorRef)CGColor
{
NSColor *colorRGB = [self colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
CGFloat components[4];
[colorRGB getRed:&components[0]
green:&components[1]
blue:&components[2]
alpha:&components[3]];
CGColorSpaceRef space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
CGColorRef theColor = CGColorCreate(space, components);
CGColorSpaceRelease(space);
return (CGColorRef)[(id)theColor autorelease];
}
#end
What is the correct way to do this with ARC? I don't want to return a retained CGColor.
The ARC converter in XCode suggest using
return (CGColorRef)[(__bridge id)theColor autorelease];
but that results in the following error message:
[rewriter] it is not safe to cast to 'CGColorRef' the result of
'autorelease' message; a __bridge cast may result in a pointer to a
destroyed object and a __bridge_retained may leak the object
Essentially it's because there is no good way to convert the following code in ARC:
CGColorRef a = ...;
id b = [(id)a autorelease];
CGColorRef c = (CGColorRef)b;
// do stuff with c
The converter removes -autorelease and adds some bridged casts, but it gets stuck:
CGColorRef a = ...;
id b = (__bridge_transfer id)a;
CGColorRef c = (__bridge_SOMETHING CGColorRef)b;
// do stuff with c. Except the compiler sees that b is no longer being used!
But what should the migrator choose to do for __bridge_SOMETHING?
If it picks __bridge, then b is no longer used so the compiler can immediately release it. This crashes.
If it picks __bridge_retained, then ownership is transferred back to "CF-land", but the original code assumed that the object would be owned by the autorelease pool. The code now leaks.
The problem is that ARC forbids calling -autorelease but does not have a documented method to guarantee that an object is added to the autorelease pool — the only good reason to do this to return an autoreleased CF type from a method, but plenty of UIKit classes have CF-typed properties (and MKOverlayPathView has an atomic CGPathRef property which must return an autoreleased value).
This is one of the tricky bits of ARC that I really wish was better documented.
There are a few hoops you can jump through which might work with varying degrees of success. In order of increasing ickiness:
Define a CFAutorelease() function in a file compiled without ARC (add -fno-objc-arc to the compiler flags in target settings → Build Phases → Compile Sources). I leave this as an exercise to the reader. This works because ARC code needs to interoperate with MRC code. This is probably the cleanest solution. (This is bound to attract a comment saying that it shouldn't use the CF prefix, but as long as you don't see a link error, C symbol name collisions are generally safe because the of the "two-level namespace" introduced in 10.3 or so.)
Various hoops to send it an -autorelease message or equivalent. All of these are a bit messy because they rely on "fooling" ARC, except the last one which assumes id is ABI-compatible with void*. They're also probably slower than the above because they need to look up a class/selector (objc_lookUpClass() and sel_registerName() might be faster or even optimized away, but I wouldn't bet on it).
return (__bridge CGColorRef)[(__bridge id)theColor performSelector:NSSelectorFromString(#"autorelease")]
[NSClassFromString(#"NSAutoreleasePool") addObject:(__bridge id)theColor]
return theColor;
return (__bridge CGColorRef)((id(*)(id,SEL))objc_msgSend)((__bridge id)theColor,NSSelectorFromString(#"autorelease"));
return ((void*(*)(void*,SEL))objc_msgSend)(theColor,NSSelectorFromString(#"autorelease"));
Force it to be added to the autorelease pool by assigning to an __autoreleasing variable that the compiler can't optimize away. I'm not sure if this is guaranteed (in particular, something similar to objc_autoreleaseReturnValue() and objc_retainAutoreleasedReturnValue() might be possible, but I think this is unlikely since it would slow down the common case of (NSError * __autoreleasing *)error).
-(id)forceAutorelease:(id)o into:(id __autoreleasing*)p
{
*p = o;
return p;
}
-(CGColorRef)CGColor
{
...
CGColorRef theColor = CGColorCreate(...);
CGColorSpaceRelease(space);
id __autoreleasing temp;
return (__bridge CGColorRef)[self forceAutorelease:(__bridge_transfer id)theColor into:&temp];
}
(It also might be possible for the compiler/runtime to co-operate and use static dispatch/inlining until the relevant methods are overridden, but that seems tricky and not without significant overheads of its own.)
Use a typedef with __attribute__((NSObject)). This is the most confusingly documented parts of the ARC spec, but something like this seems to work:
typedef CGColorRef MyCGColorRef __attribute__((NSObject));
-(MyCGColorRef)CGColor
{
...
return (__bridge MyCGColorRef)(__bridge_transfer id)theColor;
}
I think you need two bridges for this to work (one to transfer ownership to ARC and another to); if you simply return theColor; I suspect it is leaked. From my reading of the docs, you ought to just need (__bridge_transfer MyCGColorRef) because it's converting from a non-ARC pointer (CGColorRef) to an ARC pointer (MyCGColorRef), but that makes the compiler complain. Alas, the docs do not give any examples of how to use __attribute__((NSObject)) typedefs.
Note that you do not need to change the return type in the header. Doing so may enable autoreleased return value optimization, but I'm not sure how the compiler handles the conversion from MyCGColorRef to CGColorRef. Le sigh.
CGColor is a Core Foundation object. You should not attempt to use autorelease with it. Instead, you should rename your method copyCGColor and return a retained object.
Auto-releasing is an Objective-C concept. It does not exist at the Core Foundation level.
Since CGColor is not toll-free bridged to any Objective-C class, it is very weird to try to autorelease it (even if that might work).
Update a few years later
There is now CFAutorelease() at the CoreFoundation level (available since Mavericks and iOS 7).
Starting with OS X 10.9 or iOS 7 you can just use CFAutorelease() (declared in CFBase.h).
Indeed, in manual memory management you can retain, release and autorelease any CoreFoundation object, because they all are toll-free bridged to at least NSObject.
Since ARC forbids use of manual memory management, we should somehow tell hint the compiler what to do. One way is to name your method - (CGColorRef)copyCGColor; so the compiler will know the method returns object with +1 retain count.
However if you are like me and prefer plain "CGColor" for such methods, you can just append __attribute__((cf_returns_retained)) to the method definition:
#interface NSColor (MyCategory)
- (CGColorRef)CGColor __attribute__((cf_returns_retained));
#end
I think you want to use __bridge_transfer in this case.
Docs
I have a class RemoteImageLoader which has a method loadImage:
- (void) loadImage: (NSString*) url setTarget:(NSData **)target;
I used a NSData** here because I need to indirectly return NSData* , just like some typical method:
- (BOOL)save:(NSError**)
since the method will actually invoke another asynchronous method, I have to save the target as a member variable so I can access it later. but when I define a NSData ** member variable:
#interface RemoteImageLoader : NSObject
#property NSData** target;
#end
the compiler complains that "Pointer to non-const type 'NSData*' with no explicit ownership". I've done some search on google, but find no answer of it. Could anyone help me with this? Thanks a lot
and I've tried to replace the declaration to
#interface RemoteImageLoader : NSObject
#property NSData * __autoreleasing * target;
#end
but the problem still exists
The ARC Transition Notes recommend you declare indirect pointers to NSData and NSError objects in your case with __autoreleasing, like (NSData * __autoreleasing *)target;
__autoreleasing is known as a lifetime qualifier which tells the compiler to return an autoreleased instance of the object.
Because of this, a rewrite of your method signature is required.
- (void) loadImage: (NSString*) url setTarget:(NSData* __autoreleasing *)target;
Be warned, __autoreleasing objects are extremely short lived. Declare your NSData** as __strong to override the default __autoreleasing for a longer lifetime.
I think your method signature is going to cause trouble. A caller is very likely to assume that the pointed-to pointer is filled in as soon as your method returns. Similarly, they are very likely to pass the address of a stack variable which won't be valid for long. Lastly, your method provides no means for the caller to know when the pointed-to pointer has been filled with a value.
You are probably better off taking a completion block from the caller. The completion block will receive an NSData pointer as an argument. Something like:
- (void) loadImage: (NSString*) url completionHandler:(void (^)(NSData* data))block;
This also mirrors the underlying framework API I presume you're using, which is always good for reducing "impedance mismatch".
As for the specific narrow issue you're encountering from the compiler, I suspect the issue is that the compiler can't know if it should emit retains and releases when you assign to *target. It wants you to explicitly declare the ownership characteristic of the pointed-to pointer. I can't check at the moment, but I guess that declaring it as __strong NSData** target would work. That is, it's not interested in whether target owns what it's pointing at, since one can't own a pointer. It's interested in whether the NSData* pointer to which target points owns the NSData object to which it points.
I can't be sure what you are trying to do without seeing your code, but why are you trying to create a pointer to an NSData object (Which is a pointer to NSData). Because you are creating a pointer to a pointer which is probably why you are getting the error. Try removing one of the pointers and see what happens.
Generally, when you do this sort of thing outside of ARC you do something like:
NSData* returnedParm;
[someObj doSomething:&returnedParm];
on the caller's side. I don't see your equivalent of my returnedParm above. (I've never tried this with ARC, but I'd think the basics would have to be similar.)
Declaring a property as NSData** is declaring a pointer to a non-object and it would not be retained (because there's no object to retain).
My guess is that you should prototype your function as:
-(void)doSomething:(NSData* __autoreleasing*)theReturnParm
and assign to it inside that function using *theReturnParm = something;.
Then on the calling side you'd have your returnedParm as an autoreleased value (so if you want to preserve it you should relatively quickly assign it to a strong pointer).
In objective-c, I have a utility class with a bunch of static methods that I call for various tasks. As an example, I have one method that returns an NSArray that I allocate in the static method. If I set the NSArray to autorelease, then some time later, the NSArray in my calling method (that is assigned to the returned pointer) losses it's reference because the original form the static method is cleaned up. I can't release the NSArray object in the static method because it needs to be around for the return and assignment.
What is the right way to return an object (like the NSArray) from a static class, and have it hang around for the calling class, but then get cleaned up later when it is no longer needed?
Do I have to create the object first in the caller and pass in a pointer to the object and then return that same object form the static method?
I know this is a basic O-O problem, I just never had this issue in Java and I do not do much C/C++.
Thanks for your help.
Your autorelease is correct in the return just retain it when you call the static method.
NSArray *data = [[StaticClass getArray] retain];
If you have a property for the place your assigning the return value to, you can just do self.data = .. and the retain is automatic.
Please take the time to read over the rules. These apply to all of the frameworks you'll be using, and should apply to your code as well. Burn these into your head, and they'll become second nature. Thankfully, it's not complex, rather simple.
It's quite simple. If you do not own an object, it will go away at some indeterminate point in the future. In your case, the "indeterminate" point is when the autorelease pool gets drained, which in the normal case, is at the end of processing the current event.
If you want an object to hang around, you need to own it. The memory management rules referred to by jer will tell you exactly how you get ownership of an object. In this case, you need to retain the object. You must then, of course, release it later when you have done with it.
Regards your comment to Matt's answer. Your code is this:
for (NSString * date in dateList)
{
[historyList addObject:[[BIUtility historyForDate:date] retain]];
}
and
+ (NSArray *) historyForDate:(NSString *)date
{
NSMutableArray * ret = [[[NSMutableArray alloc] init] autorelease];
}
The first thing you need to know is that collections retain their members, so, in fact, your retain of the historyForDate is unnecessary. You don't want to own that object, historyList does. If it's disappearing, it's probably because historyList itself is being deallocated (because you don't own it) or is nil.
By the way, historyForDate: does nothing with the date. Is that correct?