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:
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
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?)
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
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
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
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