¿Cuál es la diferencia entre declarar una variable “id” y “NSObject *”?

En Objective-C, ¿cuál es la diferencia entre declarar un id variable frente a declararlo NSObject * ?

Con una id tipo variable, puede enviar cualquier mensaje conocido y el comstackdor no se quejará. Con un NSObject * tipo variable, solo puede enviar mensajes declarados por NSObject (no métodos de ninguna subclase) o bien generará una advertencia. En general, id es lo que quieres.

Explicación adicional: Todos los objetos son esencialmente de tipo id . El objective de declarar un tipo estático es decirle al comstackdor: “Supongamos que este objeto es miembro de esta clase”. Entonces, si le envía un mensaje que la clase no declara, el comstackdor puede decirle, “¡Espera, ese objeto no debe recibir ese mensaje!” Además, si dos clases tienen métodos con el mismo nombre pero diferentes firmas (es decir, argumentos o tipos de devolución), puede adivinar a qué método se refiere la clase que ha declarado para la variable. Si se declara como id , el comstackdor levantará las manos y le dirá: “OK, no tengo suficiente información aquí. Estoy escogiendo una firma de método al azar”. (Esto generalmente no será ayudado por la statement de NSObject* , sin embargo. Por lo general, el conflicto es entre dos clases más específicas.)

id significa “un objeto”, NSObject * significa “una instancia de NSObject o una de sus subclases”. Hay objetos en Objective-C que no son NSObject s (los que encontrarás en Cocoa en este momento son NSProxy , Protocol y Class ). Si algún código espera un objeto de una clase en particular, declarar que ayuda al comstackdor a verificar que lo está utilizando correctamente. Si realmente puede tomar “cualquier objeto”, por ejemplo, declara un delegado y probará todos los envíos de métodos con respondsToSelector: llamadas, puede usar una id .

Otra forma de declarar una variable de objeto es como ” id “, que significa “cualquier objeto que implemente el protocolo NSObject .

Desde mi comprensión limitada de Objective-C, no todos los objetos se derivan de NSObject (a diferencia de Java, donde todos los objetos se derivan de Object). Teóricamente puede tener otros objetos raíz. id podría aplicarse a cualquiera de esos objetos derivados no-NSObject.

Me gustaría agregar otra diferencia. Cuando agrega un protocolo a la id , ya no significa que será de tipo NSObject * , simplemente significa que será cualquier clase que confirme a ese protocolo.

Entonces, por ejemplo, este código no arrojará ningún error, ya que la categoría NSDelayedPerforming tiene ese método:

 id testId; [testId performSelector:@selector(isKindOfClass:) withObject:[NSObject class] afterDelay:.5]; 

Sin embargo, este código mostrará el error. No known instance method for selector "performSelector:withObject:afterDelay:" :

 id testId; [testId performSelector:@selector(isKindOfClass:) withObject:[NSObject class] afterDelay:.5];