2011-10-27 18 views
7

Estoy intentando construir una lista de argumentos de variable "falsa", utilizando la técnica descrita here, pero para el proyecto ARC habilitado y no puedo entender cómo obtener librarme del error que estoy recibiendoCómo convertir de char * a id * con ARC habilitado

Aquí está el código en cuestión:

NSMutableArray* argumentsArray = [NSMutableArray array]; 

// ... Here I fill argumentsArray with some elements 
// And then, I want to construct a "fake" variable argument list 

char* fakeArgList = (char*) malloc(sizeof(NSString*) * [argumentsArray count]); 
[argumentsArray getObjects: (id*) fakeArgList]; 

NSString* content = [[NSString alloc] initWithFormat: formatString arguments:fakeArgList]; 

XCode se queja sobre la ( id) fakeArgList * fundición, diciendo:

moldeada de la no-Objective-C de tipo puntero char' * 'to' _autoreleasing id * ' no está permitido con ARC

Mi teoría inicial era th simplemente necesito agregar __unsafe_unretained a (id *) casting para decirle a ARC que soy responsable de ese bloque de memoria y no debería retenerlo/liberarlo, pero eso no funciona y no puedo entender cómo para arreglar este problema

Actualización: Aquí tiene la función completa. Debería tomar una cadena de formato de estilo printf y una lista de variables de nombres dentro de .plist y generar una cadena formateada con los datos cargados desde .plist. Es decir, si tengo un archivo plist con los campos "campo1" = "foo" y "campo2" = 3 y que llamo [loadStringFromFixture: @"?param1=%@&param2=%d", @"field1", @field2] entonces yo debería conseguir cadena "? Param1 = foo & param2 = 3"

- (NSString*) loadStringFromFixture:(NSString*) format, ... 
{ 
    NSString* path = [[NSBundle mainBundle] bundlePath]; 
    NSString* finalPath = [path stringByAppendingPathComponent:@"MockAPI-Fixtures.plist"]; 
    NSDictionary* plistData = [NSDictionary dictionaryWithContentsOfFile:finalPath]; 

    va_list argumentsList;  
    va_start(argumentsList, format); 

    NSString* nextArgument; 
    NSMutableArray* argumentsArray = [NSMutableArray array]; 

    while((nextArgument = va_arg(argumentsList, NSString*))) 
    { 
     [argumentsArray addObject: [plistData objectForKey:nextArgument]]; 
    } 

    NSRange myRange = NSMakeRange(0, [argumentsArray count]); 

    id* fakeArgList = (__bridge id *)malloc(sizeof(NSString *) * [argumentsArray count]); 
    [argumentsArray getObjects:fakeArgList range:myRange]; 
    NSString * content = [[NSString alloc] initWithFormat:formatString 
               arguments:(__bridge va_list)fakeArgList]; 

    free(fakeArgList); 

    return content; 
} 
+0

Tiene que haber una mejor manera de hacer esto ... – semisight

+3

serio; Una lectura rápida del artículo fuente me hace pensar que solo funciona por coincidencia y está fuera de los límites de la ABI o especificación. – bbum

+0

Eso es cierto, pero lo necesito solo para mi código de prueba de unidad, así que estoy menos preocupado por el hecho de que es un "truco sucio". Aunque si alguien puede señalar una mejor manera de construir una lista de argumentos variables, estoy realmente interesado. –

Respuesta

1

Mirando este código, parece un truco bastante sucio, pero supongo que si funcionó sin ARC, también debería funcionar con ARC. El problema aquí es que estas lanzando desde c-punteros a punteros de Objective-C, que no se puede hacer sin que se forme:

NSMutableArray * argumentsArray = [NSMutableArray array]; 

// ... Here I fill argumentsArray with some elements 
// And then, I want to construct a "fake" variable argument list 

NSRange myRange = NSMakeRange(0, [argumentsArray count]); 
id * fakeArgList = (__bridge id *)malloc(sizeof(NSString *) * [argumentsArray count]); 
[argumentsArray getObjects:fakeArgList range:myRange]; 
NSString * content = [[NSString alloc] initWithFormat:formatString 
              arguments:(__bridge va_list)fakeArgList]; 
free(fakeArgList); 

Esto es todavía bastante feo, y realmente espero que hay una manera mejor de haciendo esto, pero dado que es para una prueba unitaria, supongo que tendrá que hacer.

EDITAR: Puede ser que el elenco puente debe hacerse esta forma:

id __autoreleasing * fakeArgList = (__bridge id __autoreleasing *)malloc(sizeof(NSString *) * [argumentsArray count]); 
+0

Todavía obtuve errores de compilación con ese código. Se queja de "Incompatible types casting" void * "to" __autoreleasing id * "con un __bridge cast" en la línea con malloc. –

+0

Actualicé mi publicación original con texto de función completo –

+0

Mi edición puede ser su solución, o puede ser totalmente inactiva. Compruébalo y mira. –