CFAttributedStringSetAttribute和NSNumber中的EXC_BAD_ACCESS?

时间:2010-06-06 18:33:56

标签: iphone objective-c exc-bad-access

我正在处理的目标c应用中遇到令人愤怒的EXC_BAD_ACCESS错误。您可以提供的任何帮助将非常感谢。我已经尝试了这个错误的正常调试方法(打开NSZombieEnabled,检查retain / release / autorelease以确保我没有尝试访问一个解除分配的对象等)并且它似乎没有帮助。

基本上,错误总是发生在这个函数中:

void op_TJ(CGPDFScannerRef scanner, void *info)
{
    PDFPage *self = info;
    CGPDFArrayRef array;

    NSMutableString *tempString = [NSMutableString stringWithCapacity:1];
    NSMutableArray *kernArray = [[NSMutableArray alloc] initWithCapacity:1];

    if(!CGPDFScannerPopArray(scanner, &array)) {
        [kernArray release];
        return;
    }

    for(size_t n = 0; n < CGPDFArrayGetCount(array); n += 2)
    {
        if(n >= CGPDFArrayGetCount(array))
            continue;

        CGPDFStringRef pdfString;

        // if we get a PDF string
        if (CGPDFArrayGetString(array, n, &pdfString))
        {
            //get the actual string
            const unsigned char *charstring = CGPDFStringGetBytePtr(pdfString);

            //add this string to our temp string
            [tempString appendString:[NSString stringWithCString:(const    char*)charstring encoding:[self pageEncoding]]];
            //NSLog(@"string: %@", tempString);

            //get the space after this string
            CGPDFReal r = 0;
            if (n+1 < CGPDFArrayGetCount(array)) {
                CGPDFArrayGetNumber(array, n+1, &r);

                // multiply by the font size
                CGFloat k = r;
                k = -k/1000 * self.tmatrix.a * self.fontSize;


                CGFloat kKern = self.kern * self.tmatrix.a;
                k = k + kKern;

                // add the location and kern to the array
                NSNumber *tempKern = [NSNumber numberWithFloat:k];
                NSLog(@"tempKern address: %p", tempKern);
                [kernArray addObject:[NSArray arrayWithObjects:[NSNumber numberWithInt:[tempString length] - 1], tempKern, nil]];

            }
        }
    }

    // create an attribute string
    CFMutableAttributedStringRef attString =    CFAttributedStringCreateMutable(kCFAllocatorDefault, 10);

    CFAttributedStringReplaceString(attString, CFRangeMake(0, 0), (CFStringRef)tempString);

    //apply overall kerning
    NSNumber *tkern = [NSNumber numberWithFloat:self.kern * self.tmatrix.a * self.fontSize];
    CFAttributedStringSetAttribute(attString, CFRangeMake(0, CFAttributedStringGetLength(attString)), kCTKernAttributeName, (CFNumberRef)tkern);

    //apply individual kern attributes
    for (NSArray *kernLoc in kernArray) {
        NSLog(@"kern location: %i, %i", [[kernLoc objectAtIndex:0] intValue],[[kernLoc objectAtIndex:1] floatValue]);
        CFAttributedStringSetAttribute(attString, CFRangeMake([[kernLoc objectAtIndex:0] intValue], 1), kCTKernAttributeName, (CFNumberRef)[kernLoc objectAtIndex:1]);
    }

    CFAttributedStringReplaceAttributedString([self cfAttString], CFRangeMake(CFAttributedStringGetLength([self cfAttString]), 0), attString);

    //release
    CFRelease(attString);
    [kernArray release];


}

由于行

,程序总是崩溃
CFAttributedStringSetAttribute(attString, CFRangeMake([[kernLoc objectAtIndex:0] intValue], 1), kCTKernAttributeName, (CFNumberRef)[kernLoc objectAtIndex:1])

它似乎取决于一些事情:

  1. 如果[kernLoc objectAtIndex:1]引用[NSNumber numberWithFloat:k],其中k = 0(换句话说,如果k = 0高于我填充kernArray的位置)那么程序几乎立即崩溃

  2. 如果我注释掉行k = k + kKern,那么程序崩溃需要更长的时间,但最终会崩溃(为什么崩溃会依赖于这个值?)

  3. 如果我将CFRangeMake的长度从1更改为0,程序崩溃需要更长的时间,但最终仍然会发生。 (我不认为我试图访问超出attString的范围,但我错过了什么?)

  4. 当它崩溃时,我会得到类似的东西:

    #0  0x942c7ed7 in objc_msgSend ()
    #1  0x00000013 in ?? ()
    #2  0x0285b827 in CFAttributedStringSetAttribute ()
    #3  0x0000568f in op_TJ (scanner=0x472a590, info=0x4a32320) at /Users/Richard/Desktop/AppTest/PDFHighlight 2/PDFScannerOperators.m:251
    

    有什么想法吗?这似乎是我覆盖内存或尝试访问已更改的内存的方式,但我不知道。如果我能提供更多信息,请告诉我。

    谢谢, 理查德

2 个答案:

答案 0 :(得分:4)

你的崩溃看起来像某个地方过度释放的结果。很难找出问题所在,尤其是当您将核心基础与Cocoa混合时。核心基础的内存管理规则不同。

我想我会从CFAttributedStringSetAttribute中提取所有对数据的引用,以便我可以使用调试器对它们进行NSLog或检查,如下所示:

NSNumber* rangeStart = [kernLoc objectAtIndex:0];      // Debug: make sure it is a number
NSNumber attrValue = [kernLoc objectAtIndex:1];        // Debug: make sure it is a number
CFRange range = CFRangeMake([rangeStart intValue], 1); // Debug: make sure it is a valid range for the string
CFAttributedStringSetAttribute(attString, range, kCTKernAttributeName, (CFNumberRef)attrValue)

答案 1 :(得分:2)

跟进 - 似乎CFAttributedStringSetAttributes(复数)是要走的路。我仍然需要将它实现到我的程序中,但是在一个小测试中,这个函数允许我覆盖以前定义的值而不会导致EXC_BAD_ACCESS崩溃。如果在某处记录下来本来会很好。希望这有助于其他人。谢谢!