Search code examples
memory-managementios5memory-leakscore-text

How to release Core foundation object when work with Core text


I have a method that will calculate the height of a text line. But the problem is it leak the memory with 2 items: CTFrame and a Malloc (48 byte).

Here are the core of that method:

(void)calculatePageHeight {
    __weak UIBezierPath *path = [UIBezierPath bezierPathWithRect:self.view.bounds];

    NSString *sampleText = @"The CTFont opaque type represents a Core Text font object. Font objects represent fonts to an application, providing access to characteristics of the font, such as point size, transform matrix, and other attributes. Fonts provide assistance in laying out glyphs relative to one another and are used to establish the current font when drawing in a graphics context.";
    NSRange contentRange = NSRangeFromString(sampleText);
    NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:sampleText attributes:self.textAttributes];

    CFAttributedStringRef attributeRef = (__bridge CFAttributedStringRef)attributedString;

    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attributeRef);

    CGPathRef myPath = [path CGPath];
    CFRange myRange = CFRangeMake(contentRange.location, contentRange.length);

    CTFrameRef contentFrame = CTFramesetterCreateFrame(framesetter, myRange , myPath, nil);
    CFArrayRef lines = CTFrameGetLines(CFRetain(contentFrame));
    NSInteger lineCount = CFArrayGetCount(lines);
    CGPoint *origins = calloc(lineCount, sizeof(CGPoint));

    CTFrameGetLineOrigins(contentFrame, CFRangeMake(0, 0), origins);
    CGFloat lineSpacing = 0;

    for (NSInteger index = 0; index < lineCount; index ++) {
        CTLineRef line = CFArrayGetValueAtIndex(lines, index);
        CGFloat ascent;
        CGFloat descent;

        CTLineGetTypographicBounds(line, &ascent, &descent, nil);
        NSLog(@"line height: %f", ascent + (descent * 2));

        lineSpacing = ascent + (descent * 2);
    }
    free(origins);
    CFRelease(lines);
    //free(contentFrame);

    NSLog(@"line spacing: %f", lineSpacing);

    NSInteger numberOfLine = TEXT_PAGE_HEIGHT / (lineSpacing);

    CGFloat pageHeight = numberOfLine * (lineSpacing);
    self.pageHeight = pageHeight;

    CGPathRelease(myPath);
    CFRelease(framesetter);
}

If I uncomment the line, the CTFrame will be out, but there will be a warning:

Passing CTFrameRef (aka const struct_CTFrame *) to parameter of type "void *' discards qualifiers)

free(contentFrame);

then the leaking will have only one for Malloc. The instrument tool let me know this line of code cause the leaking.

CTFrameRef contentFrame = CTFramesetterCreateFrame(framesetter, myRange , myPath, nil);

Any one can help me to explain this, I can not explain why the Malloc is leaking. And how to fix that, how to release CTFrame object as well ?

I research so much but could not found a solution.


Solution

  • Use CFRelease instead of free, the documentation doesn't mention using CFRelease to deallocate CT* objects, but it just works.