Objective-C (lenguaje de programación): ¿Cómo explica la estructura de argumento impar de NSStringWithFormat, en la que se proporcionan más argumentos después de una coma?

+ stringWithFormat: es un método variadic en lugar de simplemente tomar una matriz de valores para interpolar en la cadena por varias razones.

Objective-C, como su nombre lo indica, es un superconjunto de C y coexiste con el entorno tradicional de C, incluida la biblioteca estándar de C. Esa biblioteca incluye la venerable familia de funciones printf, cada una de las cuales toma una cadena de formato y una lista variada de argumentos e interpola la cadena con los argumentos para algún efecto. Sin duda, se esperaba familiaridad con printf, ya que + stringWithFormat: no solo toma argumentos similares, sino que también admite todos los especificadores de formato en la cadena que admite printf, al tiempo que agrega% @ para indicar que el argumento es un objeto.

Esto sugiere una razón técnica para usar un método variadic en lugar de una matriz: la necesidad de agregar un especificador de formato específicamente para objetos implica que no todos los tipos son iguales a los ojos del manejo de cadenas de formato. De hecho, una de las cosas extrañas y maravillosas que puede hacer en los lenguajes de la familia C es tomar una región de memoria que aparentemente sea un valor de un tipo e interpretarla como si fuera un valor de otro tipo. Puede hacer esto, por ejemplo, utilizando el especificador de formato para un entero pero pasando un flotante: et voila, así es como se ven los flotantes IEEE debajo.

Pero si especifica un objeto y pasa un flotante, se bloquea: objc_msgSend requiere más que solo los 32 bits para que se mantengan sus contratos. Entonces, ¡lo que se pasa como un objeto debería ser un objeto!

Entonces, si puede pasar casi cualquier tipo antiguo al método e interpretar de acuerdo con la cadena de formato, realmente necesita variables. No puede colocar un flotador en un NSArray sin encajonarlo en un NSNumber u otro objeto primero, y eso plantea todo tipo de otras preguntas: ¿cómo haría + stringWithFormat: comunicar el especificador de formato al objeto? Normalmente solo llama a -description. ¿Es razonable que el argumento tenga algo que decir sobre cómo se formatea? ¿Deberíamos simplemente pedirle que se desempaquete y esperar lo mejor? Si está cambiando tanto, ¿por qué usar una cadena de formato? ¿Por qué no algo como el bigote para las cadenas de plantillas?

Obviamente, es cierto que si puede pasar los argumentos al método y hacer que funcione, podría hacer algún tipo de matriz que pueda almacenar muchos tipos. Pero resulta que esto es mucho trabajo y puede confundir a los usuarios que esperan el tipo típico de NSArray; Además, se trata básicamente de un gran esfuerzo para reemplazar las variables, que, como resultado, ya puedes reunir en una estructura (suponiendo que te llamaron con los argumentos que deseas recopilar) y pasar a otros métodos. Esta es la razón por la cual existe el método -initWithFormat: argumentos:: para que pueda construir sus propios métodos de cadena de formato y hacer instancias de NSString con los argumentos con los que fue llamado.

Esta es, en última instancia, una de esas partes divertidas del lenguaje donde resulta que la forma obvia, clara y sensata de hacer algo es mucho menos obvia, clara o sensata cuando la historia (o menos importante, si eres menos indulgente) ) de la lengua se tiene en cuenta. Pero aquí hay una oportunidad divertida para experimentar: ¿cómo implementaría un + stringWithFormat: –método de prueba que toma una matriz y admite todo lo que admite el original? ¿Qué desafíos enfrenta al hacerlo? ¿Es el resultado tan fácil de usar? ¿Mas de? No hay nada que le dé más empatía por un desarrollador de API que caminar una milla dentro de sus limitaciones de implementación estrechamente vinculadas.