2010-06-06 5 views
3

Je reçois une erreur EXC_BAD_ACCESS exaspérante dans une application c objective sur laquelle je travaille. Toute aide que vous pourriez offrir serait très appréciée. J'ai essayé les méthodes de débogage normales pour cette erreur (en activant NSZombieEnabled, en vérifiant retain/release/autorelease pour m'assurer que je n'essaye pas d'accéder à un objet désalloué, etc.) et cela n'a pas semblé aider.EXC_BAD_ACCESS dans CFAttributedStringSetAttribute et NSNumber?

En fait, l'erreur se produit toujours dans cette fonction:

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]; 


} 

Le programme se bloque toujours à cause de la ligne

CFAttributedStringSetAttribute(attString, CFRangeMake([[kernLoc objectAtIndex:0] intValue], 1), kCTKernAttributeName, (CFNumberRef)[kernLoc objectAtIndex:1]) 

Et il semble dépendre d'un certain nombre de choses:

  1. si [kernLoc objectAtIndex: 1] fait référence à un [NSNumber numberWithFloat: k] où k = 0 (dans d'autres ds, si k = 0 ci-dessus où je peuple kernArray) puis le programme se bloque presque immédiatement

  2. Si je commente la ligne k = k + kKern, il faut plus de temps pour que le programme plante, mais finalement (pourquoi le crash dépend de cette valeur?)

  3. Si je change la longueur de CFRangeMake de 1 à 0, il faut beaucoup plus de temps pour que le programme plante, mais le fait finalement. (Je ne pense pas que je suis en train d'accéder au-delà des limites de attString, mais que je manque quelque chose?)

Quand il tombe en panne, je reçois quelque chose de similaire à:

#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 

Toutes les idées ? Il semble que quelque part sur le chemin j'efface la mémoire ou essaie d'accéder à la mémoire qui a été changée, mais je n'en ai aucune idée. S'il y a plus d'informations que je peux fournir, s'il vous plaît faites le moi savoir.

Merci, Richard

Répondre

4

Votre accident ressemble le résultat d'une part sur la libération. Il est difficile de savoir quel pourrait être le problème, en particulier lorsque vous mélangez les fondations avec Cocoa. Les règles de gestion de la mémoire sont différentes pour la base de base.

Je pense que je tirerais toutes les références à des données sur CFAttributedStringSetAttribute pour que je puisse les NSLog ou les inspecter avec le débogueur, comme ceci:

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) 
+0

Salut JeremyP, merci pour la suggestion. J'ai essayé ceci et ai trouvé que toutes les valeurs étaient correctes avant d'aller dans CFAttributedStringSetAttribute (et la gamme est w/n bornes). J'ai expérimenté avec des valeurs et trouvé qu'un crash dépend de la valeur de attrValue ET si attrValue = tkern (l'autre valeur de kern déjà appliquée) le programme se bloque. J'ai créé un programme de test simple avec un CFMutableAttributedString, j'ai essayé d'écraser le même attribut avec la même valeur, et il s'est écrasé! Je ne veux pas être présomptueux à propos de mes compétences de codage, mais cela semble être un bug dans la fonction d'Apple. Cela pourrait-il être le cas? – RichardR

+0

Quand vous dites «la même valeur» voulez-vous dire le même CFNumberRef? OU un nombre différent ref avec la même valeur? Il semblerait que l'ancien attrValue soit publié * avant * d'être remplacé par le nouvel attrValue, ce qui pourrait être un désastre s'il s'agissait du même objet. Donc, cela ressemble certainement à un bug, mais cela pourrait signifier que nous avons tous les deux manqué quelque chose. – JeremyP

+0

Essayez d'associer l'appel à CFAttributedStringSetAttribute avec un appel à CFRetain sur la valeur de l'attribut avant l'appel et un appel à CFRelease sur la valeur de l'attribut après l'appel. – JeremyP

2

Suivi - il semble que CFAttributedStringSetAttributes (pluriel) est le chemin à parcourir. J'ai encore besoin de l'implémenter dans mon programme, mais dans un petit test, cette fonction me permet d'écraser les valeurs précédemment définies sans provoquer un crash EXC_BAD_ACCESS. Cela aurait été bien si cela a été documenté quelque part. J'espère que cela aide d'autres personnes. Merci!

+0

Merci pour cette mise à jour - qui a résolu le problème pour moi aussi. –