0
votes

I am using a Core Foundations method I borrowed from Apple's useful UIElementUtilities app. The problem is that I wish to update this borrowed method so that it runs under Apple's new Automatic Reference Counting (ARC) system. I have made some progress adapting most of my borrowed methods by inserting the '__bridge' qualifier before variables, however with the method shown below I get the following error after attempting to convert to ARC: "error: Incompatible types casting 'NSString __strong *' to 'CFTypeRef *' (aka 'const void **) with a __bridge cast". How do I make make an acceptable pointer to the 'actionDescription' buffer so that its contents is recast to an NSString?

+ (NSString *)descriptionOfAction:(NSString *)actionName ofUIElement:(AXUIElementRef)element {

NSString * actionDescription = nil;

AXUIElementCopyActionDescription(element, (__bridge CFStringRef)actionName, (__bridge CFStringRef *)&actionDescription);

return actionDescription;

//return [actionDescription autorelease];

}

1

1 Answers

3
votes

Interesting question.

In ARC when you assign a reference to a variable ARC needs to know what to do with the previous value of the variable. If the variable is __strong then the old reference needs to be released, if it is __unsafe_unretained it can just discard the old reference, etc. All this happens most of the time without you needing to be concerned.

When you pass a pointer to a variable containing a reference it gets a bit more complicated, ARC needs to know the qualifier on the pointed at variable. Objective-C uses a technique termed pass-by-writeback, which can involve using hidden temporary variables to make sure it all works correctly, for details see Objective-C Automatic Reference Counting. Core Foundation does not have an equivalent of this and this is what is tripping up your conversion.

The solution is to pass the function a pointer to a Core Foundation typed variable and then to the transfer to Objective-C and ARC after the call:

+ (NSString *)descriptionOfAction:(NSString *)actionName ofUIElement:(AXUIElementRef)element
{   
   CFStringRef actionDescription = nil;

   AXUIElementCopyActionDescription(element, (__bridge CFStringRef)actionName, &actionDescription);

   return (__bridge_transfer NSString *)actionDescription;
}

Note the use of __bridge_transfer - the Copy in the function name indicates that the returned CFStringRef is owned by the caller and must be released after use, the __bridge_transfer hands that ownership to ARC which will then be responsible for releasing the reference.

HTH