0

我正在继承一个 UILabel ,而不是使用 drawRect 我在后台将文本渲染到 UIImage ..这是代码:

- (UIImage *)imageForText
{
    UIGraphicsBeginImageContextWithOptions(self.frameSize, NO, 0);

            CGContextRef ctx = UIGraphicsGetCurrentContext();
            CGContextSaveGState(ctx);

            CGAffineTransform transform = [self _transformForCoreText];
            CGContextConcatCTM(ctx, transform);

            if (nil == self.textFrame) {
                CFAttributedStringRef attributedString = (__bridge CFAttributedStringRef)attributedStringWithLinks;
                CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attributedString);

                CGMutablePathRef path = CGPathCreateMutable();
                // We must tranform the path rectangle in order to draw the text correctly for bottom/middle
                // vertical alignment modes.
                CGPathAddRect(path, &transform, rect);
                if (nil != self.shadowColor) {
                    CGContextSetShadowWithColor(ctx, self.shadowOffset, self.shadowBlur, self.shadowColor.CGColor);
                }
                self.textFrame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL);
                CGPathRelease(path);
                CFRelease(framesetter);
            }

            // Draw the tapped link's highlight.
            if ((nil != self.touchedLink || nil != self.actionSheetLink) && nil != self.highlightedLinkBackgroundColor) {
                [self.highlightedLinkBackgroundColor setFill];

                NSRange linkRange = nil != self.touchedLink ? self.touchedLink.range : self.actionSheetLink.range;

                CFArrayRef lines = CTFrameGetLines(self.textFrame);
                CFIndex count = CFArrayGetCount(lines);
                CGPoint lineOrigins[count];
                CTFrameGetLineOrigins(self.textFrame, CFRangeMake(0, 0), lineOrigins);

                for (CFIndex i = 0; i < count; i++) {
                    CTLineRef line = CFArrayGetValueAtIndex(lines, i);

                    CFRange stringRange = CTLineGetStringRange(line);
                    NSRange lineRange = NSMakeRange(stringRange.location, stringRange.length);
                    NSRange intersectedRange = NSIntersectionRange(lineRange, linkRange);
                    if (intersectedRange.length == 0) {
                        continue;
                    }

                    CGRect highlightRect = [self _rectForRange:linkRange inLine:line lineOrigin:lineOrigins[i]];

                    if (!CGRectIsEmpty(highlightRect)) {
                        CGFloat pi = (CGFloat)M_PI;

                        CGFloat radius = 5.0f;
                        CGContextMoveToPoint(ctx, highlightRect.origin.x, highlightRect.origin.y + radius);
                        CGContextAddLineToPoint(ctx, highlightRect.origin.x, highlightRect.origin.y + highlightRect.size.height - radius);
                        CGContextAddArc(ctx, highlightRect.origin.x + radius, highlightRect.origin.y + highlightRect.size.height - radius,
                                        radius, pi, pi / 2.0f, 1.0f);
                        CGContextAddLineToPoint(ctx, highlightRect.origin.x + highlightRect.size.width - radius,
                                                highlightRect.origin.y + highlightRect.size.height);
                        CGContextAddArc(ctx, highlightRect.origin.x + highlightRect.size.width - radius,
                                        highlightRect.origin.y + highlightRect.size.height - radius, radius, pi / 2, 0.0f, 1.0f);
                        CGContextAddLineToPoint(ctx, highlightRect.origin.x + highlightRect.size.width, highlightRect.origin.y + radius);
                        CGContextAddArc(ctx, highlightRect.origin.x + highlightRect.size.width - radius, highlightRect.origin.y + radius,
                                        radius, 0.0f, -pi / 2.0f, 1.0f);
                        CGContextAddLineToPoint(ctx, highlightRect.origin.x + radius, highlightRect.origin.y);
                        CGContextAddArc(ctx, highlightRect.origin.x + radius, highlightRect.origin.y + radius, radius, 
                                        -pi / 2, pi, 1);
                        CGContextFillPath(ctx);
                    }
                }


            CTFrameDraw(self.textFrame, ctx);
            CGContextRestoreGState(ctx);
            self.renderedImage = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
                return self.renderedImage;
}

现在这是我在 Instruments 上的分配工具上得到的快照。

在此处输入图像描述

我不知道如何深入挖掘这个,但似乎图像没有被释放并保存在内存中,并且随着我滚动我拥有的 UIScrollView 并越来越多地调用此方法,它正在增加。有任何想法吗?我上面的代码有问题吗?我确实使用泄漏对其进行了分析,但没有发现泄漏的迹象...

编辑:

我添加了关于如何调用 imageForText 的代码:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
             NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
            [self parseTagsInComment];
            [self.commentsText_ setLinkColor:self.textColor_];
              [weakSelf.commentsText_ imageForText];


            UIImage *renderedImage = [weakSelf.commentsText_ imageForText];
            dispatch_async(dispatch_get_main_queue(), ^{
                [weakSelf.commentTextImageView_ setImage:renderedImage];
                [weakSelf.commentTextImageView_ setAlpha:0.0];
                [UIView animateWithDuration:0.3 animations:^{
                    [weakSelf.commentTextImageView_ setAlpha:1.0];
                }];
            });

             [pool release];
         });

我什至尝试通过这样做来调用它:

[self.commentsText_ imageForText];

然而记忆仍在飙升

4

2 回答 2

0

我们需要看看你是如何打电话imageForText来告诉的,但是你看起来像是双重保留了来自UIGraphicsGetImageFromCurrentImageContext(). 您设置self.renderedImage等于UIImagefromUIGraphicsGetImageFromCurrentImageContext()并返回图像。我假设它renderedImage是一个strong属性,所以它会保留一次。返回的图像可能设置在局部变量中或以其他方式保留在其他地方。更典型的模式是imageForText没有保留图像的副作用,如果您需要将图像保留在属性中,则按如下方式调用它:

self.renderedImage = [self imageForText];
// Do whatever you want with self.renderedImage ...

另一个潜在的问题是,当您说“在后台将文本渲染到 UIImage ”时,希望您不是指在后台线程中。UIKit 之类的函数UIGraphicsBeginImageContextWithOptions()只能从应用程序的主线程调用。

于 2012-07-29T21:38:49.917 回答
0

您应该在辅助线程中显式创建位图上下文。从后台线程使用 CoreGraphics 没有问题,但不要从辅助线程调用 UIKit 方法,这将导致非常难以调试问题。苹果文档中明确提到了一些例外情况(如 UIFont),但一般规则是不要使用 UIKit 函数,因为它们通常不工作,除非在主线程中。另外,不要调用 self.frameSize 之类的访问方法,因为这会调用 UIKit。

因为您使用的是 CoreText,所以您可能还会被此内存泄漏memory-usage-grows-with-ctfontcreatewithname-and-ctframesetterref 所困扰

于 2013-06-24T20:06:51.853 回答