我在iPhone上遇到一些有趣的CoreText问题,在某些情况下导致内存泄漏。
我在文档和互联网上随处可见,似乎没有人遇到同样的问题。但是,情况可能很特殊(见下文)。
无论如何,在经过大量缩小之后,我设法得到了这个重复案例:
void leakTest(NSString* fontname, NSString* text)
{
NSDictionary* descriptorAttr = [NSDictionary dictionaryWithObjectsAndKeys:
fontname, (const NSString*)kCTFontFamilyNameAttribute, nil];
CTFontDescriptorRef descriptor = CTFontDescriptorCreateWithAttributes((CFDictionaryRef)descriptorAttr);
CTFontRef font = CTFontCreateWithFontDescriptor(descriptor, 0, nil);
NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
(id)font, (const NSString*)kCTFontAttributeName, nil];
CFRelease(descriptor);
CFRelease(font);
NSMutableAttributedString* string = [[NSMutableAttributedString alloc] initWithString:text];
[string setAttributes:dict range:NSMakeRange(0, string.length)];
CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedString((CFMutableAttributedStringRef)string);
CFRelease(typesetter);
[string release];
}
根据字体和文本的不同,这可能会或可能不会根据泄漏工具泄漏 - 各种/大量的东西,但绝对看似字体和字体描述符相关。
这些可能导致如下:
const char* unicodeText = "Ernle\310\235e"; // "Ernleȝe" if your editor groks unicode
NSString* textLeaky = [NSString stringWithUTF8String:unicodeText];
NSString* textNormal = @"Hello World";
leakTest(@"Courier", textNormal); // This doesn't leak
leakTest(@"Courier", textLeaky); // This does leak
leakTest(@"Arial", textLeaky); // This doesn't leak with this font?
显然我注释掉了以便使用Leaks工具留下一个leakTest调用进行测试!
因此,具有不寻常但完全合法的unicode字符的字符串会导致一种字体泄漏但不会泄漏另一种字体。
我的代码中有什么问题,我恰好用Arial“侥幸成功”吗?我想知道是否可能存在导致明显泄漏的某种字体缓存,但操作系统或其他任何实际上都处理它没问题。
希望你能帮助别人!
答案 0 :(得分:0)
虽然泄露的对象是CTFont
,但我敢打赌NSMutableAttributedString
正在泄漏。尝试添加一个@"bogus"
属性,例如一个空的NSData
对象,看看它是否也被泄露了。
答案 1 :(得分:0)
查看此代码(没有内存泄漏),我使用不同的字体和unicode文本。 当我使用(CFMutableAttributedStringRef)字符串counstruction时,存在内存泄漏。
我认为您必须使用CFAttributedStringCreateMutable()来消除泄漏。
CTTextAlignment alignment = kCTLeftTextAlignment;
CTLineBreakMode breakMode = kCTLineBreakByTruncatingTail;
CGFloat paragraphSpacing = 0;
CGFloat maximumLineSpacing = 0;
CTParagraphStyleSetting paragraphStyleSetting[] = {
{kCTParagraphStyleSpecifierAlignment, sizeof(CTTextAlignment), &alignment},
{kCTParagraphStyleSpecifierLineBreakMode, sizeof(CTLineBreakMode), &breakMode},
{kCTParagraphStyleSpecifierParagraphSpacing, sizeof(CGFloat), ¶graphSpacing},
{kCTParagraphStyleSpecifierMaximumLineSpacing, sizeof(CGFloat), &maximumLineSpacing}
};
CTParagraphStyleRef paragraphStyleRef = CTParagraphStyleCreate(paragraphStyleSetting, sizeof(paragraphStyleSetting) / sizeof(paragraphStyleSetting[0]));
CFMutableAttributedStringRef attributedStringRef = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
if (attributedStringRef) {
CFAttributedStringReplaceString(attributedStringRef, CFRangeMake(0, 0), (CFStringRef)aText);
CFAttributedStringSetAttribute(attributedStringRef, CFRangeMake(0, aText.length), kCTFontAttributeName, aFontRef);
CFAttributedStringSetAttribute(attributedStringRef, CFRangeMake(0, aText.length), kCTForegroundColorAttributeName, aColorRef);
CFAttributedStringSetAttribute(attributedStringRef, CFRangeMake(0, aText.length), kCTParagraphStyleAttributeName, paragraphStyleRef);
CFRelease(paragraphStyleRef);
CTTypesetterRef typesetterRef = CTTypesetterCreateWithAttributedString(attributedStringRef);
//skip
CFRelease(typesetterRef);
CTFramesetterRef framesetterRef = CTFramesetterCreateWithAttributedString(attributedStringRef);
CFRelease(attributedStringRef);
if (framesetterRef) {
//skip
CFRelease(frameRef);
}
}