Estoy tratando de reducir un error a un caso reproducible mínimo y encontré algo extraño.¿Por qué no se cuelga?
consideran este código:
static NSString *staticString = nil;
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
if (staticString == nil) {
staticString = [[NSArray arrayWithObjects:@"1", @"2", @"3", nil] componentsJoinedByString:@","];
}
[pool drain];
NSLog(@"static: %@", staticString);
return 0;
}
estoy esperando este código se bloquee. En su lugar, registra:
2011-01-18 14:41:06.311 EmptyFoundation[61419:a0f] static: static:
Sin embargo, si cambio el NSLog()
a:
NSLog(@"static: %s", [staticString UTF8String]);
Entonces se hace accidente.
edición un poco más de información:
Después de vaciar la piscina:
NSLog(@"static: %@", staticString); //this logs "static: static: "
NSLog(@"static: %@", [staticString description]); //this crashes
Así que al parecer la invocación de un método en la cadena es lo suficientemente bueno para conseguir que se bloquee. En ese caso, ¿por qué el registro de la cadena no causa directamente que se bloquee? ¿No debería NSLog()
invocar el método -description
?
¿De dónde viene el segundo "estático:"? ¿Por qué no se está cayendo?
Resultados:
Tanto Kevin Ballard y Graham Lee son correctos. Graham está en lo cierto al darse cuenta de que NSLog()
es y no invocando -description
(como estaba asumiendo erróneamente), y Kevin está casi seguro de que este es un problema extraño relacionado con la pila al copiar una cadena de formato y un va_list
.
NSLogging
yNSString
no invoca-description
. Graham mostró esto con elegancia, y si rastreas a través de las fuentes de Core Foundation que hacen el registro, verás que este es el caso. Cualquier traza inversa originada dentro deNSLog
muestra que invocaNSLogv
=>_CFLogvEx
=>_CFStringCreateWithFormatAndArgumentsAux
=>_CFStringAppendFormatAndArgumentsAux
._CFStringAppendFormatAndArgumentsAux()
(línea 5365) es donde se desarrolla toda la magia. Puede ver que está pasando por el poder para encontrar todas las sustituciones%
. Solo termina invocando la función de copia de descripción si el tipo de la sustitución esCFFormatObjectType
, la función de descripción no es nula y la sustitución no ha sido manejada ya por otro tipo. Como hemos demostrado que la descripción no se está copiando, es razonable suponer que unNSString
se maneja antes (en cuyo caso probablemente se trate de una copia de bytes sin formato), lo que nos lleva a creer ...- Aquí hay un error de acumulación, como Kevin conjetura. De alguna manera, el puntero que era apuntando a la cadena autorretratada se sustituye por un objeto diferente, que sucede como
NSString
. Por lo tanto, no se cuelga. Extraño. Sin embargo, si cambiamos el tipo de la variable estática a otra cosa, como unNSArray
, se llama al método-description
y el programa se bloquea como se esperaba.
Qué tan verdaderamente extraño. Los puntos van a Kevin por ser el más correcto sobre la raíz causa del comportamiento, y felicitaciones a Graham por corregir mi pensamiento erróneo. Desearía poder aceptar dos respuestas ...
¿Por qué esperas que se cuelgue? – Davidann
'NSLog ([cadena NSStringWithFormat: @" static:% @ ", staticString])' __doses__ causa un bloqueo, por lo que es realmente debido a un comportamiento diferente de 'NSLog' al manejar'% @ ' – Joost
Nitpicks: creo que su análisis wrt/"Results:" & '_CFStringAppendFormatAndArgumentsAux' es incorrecto. Para cada '% @', '_CFStringAppendFormatAndArgumentsAux' intentará 1) una función' copyDesc' que se pasó a través de un argumento, 2) '__CFCopyFormattingDescription', que para los objetos ObjC resulta en intentar' _copyFormattingDescription: ', y finalmente 3)' CFCopyDescription', que para los objetos ObjC da como resultado '_copyDescription', y el desmontaje muestra 'NSObject' defaults a llamar' -description'. Por lo tanto, el 99% del tiempo, '% @' dará como resultado que se llame a '-description'. – johne