Which __bridge free bridge should be used to create the Objective-C convenience constructor in C ref?

I am trying to convert a manual save release code to ARC.

I am trying to figure out the correct path to a free bridge when I have an Objective-C convenience constructor whose return value is stored in CFTypeRef.

Existing code using MRR:

@interface SourceItemCell UITableViewCell { CATextLayer *mSourceText; } @implementation SourceItemCell - (id)init { self = [super init]; mSourceText = [CATextLayer layer]; // key line I'm wondering about: mSourceText.font = [UIFont fontWithName:@"HelveticaNeue" size:12.0]; [[self contentView].layer addSublayer:mSourceText]; return self; } 

So you don’t have to look for documentation, the CATextLayer font property is of type CFTypeRef.

It looks like my options are:

 mSourceText.font = (__bridge CFTypeRef)[UIFont fontWithName:@"HelveticaNeue" size:12.0]; 

or

 mSourceText.font = (__bridge_transfer CFTypeRef)[UIFont fontWithName:@"HelveticaNeue" size:12.0]; 

or

 mSourceText.font = (__bridge_retained CFTypeRef)[UIFont fontWithName:@"HelveticaNeue" size:12.0]; 

Here is my thinking. The vivid guide to the free bridging I found is http://www.mikeash.com/pyblog/friday-qa-2011-09-30-automatic-reference-counting.html . There is a similar example of casting an Objective-C type to a C type, which he writes about:

Using __bridge_retained, we can inform ARC of the transfer of ownership from the system to our hands. Since ownership is transferred, we are now responsible for the release of the property when it is completed with it, as with any other CF code.

... Otherwise, if we used only __bridge, ARC would not have made any effort to keep the memory in our CFTypeRef account.

So here is what I consider the most sensible way:

 mSourceText.font = (__bridge_retained CFTypeRef)[UIFont fontWithName:@"HelveticaNeue" size:12.0]; ... // At some later point CFRelease(mSourceText.font); 

Now, if this is correct, I still do not quite understand when I can be sure that it is safe to free it, but if I never release it, it will be at least just a small memory leak, right?

In conclusion, my current questions are:

  • Is my suggested code correct?
  • Where can I get CFRelease this object? In dealloc function for SourceItemCell?

This is why I did not think related questions answered my question:

PS. Please do not judge me, because I use Helvetica ... :)

Edit:

When I use __bridge_retained and do a static analyzer, I get this complaint:

Static analyzer complaint

"The property returns a Core Foundation object with a +0 save count. Incorrect decrement of the reference counter of an object that is not currently owned by the caller.

(The mDelegate and IS_ARC lines, I believe, are not relevant to this problem.)

So, I fundamentally don’t understand something correctly ...

+4
source share
2 answers

Firstly, I am wondering if the MRR source code is correct. According to the documentation, you cannot assign a UIFont object to the font property of a CATextLayer object, but either CTFontRef or a CGFontRef . Something like this should work fine:

  CGFontRef font = CGFontCreateWithFontName(CFSTR("HelveticaNeue")); mSourceText.font = font; CGRelease(font); mSourceText.fontSize = 12.0; 

To answer your connection question, let's say that it would be correct to drop UIFont * in CGFontRef (which, I am sure, not!). Then you should use __bridge :

  mSourceText.font = (__bridge CGFontRef)[UIFont fontWithName:@"HelveticaNeue" size:12.0]; 

The reason is that the CATextLayer object in mSourceText will be held on the font itself, so we do not need to do this.

We have to be careful though if we saved CGFontRef between them. Code like this is dangerous:

 CGFontRef fontRef = (__bridge CGFontRef)[UIFont fontWithName:@"HelveticaNeue" size:12.0]; mSourceText.font = fontRef; 

ARC can free a UIFont object between the first and second statement so that the fontRef pointer fontRef to the freed object. If we want to write code in two operations, we must save the object so that it is long enough so that it can be assigned, and then release it:

 CGFontRef fontRef = (__bridge_retained CGFontRef)[UIFont fontWithName:@"HelveticaNeue" size:12.0]; mSourceText.font = fontRef; CFRelease(fontRef); 
+4
source

I agree with Tammo's answer.

I recommend that you always use cover functions for __bridge_transfer and __bridge_retained : CFBridgingRelease() and CFBridgingRetain() respectively. They help clarify your thinking.

You can use CFBridgingRelease() only when you are entitled to CFRelease() . And you should only use CFBridgingRetain() , where that makes sense for CFRetain() .

The +[UIFont fontWithName:size:] method does not give you ownership of the returned object, so you do not have the right to release it, so of course you would not CFRelease() it, and you should not CFBridgingRelease() it.

Now consider another case: would you have a CFRetain() or -retain object before passing it to the property setting tool? Consider a slightly different case. Imagine a class with a font property of type UIFont* , and not any type of Core Foundation. You will do this (according to MRR):

 someObject.font = [[UIFont fontWithName:@"HelveticaNeue" size:12.0] retain]; 

?

I hope you know you shouldn't. You do not have the proper way to free this object in order to maintain balance. (And, no, the execution of the later [someObject.font release] is incorrect. The property may not return the same object from its receiver that was passed to the setter. The installer can make a copy or calculate a new value based on the value passed in Or do something- anything else that he likes.)

In any case, as soon as you understand that in this situation you will not be -retain , you will understand that you do not want CFRetain() , and you should not CFBridgingRetain() .

Finally, another way to think about things is locally managing memory. The calling setter is not responsible for running the transferred object. The setter implementation is responsible for this if it ultimately maintains a reference to the passed object (which it cannot). When you write a method or class, you should handle memory management for this method or class, and not for any other method or class. You should expect another method or class to take care of its own responsibilities. (This principle also allows you to mix ARC-compiled and MRR code.)

+2
source

Source: https://habr.com/ru/post/1481431/


All Articles