¿Pueden los nuevos literales de Clang Objective-C redirigirse a clases personalizadas?

Aunque la sobrecarga de @ comienza a pisar territorio peligroso, me encanta la adición de los nuevos literales de Objective-C en Clang 3.1. Lamentablemente, los nuevos literales son de uso limitado para mí. Excepto en los casos en los que el código necesita interactuar con AppKit, he descartado el uso de las clases Foundation a favor de mi propio framework personalizado (por una variedad de razones, la mayoría de las cuales es que necesito control directo sobre los patrones de asignación de memoria utilizados por objetos).

Siempre podría usar algunos trucos de tiempo de ejecución para pasar el objeto recién creado como mi clase personalizada (y es lo que ya tengo que hacer con los literales de objeto de cadena, ya que solo el tiempo de ejecución GCC que no sea de Apple admite el -fconstantstring=class ), pero esto es un truco en el mejor de los casos y arroja todos los beneficios que obtuve al reemplazar la clase Foundation equivalente para empezar.

A diferencia de los literales de objeto de cadena, los nuevos lenguajes Los implementos de Clang no son realmente clases constantes (donde el diseño de la memoria está codificado); en su lugar, los mensajes apropiados se envían a sus respectivas clases para crear e inicializar un nuevo objeto en tiempo de ejecución. El efecto no es diferente de si tú mismo hubieras creado el objeto. En teoría, significa que las clases utilizadas y los métodos llamados por los nuevos literales no están codificados. En la práctica, no encuentro ninguna forma de cambiarlos para apuntar a mis propias clases y métodos personalizados (de hecho, me alegraría simplemente apuntar a una clase personalizada; señalar un método ficticio a un método real en el tiempo de ejecución no es difícil )

Cuando analicé esto por primera vez, realmente esperaba encontrar un conjunto de indicadores que pudieran usarse para hacer lo que estoy pidiendo, pero como no he encontrado ninguno, espero que alguien tenga una solución.

Puede sustituir clase por algunos literales Objective-C con el truco de palabra clave @compatibility_alias .

Aquí hay un ejemplo.

 @compatibility_alias NSNumber AAA; 

Por supuesto, debe proporcionar la implementación adecuada para la nueva clase.

 #import  @interface AAA : NSObject + (id)numberWithInt:(int)num; @end @implementation AAA + (id)numberWithInt:(int)num { return @"AAAAA!!!"; // Abused type system just to check result. } @end @compatibility_alias NSNumber AAA; 

Ahora Clang hará el trabajo por usted. Confirmé que esto funciona para números, matrices, literales de diccionarios. Lamentablemente, los literales de cadena parecen emitirse estáticamente, por lo que no funcionará.

Para obtener más información sobre la palabra clave @compatibility_alias , consulte aquí .

Nota

Como la palabra clave @compatibility_alias es una directiva de comstackción que se aplica a la unidad de comstackción actual, debe separar la unidad de comstackción para evitar la duplicación de símbolos con la clase NSObject en el Kit Foundation de Apple. Así es como lo hice.

main.m

 #import "test.h" // Comes before Foundation Kit. #import  int main(int argc, const char * argv[]) { @autoreleasepool { NSLog(@"return of test = %@", test()); // insert code here... NSLog(@"Hello, World!"); } return 0; } 

test.h

 id test(); 

test.m

 #import "test.h" #import  @interface AAA : NSObject + (id)numberWithInt:(int)v; + (id)arrayWithObjects:(id*)pobj count:(int)c; + (id)dictionaryWithObjects:(id*)pvals forKeys:(id*)pkeys count:(int)c; @end @implementation AAA + (id)numberWithInt:(int)v { return @"AAAAA as number!!!"; } + (id)arrayWithObjects:(id*)pobj count:(int)c { return @"AAAAA as array!!!"; } + (id)dictionaryWithObjects:(id*)pvals forKeys:(id*)pkeys count:(int)c { return @"AAAAA as dictionary!!!"; } @end @compatibility_alias NSDictionary AAA; @compatibility_alias NSArray AAA; @compatibility_alias NSNumber AAA; id test() { // return @{}; // return @[]; return @55; } 

Resultado.

 2013-03-23 08:54:42.793 return of test = AAAAA!!! 2013-03-23 08:54:42.796 Hello, World! 

Los comentarios tienen todo correcto, pero solo para resumir:

  • No.

Los significados de los literales @{} , @[] y @"" de Apple están codificados en Clang. Puedes verlo aquí: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/NSAPI.cpp?view=markup Todo es bastante modular, lo que significa que no sería difícil para un Clang hacker para agregar su propia syntax literal … pero “modular” no significa “accesible desde el exterior”. Agregar una nueva syntax o incluso redirigir la syntax existente a nuevas clases definitivamente requeriría reconstruir Clang usted mismo.

Aquí hay una publicación en el blog sobre cómo agregar literales NSURL a Clang mediante la piratería en sus partes internas: http://www.stuartcarnie.com/2012/06/llvm-clang-hacking-part-3.html (Gracias @Josh Caswell)


Si está dispuesto a usar Objective-C ++ con extensiones C ++ 11, puede tener “literales definidos por el usuario”, que le permiten escribir cosas como

 NSURL *operator ""URL (const char *s) { return [NSURL URLWithString: @(s)]; } int main() { ... NSURL *myurl = "ftp://foo"URL; ... } 

Esto fue mencionado en los comentarios en el blog de Mike Ash. http://www.mikeash.com/pyblog/friday-qa-2012-06-22-objective-c-literals.html Pero esto no se ve muy Objective-C-ish (o muy C ++ ish!) , y funciona solo con un comstackdor Objective-C ++ 11, y en general no lo hagas. 🙂