memory management for CTRunDelegateRef iPhone

2020-06-29 02:20发布

问题:

I focus on a project to add image support based on OmniGroup's rtf editor.I met the problem when I use CTFramesetterCreateWithAttributedString, and it receives

EXC_BAD_ACCESS

which is caused by a zombie object.

For simplicity, I get the NSAttributedString from a rtfd file which only has a photo. I add the method to parser the image tag on iOS based on the Omni's sample. And the part to create the NSAttributedString is followed by this tutorial from raywenderlich, and looks like:


    CTRunDelegateCallbacks callbacks;
    callbacks.version = kCTRunDelegateCurrentVersion;
    callbacks.getAscent = ascentCallback;
    callbacks.getDescent = descentCallback;
    callbacks.getWidth = widthCallback;
    callbacks.dealloc = deallocCallback;
    CTRunDelegateRef delegate = CTRunDelegateCreate(&callbacks, imgAttr); 

    NSDictionary *imgAttr = [NSDictionary dictionaryWithObjectsAndKeys:imgWidth,kImageWidth,imgHeight,kImageHeight, nil];//recored the width and height
    NSDictionary *attrDictionaryDelegate = [NSDictionary dictionaryWithObjectsAndKeys:(id)delegate, (NSString*)kCTRunDelegateAttributeName,nil];
     [_attributedString appendString:@" " attributes:attrDictionaryDelegate];
     CFRelease(delegate);

here appendString:attributes: is provided by Omni and is a category for NSMutableAttributedString:


- (void)appendString:(NSString *)string attributes:(NSDictionary *)attributes;
{
    NSAttributedString *append;

    append = [[NSAttributedString alloc] initWithString:string attributes:attributes];
    [self appendAttributedString:append];
    [append release];
}

In the Parser class I test CTFramesetterCreateWithAttributedString and it creates successfully and no memory problem happens. However, when I call CTFramesetterCreateWithAttributedString in my view class, it receives the EXC_BAD_ACESS problem. I send the CTFramesetterCreateWithAttributedString to my view in the viewDidLoad:


NSArray *arr = [OUIRTFReader parseRTFString2:rtfString];
self.editFrame.attributedText = [arr objectAtIndex:0];


//for OUIRTFReader
+ (NSArray *)parseRTFString2:(NSString *)rtfString
{
    OUIRTFReader *parser = [[self alloc] _initWithRTFString:rtfString];
    NSMutableArray *temp  = [NSMutableArray arrayWithCapacity:1];
    NSAttributedString *tempAstr = [[NSAttributedString alloc] initWithAttributedString:parser.attributedString];

    [temp addObject:tempAstr];
    [tempAstr release];
    if (parser.zjImageArray) {
        [temp addObject:parser.zjImageArray];
    }

    [parser release];
}

here editFrame is ivar of OUIEditableFrame provided by OmniFramework. After that, in the layoutSubview: of OUIEditableFrame, CTFramesetterCreateWithAttributedString failed. Profiling with instrument, it points there is a zombie object in :


NSDictionary *imgAttr = [NSDictionary dictionaryWithObjectsAndKeys:imgWidth,kImageWidth,imgHeight,kImageHeight, nil];

It demonstrates that

An Objective-C message was sent to a deallocated object(zombie) at address

I'm not so familiar with core foundation like as UIKit or others. So I'd like to know what's wrong with the method to create a attributed string for image with CTRunDelegateRef in my code?

Thanks!

回答1:

CTRunDelegateCreate create a delegate with an arbitrary context pointer (void *). That means the dictionary imgAttr isn't retained by the delegate.

You need to retain the context dictionary when creating the delegate and release it in the dealloc callback.