2012-05-06 33 views
0

我有一種將計算文本行高度的方法。但問題是它泄漏內存2項:CTFrame和一個Malloc(48字節)。如何在使用Core內核時釋放內核基礎對象

以下是該方法的核心:

(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); 
} 

如果我取消註釋行了,CTFrame會出來,但會有一個警告:

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

free(contentFrame); 

則泄漏將有隻有一個用於Malloc。 儀器工具讓我知道這行代碼導致泄漏。

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

任何人都可以幫助我解釋這一點,我無法解釋爲什麼Malloc泄漏。以及如何解決,如何釋放CTFrame對象?

我研究了很多,但找不到解決方案。的free

回答

2

使用CFRelease相反,文件沒有提到使用CFRelease解除分配CT*對象,但它只是工作。

0

的問題是在這些行:

CTFrameRef contentFrame = CTFramesetterCreateFrame(framesetter, myRange , myPath, nil); 
CFArrayRef lines = CTFrameGetLines(CFRetain(contentFrame)); 

在第一行中保留contentFrame的計數器是1,在第二它增加至2

不應調用CFRetain(),並且當你完成了它的工作,寫:

CFRelease(contentFrame), contentFrame = NULL; 

而且,可以肯定的是CTFrame不爲NULL。它可能還沒有被創建。 而且......不要放行!你不爲他們分配內存,你只需要參考。

你的代碼應該尋找這樣的事情:

(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); 
    if(framesetter == NULL) 
    { 
     [attributedString release], attributedString = nil; 
     return; 
    } 

    CGMutablePathRef myPath = CGPathCreateMutable(); 
    CGPathAddRect(myPath, self.view.bounds); 

    CFRange myRange = CFRangeMake(contentRange.location, contentRange.length); 

    CTFrameRef contentFrame = CTFramesetterCreateFrame(framesetter, myRange , myPath, nil); 
    if(contentFrame == NULL) 
    { 
     CFRelease(framesetter), framesetter = NULL; 
     [attributedString release], attributedString = nil; 
     return; 
    } 
    CFArrayRef lines = CTFrameGetLines(contentFrame); 
    NSInteger lineCount = CFArrayGetCount(lines); 
    CGPoint *origins = (CGPoint *)malloc(lineCount * sizeof(CGPoint)); 

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

    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 + (fabs(descent) * 2)); 

     lineSpacing = ascent + (fabs(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), myPath = NULL; 
    CFRelease(framesetter), framesetter = NULL; 
    CFRelease(contentFrame), contentFrame = NULL; 
    [attributedString release], attributedString = nil; 
}