EmptyStack
EmptyStack

Reputation: 51374

Convert __bridge CFType to support ARC

Could some one help me convert the below code to support ARC?

UIFont *boldFont = [UIFont fontWithName:@"DINPro-Medium" size:14];
CTFontRef ctBoldFont = CTFontCreateWithName((__bridge CFStringRef)boldFont.fontName, boldFont.pointSize, NULL);
CGColorRef cgColor = UIColorFromRGB(0x2b776d).CGColor;

NSNumber* underline = [NSNumber numberWithInt:kCTUnderlineStyleSingle];
NSDictionary *ULSubattributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                     CFBridgingRelease(ctBoldFont), (id)(id)kCTFontAttributeName,
                                     cgColor, (id)kCTForegroundColorAttributeName,underline, (NSString*)kCTUnderlineStyleAttributeName, nil];

I am getting a crash on the last line saying,

*** -[Not A Type retain]: message sent to deallocated instance 0x20ad4910
*** -[Not A Type class]: message sent to deallocated instance 0x20ad4910

I hope this is a duplicate question. But I am stuck. Thanks.

Upvotes: 2

Views: 846

Answers (2)

David Hoerl
David Hoerl

Reputation: 41642

/* OK */UIFont *boldFont = [UIFont fontWithName:@"DINPro-Medium" size:14];
assert(boldFont); // just be sure
/* OK */CTFontRef ctBoldFont = CTFontCreateWithName((__bridge CFStringRef)boldFont.fontName, boldFont.pointSize, NULL);
assert(boldFont); // just be sure

/* 1) CGColorRef cgColor = UIColorFromRGB(0x2b776d).CGColor; */
CGColorRef cgColor = CGColorCreateCopy( UIColorFromRGB(0x2b776d).CGColor );
assert(cgColor); // just to be sure

/* OK */NSNumber* underline = [NSNumber numberWithInt:kCTUnderlineStyleSingle];

NSDictionary *ULSubattributes = @{ 
/* you don't own the kCT strings */(__bridge NSString *)kCTFontAttributeName : CFBridgingRelease(ctBoldFont),
/* ... */   (__bridge NSString *)kCTForegroundColorAttributeName : CFBridgingRelease(cgColor),
/* ... */   (__bridge NSString *)kCTUnderlineStyleAttributeName : underline };

1) There is a bug in iOS pre-iOS6 where ARC will release the UIColor backing the CGColorRef while you are still using the CGColorRef. I know this since I created a rdar which was then reported as fixed in iOS 6.

PS: a nice blog by Mike Ash here

EDIT: this code works fine in my iOS demo app (deploy set to 5.1 and 6 both) - see the log message. I made the dict an ivar.

{

    UIFont *boldFont = [UIFont fontWithName:@"Helvetica" size:14];
    assert(boldFont); // just be sure
    CTFontRef ctBoldFont = CTFontCreateWithName((__bridge CFStringRef)boldFont.fontName, boldFont.pointSize, NULL);
    assert(boldFont); // just be sure

    CGColorRef cgColor = CGColorCreateCopy( [UIColor colorWithRed:0.8f green:0.8f blue:0.8f alpha:0.8f].CGColor );
    assert(cgColor);

    NSNumber* underline = [NSNumber numberWithInt:kCTUnderlineStyleSingle];
    assert(underline);

    ULSubattributes = @{ 
        (__bridge NSString *)kCTFontAttributeName : CFBridgingRelease(ctBoldFont),
        (__bridge NSString *)kCTForegroundColorAttributeName : CFBridgingRelease(cgColor),
        (__bridge NSString *)kCTUnderlineStyleAttributeName : underline };

    NSLog(@"ULSubattributes: %@", ULSubattributes);
}

2013-04-12 11:48:20.294 WebViewScrollTester[44147:c07] ULSubattributes: { CTForegroundColor = " [ (kCGColorSpaceDeviceRGB)] ( 0.8 0.8 0.8 0.8 )"; NSFont = "CTFont \nCTFontDescriptor {type = mutable dict, count = 1,\nentries =>\n\t1 : {contents = \"NSFontNameAttribute\"} = {contents = \"Helvetica\"}\n}\n>"; NSUnderline = 1; }

EDIT2: I even added a dispatch_after to show nothing has gotten released by ARC:

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^
        {
            NSLog(@"ULSubattributes: %@", ULSubattributes);
        } );

Upvotes: 2

matt
matt

Reputation: 535306

Here is some actual working code of mine that does something quite similar to yours:

 CTFontRef font2 =
     CTFontCreateCopyWithSymbolicTraits (
         basefont, f, nil, kCTFontBoldTrait, kCTFontBoldTrait);
 NSDictionary* d2 =
     @{(NSString*)kCTFontAttributeName: CFBridgingRelease(font2)};
 [mas addAttributes:d2 range:encRange];

Note that I do not release font2! CFBridgingRelease means "ARC, this object has been retained; you release it when the time comes." And ARC does. No leak, no zombie, no crash, no problem.

(On the other hand, basefont, which was created earlier with CTFontCreateWithName and was never handed over to ARC for control, must be released explicitly with CFRelease.)

Here is a whole lot more Core Text code from my book, showing ARC memory management throughout:

http://www.apeth.com/iOSBook/ch23.html#_core_text

And here is the section of my book about CFType memory management with ARC:

http://www.apeth.com/iOSBook/ch12.html#_memory_management_of_cftyperefs

Upvotes: 3

Related Questions