Entiendo que marca el final de un conjunto de varargs, pero ¿por qué no se puede implementar de tal manera que no requiera el nil?¿Por qué NSArray arrayWithObjects requiere un nulo de terminación?
Respuesta
Todo tiene que ver con la C llamando a ABI.
Considere estos métodos:
- (id)initWithFormat:(NSString *)format, ...;
+ (id)arrayWithObjects:(id)firstObj, ...;
+ (id)dictionaryWithObjectsAndKeys:(id)firstObject, ...;
El ...
indica al compilador que un número variable de argumentos de cualquier tipo puede estar presente. No hay forma de que el compilador sepa qué tipo de estos deben ser (las definiciones reales tienen marcadores que ayudan con eso).
Ahora, considere los tres métodos. Los tres tienen requisitos muy diferentes para lo que podría estar presente en la lista de argumentos variables. Una matriz debe ser un grupo de objetos seguido de un nil. El diccionario requiere un grupo de pares de objetos seguidos de un nil. Finalmente, el método de cadena requiere un grupo de argumentos que coincidan con los tipos en la cadena de formato.
Todos estos comportamientos están directamente relacionados con el método invocado y, si el autor de una API decidió usar "difícil de usar", el comportamiento de decodificación de los argumentos variables podría modificarse en tiempo de ejecución, solo para hacer vida difícil
En pocas palabras: El C ABI no tiene una sintaxis que permita especificar que un método o función toma un número variable de argumentos con cualquier tipo de conjunto de restricciones sobre los argumentos o su terminación.
Objective-C podría cambiar las reglas solo para declaraciones de métodos & invocaciones, pero eso no ayudaría con las funciones C o C++, las cuales Objective-C debe seguir siendo compatible.
Cualquier función varargs requiere de alguna manera saber cuántos parámetros están presentes; si no termina, solo necesitaría algo más. En este caso, la alternativa obvia es la longitud, pero luego deberá actualizar el argumento de longitud cada vez que cambie la cantidad de elementos en la matriz, y eso podría ser engorroso o incluso peor.
Supongo que tiene una matriz que puede contener nil?
NSArray no puede contener nada; debe usar NSNull para representarlo. Supongo que solo le han picado los molestos errores que pueden surgir al olvidar el terminador nulo. – Chuck
No es tanto ser pequeño olvidando el terminador nil, es solo que estoy acostumbrado a otros lenguajes como Java y Ruby que permiten varargs sin un terminador nulo. Tal vez lo que estoy preguntando es por qué Obj-C requiere un terminador nil para varargs? ¿Por qué no puede el compilador simplemente "hacer lo correcto" para [NSArray arrayWithObjects: @ "foo", @ "bar"]? Mi pregunta es más una cuestión de curiosidad sobre por qué el lenguaje requiere esto. Es una verruga obvia cuando proviene de otros idiomas. Es así porque así es como varargs en C funciones? – pjb3
I _believe_ object-c varargs se crean en las variables estándar de C que no superan recuentos de argumentos. Posiblemente obj-c podría haberlo hecho en su implementación original, pero ahora está obligado por la compatibilidad ABI. – olliej
@bbum proporciona algunos detalles técnicos geniales. Aquí hay algunas ideas sobre la práctica "¿por qué no lo arreglan?"
Recuerde: C es solo ensamblador y Obj-C es solo C ... Podría ser rediseñado, por supuesto, pero casi no hay presión para hacerlo. Aún no puedes poner nil en una matriz (eso requeriría un gran cambio). El compilador ahora te advierte si olvidas el nil, por lo que no es algo de lo que los desarrolladores se quejan mucho. La compensación es mantener el lenguaje mucho (¡mucho!) Más simple que su pariente, obteniendo los beneficios de décadas de optimizaciones del compilador C y compatibilidad garantizada con el código C.
Una cosa que debería quedar clara en la discusión de @ bbum: NSArray no es una función de lenguaje de Objective-C. Las matrices C son una función de idioma, pero las NSArrays son solo otro objeto, no diferente de los objetos que se escriben.
Existen varias soluciones, pero mi favorito actual es bueno para aplicaciones más que para frameworks lanzados. Acepte un NSArray en su método en lugar de "...", y luego llénelo con la macro de conveniencia a continuación, que se coloca en su archivo de prefijo o en el encabezado de la herramienta.
#define $ array (objs ...) [NSArray arrayWithObjects: objs, nil]
Permitirá múltiples argumentos de longitud variable bien etiquetados y se liberará del patrón arcaico de tener que usar el primer argumento y luego va_list y sus hermanos a favor de un bucle for-in o las muchas otras herramientas de recolección disponibles.
[self findMatchingSetAndAlert: @ "title" lazos: $ array (tie1, tie2, tie3) camisetas: $ array (shirt1, shirt2, shirt3, shirt4)];
Si alguien sabe cómo implementar una lista no delimitada por nulos, como stringWithFormat, ¡por favor háganoslo saber! Utiliza atributos y macros o algo diseñado específicamente para el formateo, pero esos se implementan de alguna manera.
Mi respuesta es bastante antigua y las macros ya no son necesarias como una muleta. La sintaxis moderna de Objective C ayuda mucho, ya que ahora puedes crear una matriz como '@ [@" firstString ", @" secondString "]'. Ahora podemos preocuparnos por los tipos en lugar de la ceremonia de sintaxis. –
Puede usar ahora la nueva Colección Literals (alias Container Literals) en Objective-C. Ver http://clang.llvm.org/docs/ObjectiveCLiterals.html
- 1. Hazte un método como - [NSArray arrayWithObjects:]; parámetros infinitos separed por finalizados, por nula sobre el argumento
- 2. ¿Por qué Scanf requiere &?
- 3. ¿Por qué se requiere un vector?
- 4. ¿Por qué esta consulta requiere un parámetro?
- 5. CGGradientCreateWithColors devuelve un puntero nulo
- 6. ¿Por qué C no termina cadenas con un carácter especial de terminación de cadena escapada?
- 7. ¿Por qué PreparedStatement.setNull requiere sqlType?
- 8. comprueba el carácter de terminación nulo en char *
- 9. ¿Por qué SelectSingleNode devuelve nulo?
- 10. ¿Por qué Assembly.GetExecutingAssembly() devolverá nulo?
- 11. ¿Por qué BitmapFactory.decodeByteArray devuelve nulo?
- 12. ¿Por qué verificar esto? = Nulo?
- 13. ¿Por qué HttpContext.Current.Handler es nulo?
- 14. ¿Por qué chrome.extension.getBackgroundPage() devuelve nulo?
- 15. ¿Por qué un Fortran POINTER requiere un OBJETIVO?
- 16. por qué Files.probeContentType devuelve nulo
- 17. Java: ¿por qué imprime nulo?
- 18. ¿Por qué Bitmap.getConfig() devuelve nulo?
- 19. ¿Por qué document.GetElementById devuelve nulo
- 20. ¿Por qué SynchronizationContext.Current es nulo?
- 21. ¿Por qué se requiere copy_to/from_user?
- 22. ¿Por qué ofstream requiere una descarga?
- 23. ¿Por qué log4net 1.2.10 requiere System.Web?
- 24. ¿Por qué C# requiere parens en condicionales?
- 25. ¿Cómo recuperar un índice de un NSArray utilizando un NSPredicate?
- 26. ¿Es posible filtrar un NSArray por clase?
- 27. Obtener un NSArray de un solo atributo de un NSArray
- 28. ¿Por qué se requiere $ root aquí?
- 29. ¿Por qué sendTextMessage requiere el permiso READ_PHONE_STATE?
- 30. ¿Por qué la clase MailDefinition requiere un System.Web.UI.Control?
Parece que el compilador podría agregar transparentemente un nil final a [matriz NSArrayWithObjects: a, b, c]. Eso dejaría un problema que no se permitiría como argumento. Incluso podríamos hacer esto ahora. Las personas que ya incluyen el nil obtendrían [NSArray arrayWithObjects: a, b, c, nil, nil], lo que creo que no es fatal. – Ken
Ken, colocando casos especiales en el compilador para clases particulares como NSArray abre una enorme lata de gusanos. ¿Qué pasa si subclasifica a NSArray? – NSResponder
@Ken: no se puede agregar 'nil' a' NSArray' de todos modos (en su lugar, tiene que usar 'NSNull'). – mipadi