I'm having some interesting issues with CoreText on iPhone, causing memory leaks in certain circumstances.
我在iPhone上遇到了一些有趣的CoreText问题,在某些情况下导致内存泄漏。
I've looked everywhere in the documentation and across the internet and no-one seems to be getting the same issue. However, the circumstances are perhaps special (see below).
我在文档和互联网上随处可见,似乎没有人遇到同样的问题。但是,情况可能很特殊(见下文)。
Anyway, after a lot of narrowing down, I managed to get this repro case:
无论如何,在经过大量缩小之后,我设法得到了这个重复案例:
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];
}
Depending on the font and text, this may or may not leak according to the Leaks tool - various/numerous things but definitely seeming font and font descriptor related.
根据字体和文本,这可能会或可能不会泄漏根据泄漏工具 - 各种/众多的东西,但绝对看似字体和字体描述符相关。
These can be caused as follows:
这些可能会导致如下:
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?
Obviously I commented out so as to leave one leakTest call to test with the Leaks tool!
显然我注释掉了,以便使用Leaks工具留下一个leakTest调用来测试!
So, the string with an unusual but perfectly legal unicode character in causes a leak with one font but not the other.
因此,具有不寻常但完全合法的unicode字符的字符串会导致一种字体泄漏但不会泄漏另一种字体。
Is there something wrong in my code and I happen to be "getting away with it" with Arial? I wondered whether there may be some kind of font caching that was causing the apparent leak but the OS or whatever is actually all handling it okay.
我的代码中有什么问题,我碰巧用Arial“侥幸逃脱”吗?我想知道是否可能存在导致明显泄漏的某种字体缓存,但操作系统或其他任何实际上都处理它没问题。
Hope you can help folks!
希望你能帮助大家!
2 个解决方案
#1
0
Although the object being leaked is a CTFont
, I would bet NSMutableAttributedString
is doing the leaking. Try adding a @"bogus"
attribute with, say, an empty NSData
object and see if it is also leaked.
虽然泄露的对象是CTFont,但我敢打赌NSMutableAttributedString正在泄漏。尝试添加一个@“bogus”属性,例如,一个空的NSData对象,看看它是否也被泄露。
#2
0
look at this code (no memory leaks) and I use different fonts and unicode text. There were memory leaks when I use (CFMutableAttributedStringRef)string counstruction.
看看这段代码(没有内存泄漏),我使用不同的字体和unicode文本。当我使用(CFMutableAttributedStringRef)字符串counstruction时有内存泄漏。
I think you have to use CFAttributedStringCreateMutable() to remove leaks.
我认为你必须使用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);
}
}
#1
0
Although the object being leaked is a CTFont
, I would bet NSMutableAttributedString
is doing the leaking. Try adding a @"bogus"
attribute with, say, an empty NSData
object and see if it is also leaked.
虽然泄露的对象是CTFont,但我敢打赌NSMutableAttributedString正在泄漏。尝试添加一个@“bogus”属性,例如,一个空的NSData对象,看看它是否也被泄露。
#2
0
look at this code (no memory leaks) and I use different fonts and unicode text. There were memory leaks when I use (CFMutableAttributedStringRef)string counstruction.
看看这段代码(没有内存泄漏),我使用不同的字体和unicode文本。当我使用(CFMutableAttributedStringRef)字符串counstruction时有内存泄漏。
I think you have to use CFAttributedStringCreateMutable() to remove leaks.
我认为你必须使用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);
}
}