Objective-C

Compartir Imprimir Citar

Objective-C es un lenguaje de programación orientado a objetos de propósito general que agrega mensajes de estilo Smalltalk al lenguaje de programación C. Desarrollado originalmente por Brad Cox y Tom Love a principios de la década de 1980, fue seleccionado por NeXT para su sistema operativo NeXTSTEP. Objective-C era el lenguaje de programación estándar admitido por Apple para desarrollar aplicaciones macOS (que descienden de NeXTSTEP) e iOS utilizando sus respectivas interfaces de programación de aplicaciones (API), Cocoa y Cocoa Touch, hasta la introducción de Swift en 2014.

Los programas Objective-C desarrollados para sistemas operativos que no son de Apple o que no dependen de las API de Apple también se pueden compilar para cualquier plataforma compatible con GNU GCC o LLVM/Clang.

Los archivos de programa de 'mensajería/implementación' del código fuente de Objective-C generalmente tienen extensiones de nombre de archivo.m, mientras que los archivos de 'encabezado/interfaz' de Objective-C tienen extensiones.h, al igual que los archivos de encabezado C. Los archivos Objective-C++ se indican con una extensión de archivo.mm.

Historia

Objective-C fue creado principalmente por Brad Cox y Tom Love a principios de la década de 1980 en su empresa Productivity Products International (PPI).

Antes de la creación de su empresa, ambos conocieron Smalltalk mientras estaban en el Centro de Tecnología de Programación de ITT Corporation en 1981. El primer trabajo en Objective-C se remonta a esa época. Cox estaba intrigado por los problemas de la verdadera reutilización en el diseño y la programación de software. Se dio cuenta de que un lenguaje como Smalltalk sería invaluable en la creación de entornos de desarrollo para desarrolladores de sistemas en ITT. Sin embargo, él y Tom Love también reconocieron que la compatibilidad con versiones anteriores de C era de vital importancia en el entorno de ingeniería de telecomunicaciones de ITT.

Cox comenzó a escribir un preprocesador para C para agregar algunas de las capacidades de Smalltalk. Pronto tuvo una implementación funcional de una extensión orientada a objetos del lenguaje C, a la que llamó "OOPC" por Object-Oriented Pre-Compiler. Love fue contratado por Schlumberger Research en 1982 y tuvo la oportunidad de adquirir la primera copia comercial de Smalltalk-80, lo que influyó aún más en el desarrollo de su creación. Para demostrar que se podía hacer un progreso real, Cox demostró que hacer componentes de software intercambiables realmente solo necesitaba unos pocos cambios prácticos en las herramientas existentes. Específicamente, necesitaban admitir objetos de manera flexible, suministrarse con un conjunto utilizable de bibliotecas y permitir que el código (y los recursos que necesita el código) se empaqueten en un formato multiplataforma.

Love y Cox finalmente formaron PPI para comercializar su producto, que combinó un compilador Objective-C con bibliotecas de clases. En 1986, Cox publicó la descripción principal de Objective-C en su forma original en el libro Programación orientada a objetos, un enfoque evolutivo. Aunque tuvo cuidado de señalar que hay más en el problema de la reutilización que solo lo que proporciona Objective-C, el lenguaje a menudo se compara característica por característica con otros lenguajes.

Popularización a través de NeXT

En 1988, NeXT obtuvo la licencia de Objective-C de StepStone (el nuevo nombre de PPI, el propietario de la marca registrada Objective-C) y amplió el compilador GCC para admitir Objective-C. NeXT desarrolló las bibliotecas AppKit y Foundation Kit en las que se basaron la interfaz de usuario de NeXTSTEP y el Interface Builder. Si bien las estaciones de trabajo NeXT no lograron tener un gran impacto en el mercado, las herramientas fueron ampliamente elogiadas en la industria. Esto llevó a NeXT a abandonar la producción de hardware y centrarse en herramientas de software, vendiendo NeXTSTEP (y OPENSTEP) como una plataforma para la programación personalizada.

Para eludir los términos de la GPL, NeXT originalmente tenía la intención de enviar la interfaz de Objective-C por separado, permitiendo al usuario vincularla con GCC para producir el ejecutable del compilador. Aunque inicialmente aceptado por Richard M. Stallman, este plan fue rechazado después de que Stallman consultó con los abogados de GNU y NeXT acordó hacer que Objective-C fuera parte de GCC.

El trabajo para extender GCC estuvo a cargo de Steve Naroff, quien se unió a NeXT desde StepStone. Los cambios del compilador se pusieron a disposición según los términos de la licencia GPL, pero las bibliotecas de tiempo de ejecución no, lo que hizo que la contribución de código abierto no se pudiera utilizar para el público en general. Esto llevó a otras partes a desarrollar dichas bibliotecas de tiempo de ejecución bajo una licencia de código abierto. Más tarde, Steve Naroff también fue el colaborador principal del trabajo en Apple para construir la interfaz de Objective-C para Clang.

El proyecto GNU comenzó a trabajar en su implementación de software libre de Cocoa, llamada GNUstep, basada en el estándar OpenStep. Dennis Glatting escribió el primer tiempo de ejecución de Objective-C de GNU en 1992. El tiempo de ejecución de Objective-C de GNU, que ha estado en uso desde 1993, es el que desarrolló Kresten Krab Thorup cuando era estudiante universitario en Dinamarca. Thorup también trabajó en NeXT de 1993 a 1996.

Desarrollo de Apple y Swift

Después de adquirir NeXT en 1996, Apple Computer usó OpenStep en su entonces nuevo sistema operativo, Mac OS X. Esto incluía Objective-C, la herramienta de desarrollo basada en Objective-C de NeXT, Project Builder, y su herramienta de diseño de interfaz, Interface Builder. Ambos se fusionaron más tarde en una sola aplicación, Xcode. La mayor parte de la API Cocoa actual de Apple se basa en objetos de interfaz OpenStep y es el entorno Objective-C más importante que se utiliza para el desarrollo activo.

En WWDC 2014, Apple presentó un nuevo lenguaje, Swift, que se caracterizó como "Objetivo-C sin la C".

Sintaxis

Objective-C es una capa delgada sobre C y es un "superconjunto estricto" de C, lo que significa que es posible compilar cualquier programa de C con un compilador de Objective-C e incluir libremente código de lenguaje C dentro de una clase de Objective-C.

Objective-C deriva su sintaxis de objetos de Smalltalk. Toda la sintaxis de las operaciones no orientadas a objetos (incluidas las variables primitivas, el preprocesamiento, las expresiones, las declaraciones de funciones y las llamadas a funciones) es idéntica a la de C, mientras que la sintaxis de las funciones orientadas a objetos es una implementación de Smalltalk. mensajes de estilo.

Mensajes

El modelo Objective-C de programación orientada a objetos se basa en el paso de mensajes a instancias de objetos. En Objective-C uno no llama a un método; uno envía un mensaje. Esto es diferente al modelo de programación de estilo Simula utilizado por C++. La diferencia entre estos dos conceptos está en cómo se ejecuta el código al que hace referencia el método o el nombre del mensaje. En un lenguaje de estilo Simula, el compilador vincula el nombre del método en la mayoría de los casos a una sección de código en la clase de destino. En Smalltalk y Objective-C, el destino de un mensaje se resuelve en tiempo de ejecución, y el objeto receptor interpreta el mensaje. Un método se identifica mediante un selector o SEL, un identificador único para cada nombre de mensaje, a menudo solo un NUL.-cadena terminada que representa su nombre y resuelta en un puntero de método C que lo implementa: un IMP. Una consecuencia de esto es que el sistema de paso de mensajes no tiene verificación de tipos. No se garantiza que el objeto al que se dirige el mensaje, el receptor, responda a un mensaje y, si no lo hace, genera una excepción.

Enviar el método de mensaje al objeto señalado por el puntero obj requeriría el siguiente código en C++:

obj -> método (argumento);

En Objective-C, esto se escribe de la siguiente manera:

[ método obj: argumento ]; 

El compilador traduce la llamada al "método" a la familia de funciones de tiempo de ejecución objc_msgSend(id self, SEL op,...). Diferentes implementaciones manejan adiciones modernas como super. En las familias GNU, esta función se denomina objc_msg_sendv, pero ha quedado obsoleta en favor de un sistema de búsqueda moderno bajo objc_msg_lookup.

Ambos estilos de programación tienen sus puntos fuertes y débiles. La programación orientada a objetos en el estilo Simula (C++) permite la herencia múltiple y una ejecución más rápida mediante el uso de enlaces en tiempo de compilación siempre que sea posible, pero no admite enlaces dinámicos de forma predeterminada. También obliga a todos los métodos a tener una implementación correspondiente a menos que sean abstractos. La programación de estilo Smalltalk tal como se usa en Objective-C permite que los mensajes no se implementen, con el método resuelto para su implementación en tiempo de ejecución. Por ejemplo, se puede enviar un mensaje a una colección de objetos, a los que se espera que respondan solo algunos, sin temor a que se produzcan errores de tiempo de ejecución. El paso de mensajes tampoco requiere que se defina un objeto en tiempo de compilación. Todavía se requiere una implementación para llamar al método en el objeto derivado.

Interfaces e implementaciones

Objective-C requiere que la interfaz y la implementación de una clase estén en bloques de código declarados por separado. Por convención, los desarrolladores colocan la interfaz en un archivo de encabezado y la implementación en un archivo de código. Los archivos de encabezado, normalmente con el sufijo.h, son similares a los archivos de encabezado de C, mientras que los archivos de implementación (método), normalmente con el sufijo.m, pueden ser muy similares a los archivos de código C.

Interfaz

Esto es análogo a las declaraciones de clase que se usan en otros lenguajes orientados a objetos, como C++ o Python.

La interfaz de una clase generalmente se define en un archivo de encabezado. Una convención común es nombrar el archivo de encabezado después del nombre de la clase, por ejemplo, Ball.h contendría la interfaz para la clase Ball.

Una declaración de interfaz toma la forma:

@interface  classname: superclassname  {
  // variables de instancia 
}
+  métodoclase1;
+  (retorno_tipo) classMethod2;
+  (return_type) classMethod3: (param1_type) param1_varName;

-  (tipo_retorno) método_instancia1Con1Parámetro: (tipo_param1) nombre_var_param1;
-  (tipo_retorno) método_instancia2Con2Parámetros: (tipo_param1) nombre_var_param1
                              param2_callName: (param2_type) param2_varName;
@final

En lo anterior, los signos más denotan métodos de clase, o métodos que se pueden llamar en la clase misma (no en una instancia), y los signos menos denotan métodos de instancia, que solo se pueden llamar en una instancia particular de la clase. Los métodos de clase tampoco tienen acceso a las variables de instancia.

El código anterior es aproximadamente equivalente a la siguiente interfaz de C++:

clase nombre de  clase : nombre de superclase público {    
protegido :
  // variables de instancia

público :
  // Funciones de clase (estáticas) 
static void * classMethod1 ();    
  estático return_type classMethod2 ();  
  static return_type classMethod3 (param1_type param1_varName);   

  // Funciones de instancia (miembro) 
return_type instanceMethod1With1Parameter (param1_type param1_varName);    
  tipo_retorno
  instanceMethod2With2Parameters (param1_type param1_varName, 
                                 param2_type param2_varName = predeterminado );   
};

Tenga en cuenta que instanceMethod2With2Parameters:param2_callName: demuestra el intercalado de segmentos de selector con expresiones de argumento, para lo cual no existe un equivalente directo en C/C++.

Los tipos de retorno pueden ser cualquier tipo C estándar, un puntero a un objeto Objective-C genérico, un puntero a un tipo específico de objeto como NSArray *, NSImage * o NSString *, o un puntero a la clase a la que pertenece el método. (tipo de instancia). El tipo de valor devuelto predeterminado es el ID de tipo de Objective-C genérico.

Los argumentos del método comienzan con un nombre que etiqueta el argumento que forma parte del nombre del método, seguido de dos puntos, seguido del tipo de argumento esperado entre paréntesis y el nombre del argumento. La etiqueta se puede omitir.

-  (void) setRangeStart: (int) start end: (int) end; 
-  (vacío) importDocumentWithName: (NSString *) nombre 
      conPreferenciasEspecificadas: (Preferencias *) preferencias 
                    beforePage: (int) insertPage;

Un derivado de la definición de interfaz es la categoría, que permite agregar métodos a clases existentes.

Implementación

La interfaz solo declara la interfaz de clase y no los métodos en sí: el código real se escribe en el archivo de implementación. Los archivos de implementación (método) normalmente tienen la extensión de archivo .m, que originalmente significaba "mensajes".

@implementación nombre de  clase
+  (tipo_retorno) métodoclase { 
  // implementación 
}
-  (tipo_retorno) métodoInstancia { 
  // implementación 
}
@final

Los métodos se escriben utilizando sus declaraciones de interfaz. Comparando Objective-C y C:

-  (int) método: (int) i { 
  return [ self raíz_cuadrada: i ];  
}
función int (int i) {   
  devuelve raíz_cuadrada (i); 
}

La sintaxis permite la pseudo-nominación de argumentos.

-  (vacío) changeColorToRed: (flotante) rojo verde: (flotante) verde azul: (flotante) azul {   
  //... Implementación... 
}

// Llamado así: 
[ myColor changeColorToRed: 5.0 green: 2.0 blue: 6.0 ];   

Las representaciones internas de un método varían entre las diferentes implementaciones de Objective-C. Si myColor es de la clase Color, el método de instancia -changeColorToRed:green:blue: podría etiquetarse internamente como _i_Color_changeColorToRed_green_blue. La i es para referirse a un método de instancia, con la clase y luego los nombres de los métodos agregados y los dos puntos cambiados a guiones bajos. Como el orden de los parámetros es parte del nombre del método, no se puede cambiar para adaptarlo al estilo de codificación o expresión como ocurre con los parámetros con nombre verdadero.

Sin embargo, los nombres internos de la función rara vez se usan directamente. Por lo general, los mensajes se convierten en llamadas a funciones definidas en la biblioteca de tiempo de ejecución de Objective-C. No se sabe necesariamente en el momento del enlace qué método se llamará porque la clase del receptor (el objeto al que se envía el mensaje) no necesita conocerse hasta el tiempo de ejecución.

Instanciación

Una vez que se escribe una clase de Objective-C, se puede crear una instancia. Esto se hace asignando primero una instancia no inicializada de la clase (un objeto) y luego inicializándola. Un objeto no es completamente funcional hasta que se hayan completado ambos pasos. Estos pasos deben realizarse con una línea de código para que nunca haya un objeto asignado que no se haya inicializado (y porque no es aconsejable mantener el resultado intermedio ya que -initpuede devolver un objeto diferente al que se llama).

Creación de instancias con el inicializador predeterminado sin parámetros:

MiObjeto * foo = [[ Alloc MiObjeto ] init ];     

Creación de instancias con un inicializador personalizado:

MyObject * foo = [[ MyObject alloc ] initWithString: myString ];     

En el caso de que no se realice una inicialización personalizada, a menudo se puede usar el método "nuevo" en lugar de los mensajes alloc-init:

MiObjeto * foo = [ MiObjeto nuevo ];    

Además, algunas clases implementan inicializadores de métodos de clase. Al igual +newque, se combinan +allocy -init, pero a diferencia +newde, devuelven una instancia liberada automáticamente. Algunos inicializadores de métodos de clase toman parámetros:

MiObjeto * foo = [ objeto MiObjeto ];    
MiObjeto * bar = [ MiObjeto objetoConCadena: @"Wikipedia:)" ];    

El mensaje alloc asigna suficiente memoria para contener todas las variables de instancia de un objeto, establece todas las variables de instancia en valores cero y convierte la memoria en una instancia de la clase; en ningún momento durante la inicialización la memoria es una instancia de la superclase.

El mensaje init realiza la configuración de la instancia en el momento de la creación. El método init a menudo se escribe de la siguiente manera:

-  (id) inicio { 
    self = [ inicio super ];   
    si (yo) {  
        // realizar la inicialización del objeto aquí
    }
    devolver uno mismo; 
}

En el ejemplo anterior, observe el idtipo de devolución. Este tipo significa "puntero a cualquier objeto" en Objective-C (ver la sección de escritura dinámica).

El patrón de inicialización se usa para asegurar que el objeto sea correctamente inicializado por su superclase antes de que el método init realice su inicialización. Realiza las siguientes acciones:

Un puntero de objeto no válido tiene el valor nil; las declaraciones condicionales como "if" tratan a nil como un puntero nulo, por lo que el código de inicialización no se ejecutará si se [super init]devuelve nil. Si hay un error en la inicialización, el método init debe realizar la limpieza necesaria, incluido el envío de un mensaje de "liberación" a sí mismo, y devolver nil para indicar que la inicialización falló. Cualquier verificación de tales errores solo debe realizarse después de haber llamado a la inicialización de la superclase para garantizar que la destrucción del objeto se realizará correctamente.

Si una clase tiene más de un método de inicialización, solo uno de ellos (el "inicializador designado") debe seguir este patrón; otros deberían llamar al inicializador designado en lugar del inicializador de superclase.

Protocolos

En otros lenguajes de programación, estos se denominan "interfaces".

Objective-C se amplió en NeXT para introducir el concepto de herencia múltiple de especificación, pero no de implementación, a través de la introducción de protocolos. Este es un patrón que se puede lograr como una clase base heredada múltiple abstracta en C++ o como una "interfaz" (como en Java y C#). Objective-C utiliza protocolos ad hoc llamados protocolos informales y protocolos reforzados por el compilador llamados protocolos formales.

Un protocolo informal es una lista de métodos que una clase puede optar por implementar. Se especifica en la documentación, ya que no tiene presencia en el idioma. Los protocolos informales se implementan como una categoría (ver a continuación) en NSObject y, a menudo, incluyen métodos opcionales que, si se implementan, pueden cambiar el comportamiento de una clase. Por ejemplo, una clase de campo de texto puede tener un delegado que implemente un protocolo informal con un método opcional para completar automáticamente el texto escrito por el usuario. El campo de texto descubre si el delegado implementa ese método (a través de la reflexión) y, si es así, llama al método del delegado para admitir la función de autocompletar.

Un protocolo formal es similar a una interfaz en Java, C# y Ada 2005. Es una lista de métodos que cualquier clase puede declarar para implementar. Las versiones de Objective-C anteriores a la 2.0 requerían que una clase debe implementar todos los métodos en un protocolo que declara adoptar; el compilador emitirá un error si la clase no implementa todos los métodos de sus protocolos declarados. Objective-C 2.0 agregó soporte para marcar ciertos métodos en un protocolo opcional, y el compilador no impondrá la implementación de métodos opcionales.

Se debe declarar una clase para implementar ese protocolo para poder decir que se ajusta a él. Esto es detectable en tiempo de ejecución. Los protocolos formales no pueden proporcionar ninguna implementación; simplemente aseguran a las personas que llaman que las clases que se ajustan al protocolo proporcionarán implementaciones. En la biblioteca NeXT/Apple, el sistema Distributed Objects utiliza con frecuencia los protocolos para representar las capacidades de un objeto que se ejecuta en un sistema remoto.

la sintaxis

@protocol  NSLocking 
-  (vacío) bloqueo;
-  (vacío) desbloquear;
@final

denota que existe la idea abstracta de bloqueo. Al indicar en la definición de clase que el protocolo está implementado,

@interface  NSLock: NSObject < NSLocking > 
//... 
@fin

las instancias de NSLock afirman que proporcionarán una implementación para los dos métodos de instancia.

Escritura dinámica

Objective-C, como Smalltalk, puede usar escritura dinámica: un objeto puede recibir un mensaje que no está especificado en su interfaz. Esto puede permitir una mayor flexibilidad, ya que permite que un objeto "capture" un mensaje y envíe el mensaje a un objeto diferente que pueda responder al mensaje de manera adecuada, o enviar el mensaje a otro objeto. Este comportamiento se conoce como reenvío o delegación de mensajes (ver más abajo). Como alternativa, se puede utilizar un controlador de errores en caso de que el mensaje no se pueda reenviar. Si un objeto no reenvía un mensaje, no responde a él o maneja un error, entonces el sistema generará una excepción de tiempo de ejecución. Si los mensajes se envían a cero(el puntero de objeto nulo), se ignorarán silenciosamente o generarán una excepción genérica, según las opciones del compilador.

La información de escritura estática también se puede agregar opcionalmente a las variables. Luego, esta información se verifica en el momento de la compilación. En las siguientes cuatro declaraciones, se proporciona información de tipo cada vez más específica. Las declaraciones son equivalentes en tiempo de ejecución, pero la información adicional permite que el compilador advierta al programador si el argumento pasado no coincide con el tipo especificado.

-  (vacío) setMyValue: (id) foo;

En la declaración anterior, foo puede ser de cualquier clase.

-  (vacío) setMyValue: (id < NSCopying >) foo;

En la declaración anterior, foo puede ser una instancia de cualquier clase que se ajuste al NSCopyingprotocolo.

-  (vacío) setMyValue: (NSNumber *) foo; 

En la declaración anterior, foo debe ser una instancia de la clase NSNumber.

-  (void) setMyValue: (NSNumber < NSCoping > *) foo; 

En la declaración anterior, foo debe ser una instancia de la clase NSNumber y debe cumplir con el NSCopyingprotocolo.

En Objective-C, todos los objetos se representan como punteros y no se permite la inicialización estática. El objeto más simple es el tipo al que apunta id (objc_obj *), que solo tiene un puntero isa que describe su clase. Otros tipos de C, como valores y estructuras, no se modifican porque no forman parte del sistema de objetos. Esta decisión difiere del modelo de objetos de C++, donde se unen estructuras y clases.

Reenvío

Objective-C permite el envío de un mensaje a un objeto que puede no responder. En lugar de responder o simplemente soltar el mensaje, un objeto puede reenviar el mensaje a un objeto que pueda responder. El reenvío se puede utilizar para simplificar la implementación de ciertos patrones de diseño, como el patrón de observador o el patrón de proxy.

El tiempo de ejecución de Objective-C especifica un par de métodos en Object

Un objeto que desee implementar el reenvío solo necesita anular el método de reenvío con un nuevo método para definir el comportamiento de reenvío. El método de acción performv:: no necesita anularse, ya que este método simplemente realiza una acción basada en el selector y los argumentos. Observe el tipo, que es el tipo de mensajes en Objective-C. SEL

Nota: en OpenStep, Cocoa y GNUstep, los marcos de trabajo comúnmente utilizados de Objective-C, no se usa la clase Object. El método de la clase NSObject se utiliza para realizar el reenvío. - (void)forwardInvocation:(NSInvocation *)anInvocation

Ejemplo

Aquí hay un ejemplo de un programa que demuestra los conceptos básicos del reenvío.Reenviador.h

#importar <objc/Objeto.h>

Reenviador  @interface: Objeto  {
  id del destinatario; // El objeto al que queremos reenviar el mensaje. }  


// Métodos de acceso. 
-  (id) destinatario;
-  (id) setRecipient: (id) _recipient;
@final

Reenviador.m

#import "Reenviador.h"

Reenviador de @  implementación
-  (retval_t) adelante: (SEL) sel args: (arglist_t) args {  
  /* 
  * Comprobar si el destinatario realmente responde al mensaje. 
  * Esto puede ser deseable o no, por ejemplo, si un destinatario 
  * a su vez no responde al mensaje, podría hacer el reenvío 
  * por sí mismo. 
  */
  if ([ el destinatario responde al selector: sel ]) {   
    return [ rendimiento del destinatario: sel args: args ];   
  } más {  
    return [ auto error: "El destinatario no responde" ];  
  }
}

-  (id) setRecipient: (id) _recipient { 
  [ liberación automática del destinatario ]; 
  destinatario = [ _destinatario retener ];   
  devolver uno mismo; 
}

-  (id) destinatario { 
  destinatario de la devolución ; 
}
@final

Destinatario.h

#importar <objc/Objeto.h>

// Un objeto Destinatario simple. 
Destinatario @interface: Objeto
-  (identificación) hola;
@final

Destinatario.m

#import "Destinatario.h"

 Destinatario de @ implementación

-  (identificación) hola { 
  printf ("¡El destinatario dice hola! n ");

  devolver uno mismo; 
}

@final

principal.m

#importar "Reenviador.h" 
#importar "Destinatario.h"

int principal (vacío) {  
  Reenviador * reenviador = [ Reenviador nuevo ];    
  Destinatario * destinatario = [ Destinatario nuevo ];    

  [ reenviador setRecipient: destinatario ]; // Establecer el destinatario. /*   * ¡Observe que el reenviador no responde a un mensaje de saludo! Será   * reenviado. Todos los métodos no reconocidos se reenviarán al   * destinatario   * (si el destinatario responde a ellos, como está escrito en el Reenviador)   */  
  





  [ reenviador hola ]; 

  [ liberación del destinatario ]; 
  [ liberación del reenviador ]; 

  devolver 0; 
}

Notas

Cuando se compila usando gcc, el compilador informa:

$ gcc -x objectivo-c -Wno-import Reenviador.m Destinatario.m main.m -lobjc
 main.m: En la función 'main': 
main.m:12: advertencia: 'Reenviador' no responde a 'hola' 
ps

El compilador informa el punto mencionado anteriormente, que Forwarder no responde a los mensajes de saludo. En esta circunstancia, es seguro ignorar la advertencia ya que se implementó el reenvío. Ejecutar el programa produce esta salida:

$./a.out ¡El
 destinatario dice hola!

Categorías

Durante el diseño de Objective-C, una de las principales preocupaciones fue la mantenibilidad de grandes bases de código. La experiencia del mundo de la programación estructurada había demostrado que una de las principales formas de mejorar el código era dividirlo en partes más pequeñas. Objective-C tomó prestado y amplió el concepto de categorías de las implementaciones de Smalltalk para ayudar con este proceso.

Además, los métodos dentro de una categoría se agregan a una clase en tiempo de ejecución. Por lo tanto, las categorías permiten al programador agregar métodos a una clase existente, una clase abierta, sin la necesidad de volver a compilar esa clase o incluso tener acceso a su código fuente. Por ejemplo, si un sistema no contiene un corrector ortográfico en su implementación de String, podría agregarse sin modificar el código fuente de String.

Los métodos dentro de las categorías se vuelven indistinguibles de los métodos en una clase cuando se ejecuta el programa. Una categoría tiene acceso completo a todas las variables de instancia dentro de la clase, incluidas las variables privadas.

Si una categoría declara un método con la misma firma de método que un método existente en una clase, se adopta el método de la categoría. Por lo tanto, las categorías no solo pueden agregar métodos a una clase, sino también reemplazar métodos existentes. Esta función se puede usar para corregir errores en otras clases reescribiendo sus métodos o para provocar un cambio global en el comportamiento de una clase dentro de un programa. Si dos categorías tienen métodos con el mismo nombre pero firmas de métodos diferentes, no está definido qué método de categoría se adopta.

Otros lenguajes han intentado agregar esta característica de varias maneras. TOM llevó el sistema Objective-C un paso más allá y también permitió la adición de variables. En su lugar, otros lenguajes han utilizado soluciones basadas en prototipos, siendo la más notable Self.

Los lenguajes C# y Visual Basic.NET implementan una funcionalidad superficialmente similar en forma de métodos de extensión, pero estos carecen de acceso a las variables privadas de la clase. Ruby y varios otros lenguajes de programación dinámicos se refieren a la técnica como "parche de mono".

Logtalk implementa un concepto de categorías (como entidades de primera clase) que subsume la funcionalidad de categorías de Objective-C (las categorías de Logtalk también se pueden usar como unidades de composición detalladas al definir, por ejemplo, nuevas clases o prototipos; en particular, una categoría de Logtalk se puede virtualmente importado por cualquier número de clases y prototipos).

Ejemplo de uso de categorías

Este ejemplo construye una clase Integer, definiendo primero una clase básica con solo métodos de acceso implementados, y agregando dos categorías, Arithmetic y Display, que amplían la clase básica. Si bien las categorías pueden acceder a los miembros de datos privados de la clase base, a menudo es una buena práctica acceder a estos miembros de datos privados a través de los métodos de acceso, lo que ayuda a mantener las categorías más independientes de la clase base. La implementación de tales descriptores de acceso es un uso típico de las categorías. Otra es usar categorías para agregar métodos a la clase base. Sin embargo, no se considera una buena práctica el uso de categorías para la anulación de subclases, también conocido como parches mono. Los protocolos informales se implementan como una categoría en el NSObject baseclase. Por convención, los archivos que contienen categorías que amplían las clases base tomarán el nombre BaseClass+ExtensionClass.h.Entero.h

#importar <objc/Objeto.h>

@interfaz  Entero: Objeto  {
  entero entero; 
}

-  (int) entero;
-  (id) entero: (int) _entero;
@final

Entero.m

#import "Entero.h"

@implementación  Entero
-  (int)  entero { 
  devolver entero; 
}

-  (id)  entero: (int) _integer {   
  entero = _entero;  
  devolver uno mismo; 
}
@final

Entero+Aritmética.h

#import "Entero.h"

@interface  Entero  (Aritmética)
-  (id)  suma: (Entero *) sumando;   
-  (id)  sub: (Entero *) sustraendo;   
@final

Entero+Aritmética.m

#import "Entero+Aritmética.h"

@implementation  Entero  (aritmética)
-  (id)  suma: (Entero *) sumando {    
  return [ entero propio: [ entero propio ] + [ entero sumando ]];       
}

-  (id)  sub: (Entero *) sustraendo {    
  return [ entero propio: [ entero propio ] - [ entero sustraendo ]];       
}
@final

Entero+Pantalla.h

#import "Entero.h"

@interface  Entero  (Pantalla)
-  (id)  showstars;
-  (id)  mostrando;
@final

Entero+Pantalla.m

# importar "Entero+Pantalla.h"

@implementation  Integer  (Mostrar)
-  (id)  estrellas del espectáculo { 
  int i, x = [ entero propio ];     
  para (yo = 0; yo < x; yo ++) {        
    imprimirf ("*");
  }
  imprimirf (" n ");

  devolver uno mismo; 
}

-  (id)  mostrando { 
  printf ("%d n ", [ entero propio ]);  

  devolver uno mismo; 
}
@final

principal.m

#import "Entero.h"
#import "Entero+Aritmética.h"
#importar "Entero+Pantalla.h"

int principal (vacío) {  
  Entero * num1 = [ Entero nuevo ], * num2 = [ Entero nuevo ];        
  intx; _ 

  printf ("Ingrese un entero:");
  scanf ("%d", & x); 

  [ num1 entero: x ]; 
  [ num1 estrellas de espectáculo ]; 

  printf ("Ingrese un entero:");
  scanf ("%d", & x); 

  [ num2 entero: x ]; 
  [ num2 estrellas de espectáculo ]; 

  [ num1 añadir: num2 ]; 
  [ num1 mostrandoint ]; 

  devolver 0; 
}

Notas

La compilación se realiza, por ejemplo, mediante:

$ gcc -x objetivo-c main.m Integer.m Integer+Arithmetic.m Integer+Display.m -lobjc

Se puede experimentar omitiendo #import "Integer+Arithmetic.h"(línea 2) y (línea 21) y omitiendo Integer+Arithmetic.m en la compilación. El programa aún se ejecutará. Esto significa que es posible mezclar y combinar categorías agregadas si es necesario; si una categoría no necesita tener alguna habilidad, simplemente no se puede compilar. [num1 add:num2]

Posando

Objective-C permite que una clase reemplace por completo a otra clase dentro de un programa. Se dice que la clase de reemplazo "se hace pasar por" la clase objetivo.

La pose de clase se declaró obsoleta con Mac OS X v10.5 y no está disponible en el tiempo de ejecución de 64 bits. Se puede lograr una funcionalidad similar mediante el uso de métodos swizzling en categorías, que intercambia la implementación de un método con otro que tiene la misma firma.

Para las versiones que aún soportan la presentación, todos los mensajes enviados a la clase de destino son recibidos por la clase que presenta. Hay varias restricciones:

Posar, de manera similar con las categorías, permite el aumento global de las clases existentes. Posar permite dos características ausentes de las categorías:

Por ejemplo,

@interfaz  CustomNSApplication: NSApplication
@final

@implementation  CustomNSApplication
-  (vacío)  setMenúPrincipal: (NSMenú *) menú {   
  // hacer algo con el menú 
}
@final

class_poseAs ([ clase CustomNSApplication ], [ clase NSApplication ]);    

Esto intercepta cada invocación de setMainMenu a NSApplication.

#importar

En el lenguaje C, la #includedirectiva de precompilación siempre hace que el contenido de un archivo se inserte en la fuente en ese punto. Objective-C tiene la #importdirectiva equivalente, excepto que cada archivo se incluye solo una vez por unidad de compilación, lo que elimina la necesidad de incluir guardias.

Compilación gcc de linux

// ARCHIVO: hola.m #importar 
<Fundación/Fundación.h> 
int main (int argc, const char * argv [])       
{
    /* mi primer programa en Objective-C */
    NSLog (@"¡Hola, mundo! n ");
    devolver 0; 
}
$ # Línea de comando de compilación para el compilador gcc y MinGW: 
$ gcc  
    $ (gnustep-config --objc-flags)   
    -o hello  
    hello.m  
    -L /GNUstep/System/Library/Libraries  
    -lobjc 
    -lgnustep-base

$./hola

Otras características

Las características de Objective-C a menudo permiten soluciones flexibles y, a menudo, fáciles para los problemas de programación.

Variantes de idioma

Objetivo-C++

Objective-C++ es una variante de lenguaje aceptada por el front-end de GNU Compiler Collection y Clang, que puede compilar archivos fuente que usan una combinación de C++ y sintaxis de Objective-C. Objective-C++ agrega a C++ las extensiones que Objective-C agrega a C. Como no se hace nada para unificar la semántica detrás de las diversas características del lenguaje, se aplican ciertas restricciones:

Objetivo-C 2.0

En la Conferencia Mundial de Desarrolladores de 2006, Apple anunció el lanzamiento de "Objective-C 2.0", una revisión del lenguaje Objective-C para incluir "recolección de basura moderna, mejoras en la sintaxis, mejoras en el rendimiento del tiempo de ejecución y compatibilidad con 64 bits". Mac OS X v10.5, lanzado en octubre de 2007, incluía un compilador Objective-C 2.0. GCC 4.6 admite muchas funciones nuevas de Objective-C, como propiedades declaradas y sintetizadas, sintaxis de puntos, enumeración rápida, métodos de protocolo opcionales, atributos de método/protocolo/clase, extensiones de clase y una nueva API de tiempo de ejecución de GNU Objective-C.

El nombramiento de Objective-C 2.0 representa una ruptura en el sistema de versiones del lenguaje, ya que la última versión de Objective-C para NeXT fue "objc4". Este nombre de proyecto se mantuvo en la última versión del código fuente de tiempo de ejecución de Objective-C heredado en Mac OS X Leopard (10.5).

Recolección de basura

Objective-C 2.0 proporcionó un recolector de basura generacional conservador opcional. Cuando se ejecuta en modo compatible con versiones anteriores, el tiempo de ejecución convirtió las operaciones de conteo de referencias como "retener" y "liberar" en operaciones sin operaciones. Todos los objetos estaban sujetos a la recolección de basura cuando la recolección de basura estaba habilitada. Los punteros C normales se pueden calificar con "__strong" para activar también las intercepciones del compilador de barrera de escritura subyacente y, por lo tanto, participar en la recolección de elementos no utilizados. También se proporcionó un subsistema débil de puesta a cero de modo que los punteros marcados como "__débil" se establezcan en cero cuando se recopila el objeto (o más simplemente, la memoria del GC). El recolector de elementos no utilizados no existe en la implementación iOS de Objective-C 2.0.La recolección de basura en Objective-C se ejecuta en un subproceso en segundo plano de baja prioridad y puede detenerse en los eventos del usuario, con la intención de mantener la experiencia del usuario receptiva.

La recolección de basura quedó obsoleta en Mac OS X v10.8 a favor del Conteo automático de referencias (ARC). Objective-C en iOS 7 que se ejecuta en ARM64 usa 19 bits de una palabra de 64 bits para almacenar el recuento de referencia, como una forma de punteros etiquetados.

Propiedades

Objective-C 2.0 introduce una nueva sintaxis para declarar variables de instancia como propiedades, con atributos opcionales para configurar la generación de métodos de acceso. Las propiedades son, en cierto sentido, variables de instancia pública; es decir, declarar una variable de instancia como una propiedad proporciona clases externas con acceso (posiblemente limitado, por ejemplo, solo lectura) a esa propiedad. Una propiedad se puede declarar como "solo lectura" y se le puede proporcionar una semántica de almacenamiento como assign, copyo retain. De forma predeterminada, se consideran las propiedades atomic, lo que da como resultado un bloqueo que impide que varios subprocesos accedan a ellas al mismo tiempo. Una propiedad se puede declarar como nonatomic, lo que elimina este bloqueo.

@interfaz  Persona: NSObject  {
@público
  NSString * nombre; 
@privado
  edad int; 
}

@propiedad (copia ) NSString * nombre;  
@propiedad (solo lectura ) int edad;  

-  (id) initWithAge: (int) edad;
@final

Las propiedades se implementan mediante la @synthesizepalabra clave, que genera métodos getter (y setter, si no son de solo lectura) de acuerdo con la declaración de la propiedad. Alternativamente, los métodos getter y setter deben implementarse explícitamente, o la @dynamicpalabra clave puede usarse para indicar que los métodos de acceso se proporcionarán por otros medios. Cuando se compila usando clang 3.1 o superior, todas las propiedades que no están declaradas explícitamente con @dynamic, marcadas readonlyo que tienen un getter y setter completo implementado por el usuario serán implícitamente @synthesize'd' automáticamente.

 Persona @implementación
@synthesize nombre; 

-  (id) initWithAge: (int) initAge { 
  self = [ inicio super ];   
  si (yo) {  
    // NOTA: asignación de variable de instancia directa, no setter de propiedad 
age = initAge;      
  }
  devolver uno mismo; 
}

-  (int) edad { 
  edad de regreso ; 
}
@final

Se puede acceder a las propiedades utilizando la sintaxis tradicional de paso de mensajes, la notación de puntos o, en la codificación de valores clave, por nombre a través de los métodos "valueForKey:"/"setValue:forKey:".

Persona * aPerson = [[ Person alloc ] initWithAge: 53 ];     
una persona nombre = @"Steve"; // NOTA: notación de puntos, usa setter sintetizado, // equivalente a [aPerson setName: @"Steve"]; NSLog (@"Acceso por mensaje (%@), notación de puntos (%@), nombre de propiedad (% @) y "   
                         

       "acceso variable de instancia directa (% @) ",
              [ Nombre de una persona ], 
      una persona nombre, [ unaPersona valueForKey: @"nombre" ], unaPersona -> nombre);     

Para usar la notación de puntos para invocar accesores de propiedad dentro de un método de instancia, se debe usar la palabra clave "self":

-  (void) presentarme con propiedades: (BOOL) useGetter { 
  NSLog (@"Hola, mi nombre es %@.", (useGetter ? self. name: name));     
  // NOTA: getter vs. ivar access 
}

Las propiedades de una clase o protocolo pueden ser objeto de una introspección dinámica.

ent i; 
int propertyCount = 0;   
objc_property_t * listaPropiedades =  
    class_copyPropertyList ([ una clase de Persona ], & propertyCount);  

for (i = 0; i < número de propiedades; i ++) {        
  objc_property_t * thisProperty = propertyList + i;     
  const char * propertyName = property_getName (* thisProperty);    
  NSLog (@"La persona tiene una propiedad: '%s'", propertyName); 
}

Variables de instancia no frágiles

Objective-C 2.0 proporciona variables de instancia no frágiles donde el tiempo de ejecución las admite (es decir, al compilar código para macOS de 64 bits y todos los iOS). En el tiempo de ejecución moderno, se agrega una capa adicional de direccionamiento indirecto al acceso de variables de instancia, lo que permite que el vinculador dinámico ajuste el diseño de la instancia en tiempo de ejecución. Esta función permite dos mejoras importantes en el código Objective-C:

Enumeración rápida

En lugar de usar un objeto NSEnumerator o índices para iterar a través de una colección, Objective-C 2.0 ofrece la sintaxis de enumeración rápida. En Objective-C 2.0, los siguientes bucles son funcionalmente equivalentes, pero tienen características de rendimiento diferentes.

// Usando NSEnumerator 
NSEnumerator * enumerator = [ thePeople objectEnumerator ];    
Persona * p; 

while ((p = [ enumerador nextObject ]) != nil) {       
  NSLog (@"%@ tiene %i años.", [ p nombre ], [ p edad ]);    
}
// Usando índices 
para (int i = 0; i < [ thePeople count ]; i ++) {          
  Persona * p = [ thePeople objectAtIndex: i ];    
  NSLog (@"%@ tiene %i años.", [ p nombre ], [ p edad ]);    
}
// Uso de enumeración rápida 
para (Persona * p en thePeople) {     
  NSLog (@"%@ tiene %i años.", [ p nombre ], [ p edad ]);    
}

La enumeración rápida genera un código más eficiente que la enumeración estándar porque las llamadas a métodos para enumerar objetos se reemplazan por aritmética de punteros mediante el protocolo NSFastEnumeration.

Extensiones de clase

Una extensión de clase tiene la misma sintaxis que una declaración de categoría sin nombre de categoría, y los métodos y propiedades declarados en ella se agregan directamente a la clase principal. Se usa principalmente como una alternativa a una categoría para agregar métodos a una clase sin anunciarlos en los encabezados públicos, con la ventaja de que para las extensiones de clase, el compilador verifica que todos los métodos declarados de forma privada estén realmente implementados.

Implicaciones para el desarrollo del cacao

Todas las aplicaciones de Objective-C desarrolladas para macOS que utilizan las mejoras anteriores para Objective-C 2.0 son incompatibles con todos los sistemas operativos anteriores a 10.5 (Leopard). Dado que la enumeración rápida no genera exactamente los mismos archivos binarios que la enumeración estándar, su uso provocará que una aplicación se bloquee en Mac OS X versión 10.4 o anterior.

Bloques

Blocks es una extensión no estándar para Objective-C (y C y C++) que utiliza una sintaxis especial para crear cierres. Los bloques solo son compatibles con Mac OS X 10.6 "Snow Leopard" o posterior, iOS 4 o posterior y GNUstep con libobjc2 1.7 y compilación con clang 3.1 o posterior.

#incluir <stdio.h> 
#include <Bloque.h> 
typedef int (^ IntBlock)();  

IntBlock MakeCounter (int inicio, int incremento) {     
  __bloque int i = inicio;    

  volver Block_copy (^ {   
    int ret = yo;   
    i += incremento;  
    volver ret; 
  });

}

int principal (vacío) {  
  IntBlock mycounter = MakeCounter (5, 2);    
  printf ("Primera llamada: %d n ", micontador ()); 
  printf ("Segunda llamada: %d n ", micontador ()); 
  printf ("Tercera llamada: %d n ", micontador ()); 

  /* porque fue copiado, también debe ser liberado */
  Block_release (micontador);

  devolver 0; 
}
/* Salida: 
  Primera llamada: 5 
  Segunda llamada: 7 
  Tercera llamada: 9 
*/

Objetivo-C moderno

Apple ha agregado algunas características adicionales a Objective 2.0 con el tiempo. Las adiciones solo se aplican al "compilador LLVM de Apple", es decir, la interfaz del idioma. De manera confusa, el control de versiones utilizado por Apple difiere del de LLVM aguas arriba; consulte las versiones de Xcode § Toolchain para obtener una traducción a los números de versión de LLVM de código abierto.

Recuento automático de referencias

El conteo automático de referencias (ARC) es una función en tiempo de compilación que elimina la necesidad de que los programadores administren manualmente los conteos de retención usando retainy release. A diferencia de la recolección de basura, que ocurre en tiempo de ejecución, ARC elimina la sobrecarga de un proceso separado que administra los recuentos de retención. ARC y la administración de memoria manual no se excluyen mutuamente; los programadores pueden continuar usando código que no sea ARC en proyectos habilitados para ARC deshabilitando ARC para archivos de código individuales. Xcode también puede intentar actualizar automáticamente un proyecto a ARC.

ARC se introdujo en LLVM 3.0. Esto se traduce en Xcode 4.2 (2011) o el compilador LLVM 3.0 de Apple.

Literales

Los tiempos de ejecución de NeXT y Apple Obj-C han incluido durante mucho tiempo una forma abreviada de crear nuevas cadenas, utilizando la sintaxis literal, o pasar a las constantes de @"a new string"CoreFoundation kCFBooleanTruey con valores booleanos. El uso de este formato evita que el programador tenga que usar métodos más largos o similares al realizar ciertas operaciones. kCFBooleanFalseNSNumberinitWithString

Cuando se usa el compilador LLVM de Apple 4.0 (Xcode 4.4) o posterior, también se pueden crear matrices, diccionarios y números (clases NSArray, NSDictionary,) usando sintaxis literal en lugar de métodos. (El compilador Apple LLVM 4.0 se traduce en código abierto LLVM y Clang 3.1).NSNumber

Ejemplo sin literales:

NSArray * myArray = [ NSArray arrayWithObjects: object1, object2, object3, nil ];    
NSDictionary * myDictionary1 = [ NSDictionary dictionaryWithObject: someObject forKey: @"key" ];     
NSDictionary * myDictionary2 = [ NSDictionary dictionaryWithObjectsAndKeys: object1, key1, object2, key2, nil ];        
NSNumber * myNumber = [ NSNumber numberWithInt: myInt ];    
NSNumber * mySumNumber = [ NSNumber numberWithInt:(2 + 3)];     
NSNumber * myBoolNumber = [ NSNumber numberWithBool: YES ];    

Ejemplo con literales:

NSArray * myArray = @[ objeto1, objeto2, objeto3 ];       
NSDictionary * myDictionary1 = @{ @"key": someObject };       
NSDictionary * myDictionary2 = @{ clave1: objeto1, clave2: objeto2 };        
NSNumber * myNumber = @(myInt);   
NSNumber * mySumNumber = @(2 + 3);   
NSNumber * myBoolNumber = @YES;   
NSNumber * myIntegerNumber = @8;   

Sin embargo, a diferencia de los literales de cadena, que se compilan en constantes en el ejecutable, estos literales se compilan en código equivalente a las llamadas de método anteriores. En particular, bajo la administración de memoria con recuento de referencia manual, estos objetos se liberan automáticamente, lo que requiere un cuidado adicional cuando, por ejemplo, se usa con variables estáticas de función u otros tipos de globales.

Suscripción

Cuando se utiliza el compilador LLVM de Apple 4.0 o posterior, las matrices y los diccionarios (NSArrayy NSDictionarylas clases) se pueden manipular mediante subíndices. Los subíndices se pueden usar para recuperar valores de índices (matriz) o claves (diccionario), y con objetos mutables, también se pueden usar para establecer objetos en índices o claves. En el código, los subíndices se representan mediante corchetes [ ].

Ejemplo sin subíndice:

id objeto1 = [ someArray objectAtIndex: 0 ];    
id objeto2 = [ algúnDiccionario objetoParaClave: @"clave" ];    
[ someMutableArray replaceObjectAtIndex: 0 withObject: object3 ];  
[ someMutableDictionary setObject: object4 forKey: @"key" ];  

Ejemplo con subíndice:

id objeto1 = someArray [ 0 ];   
id objeto2 = algúnDiccionario [ @"clave" ];   
algunaMatrizMutable [ 0 ] = objeto3;  
algúnDiccionarioMutable [ @"clave" ] = objeto4;  

Sintaxis "Moderna" de Objective-C (1997)

Después de la compra de NeXT por parte de Apple, se intentaron hacer que el lenguaje fuera más aceptable para los programadores más familiarizados con Java que con Smalltalk. Uno de estos intentos fue introducir lo que se denominó "Sintaxis moderna" para Objective-C en ese momento (a diferencia de la sintaxis "clásica" actual). No hubo cambios en el comportamiento, esto era simplemente una sintaxis alternativa. En lugar de escribir una invocación de método como

    objeto = [[ MyClass alloc ] init ];    
    [ objeto primeraEtiqueta: param1 segundaEtiqueta: param2 ];    

En cambio, fue escrito como

    objeto = (MiClase. alloc). inicio;  
    objeto _ etiquetas (param1, param2);    

Del mismo modo, las declaraciones pasaron de la forma

    - (vacío) firstLabel: (int) param1 secondLabel: (int) param2;    

a

    - (vacío) etiquetas (int param1, int param2);       

Esta sintaxis "moderna" ya no se admite en los dialectos actuales del lenguaje Objective-C.

Mulle-objc

El proyecto mulle-objc es otra reimplementación de Objective-C. Admite compiladores GCC o Clang/LLVM como backends. Se diferencia de otros tiempos de ejecución en términos de sintaxis, semántica y compatibilidad con ABI. Es compatible con Linux, FreeBSD y Windows.

Compilador de objetos portátil

Además de la implementación de GCC/NeXT/Apple, que agregó varias extensiones a la implementación original de Stepstone, también existe otra implementación de Objective-C gratuita y de código abierto llamada Portable Object Compiler. El conjunto de extensiones implementadas por Portable Object Compiler difiere de la implementación de GCC/NeXT/Apple; en particular, incluye bloques similares a Smalltalk para Objective-C, mientras que carece de protocolos y categorías, dos características que se utilizan ampliamente en OpenStep y sus derivados y parientes. En general, POC representa una etapa anterior a NeXT en la evolución del lenguaje, más o menos conforme al libro de Brad Cox de 1991.

También incluye una biblioteca de tiempo de ejecución llamada ObjectPak, que se basa en la biblioteca ICPak101 original de Cox (que a su vez se deriva de la biblioteca de clases Smalltalk-80) y es radicalmente diferente de OpenStep FoundationKit.

GEOS Objetivo-C

El sistema PC GEOS utilizaba un lenguaje de programación conocido como GEOS Objective-C o goc; a pesar de la similitud del nombre, los dos idiomas son similares solo en el concepto general y el uso de palabras clave con el prefijo @.

Sonido metálico

El conjunto de compiladores Clang, parte del proyecto LLVM, implementa Objective-C y otros lenguajes. Después de que GCC 4.3 (2008) cambiara a GPLv3, Apple lo abandonó a favor de clang, un compilador que tiene más poder legal para modificar. Como resultado, muchas de las funciones modernas del lenguaje Objective-C solo son compatibles con Clang.

El esquema de control de versiones de Apple para su "compilador LLVM" basado en clang difiere del control de versiones de código abierto de LLVM. Ver versiones de Xcode § Toolchain para una traducción

GNU, GNUstep y WinObjC

El proyecto GNU ha estado interesado durante mucho tiempo en una plataforma para portar los programas NeXT y Obj-C. El ChangeLog para el directorio libobjc en GCC sugiere que existió antes de 1998 (GCC 2.95), y su README apunta a una reescritura en 1993 (GCC 2.4).

El código fuente de NeXT frontend se lanzó ya que se hizo como parte de GCC, se lanzó la licencia pública GNU que obliga a los que hacen trabajos derivados a hacerlo. Apple continuó con esta tradición al lanzar su bifurcación de GCC hasta 4.2.1, después de lo cual abandonaron el compilador. Los mantenedores de GCC aceptaron los cambios, pero no invirtieron mucho en admitir funciones más nuevas, como el lenguaje Objective-C 2.0.

Los desarrolladores de GNUstep, interesados ​​en el nuevo lenguaje, bifurcaron GCC libobjc a un proyecto independiente de GCC llamado libobjc2 en 2009. También arreglaron que el tiempo de ejecución se usara con Clang para aprovechar la sintaxis del nuevo lenguaje. GCC se movió lentamente al mismo tiempo, pero en GCC 4.6.0 (2011) también pasaron a Objective-C 2.0 en su libobjc. La documentación de GNUstep sugiere que la implementación de GCC aún carece de soporte para bloques, variables no frágiles y el ARC más nuevo.

Microsoft bifurcó libobjc2 en una parte de WinObjC, el puente iOS para la plataforma universal de Windows, en 2015. Combinado con su propia implementación de Cocoa Touch y las API subyacentes, el proyecto permite la reutilización del código de la aplicación iOS dentro de las aplicaciones UWP.

En Windows, las herramientas de desarrollo de Objective-C se proporcionan para su descarga en el sitio web de GNUStep. El sistema de desarrollo GNUStep consta de los siguientes paquetes: GNUstep MSYS System, GNUstep Core, GNUstep Devel, GNUstep Cairo, ProjectCenter IDE (como Xcode, pero no tan complejo), Gorm (constructor de interfaces como Xcode NIB builder). Estos instaladores binarios no se han actualizado desde 2016, por lo que podría ser una mejor idea instalarlos compilando bajo Cygwin o MSYS2.

Uso de la biblioteca

En la actualidad, Objective-C se usa a menudo junto con una biblioteca fija de objetos estándar (a menudo conocida como "kit" o "marco"), como Cocoa, GNUstep u ObjFW. Estas bibliotecas a menudo vienen con el sistema operativo: las bibliotecas GNUstep a menudo vienen con distribuciones basadas en Linux y Cocoa viene con macOS. El programador no está obligado a heredar la funcionalidad de la clase base existente (NSObject/OFObject). Objective-C permite la declaración de nuevas clases raíz que no heredan ninguna funcionalidad existente. Originalmente, los entornos de programación basados ​​en Objective-C solían ofrecer una clase Object como la clase base de la que heredaban casi todas las demás clases. Con la introducción de OpenStep, NeXT creó una nueva clase base llamada NSObject, que ofrecía características adicionales sobre Object (un énfasis en el uso de referencias a objetos y conteo de referencias en lugar de punteros sin procesar, por ejemplo). Casi todas las clases en Cocoa heredan de NSObject.

El cambio de nombre no solo sirvió para diferenciar el nuevo comportamiento predeterminado de las clases dentro de la API de OpenStep, sino que permitió que el código que usaba Object, la clase base original utilizada en NeXTSTEP (y, más o menos, otras bibliotecas de clases de Objective-C), coexistir en el mismo tiempo de ejecución con el código que usó NSObject (con algunas limitaciones). La introducción del prefijo de dos letras también se convirtió en una forma simplista de espacios de nombres, de la que carece Objective-C. El uso de un prefijo para crear un identificador de empaque informal se convirtió en un estándar de codificación informal en la comunidad de Objective-C y continúa hasta el día de hoy.

Más recientemente, han comenzado a aparecer los administradores de paquetes, como CocoaPods, que pretende ser tanto un administrador de paquetes como un repositorio de paquetes. Una gran cantidad de código Objective-C de código abierto que se escribió en los últimos años ahora se puede instalar usando CocoaPods.

Análisis del lenguaje

Las implementaciones de Objective-C usan un sistema de tiempo de ejecución delgado escrito en C, que añade poco al tamaño de la aplicación. Por el contrario, la mayoría de los sistemas orientados a objetos en el momento en que se crearon utilizaban grandes tiempos de ejecución de máquinas virtuales. Los programas escritos en Objective-C tienden a no ser mucho más grandes que el tamaño de su código y el de las bibliotecas (que, por lo general, no necesitan incluirse en la distribución del software), en contraste con los sistemas Smalltalk, donde se usaba una gran cantidad de memoria. usado solo para abrir una ventana. Las aplicaciones de Objective-C tienden a ser más grandes que las aplicaciones similares de C o C++ porque la tipificación dinámica de Objective-C no permite eliminar o insertar métodos. Dado que el programador tiene tanta libertad para delegar, reenviar llamadas, crear selectores sobre la marcha y pasarlos al sistema de tiempo de ejecución, el compilador de Objective-C no puede asumir que es seguro eliminar métodos no utilizados o llamadas en línea.

Del mismo modo, el lenguaje se puede implementar sobre compiladores C existentes (en GCC, primero como preprocesador y luego como módulo) en lugar de como un nuevo compilador. Esto permite que Objective-C aproveche la enorme colección existente de código C, bibliotecas, herramientas, etc. Las bibliotecas C existentes se pueden envolver en contenedores de Objective-C para proporcionar una interfaz de estilo OO. En este aspecto, es similar a la biblioteca GObject y al lenguaje Vala, que se utilizan ampliamente en el desarrollo de aplicaciones GTK.

Todos estos cambios prácticos redujeron la barrera de entrada, probablemente el mayor problema para la aceptación generalizada de Smalltalk en la década de 1980.

Una crítica común es que Objective-C no tiene soporte de lenguaje para espacios de nombres. En cambio, los programadores se ven obligados a agregar prefijos a los nombres de sus clases, que tradicionalmente son más cortos que los nombres de los espacios de nombres y, por lo tanto, son más propensos a las colisiones. A partir de 2007, todas las clases y funciones de macOS en el entorno de programación Cocoa tienen el prefijo "NS" (por ejemplo, NSObject, NSButton) para identificarlas como pertenecientes al núcleo de macOS o iOS; el "NS" se deriva de los nombres de las clases definidas durante el desarrollo de NeXTSTEP.

Dado que Objective-C es un superconjunto estricto de C, no trata los tipos primitivos de C como objetos de primera clase.

A diferencia de C++, Objective-C no admite la sobrecarga de operadores. También a diferencia de C++, Objective-C permite que un objeto herede directamente solo de una clase (prohibiendo la herencia múltiple). Sin embargo, en la mayoría de los casos, las categorías y los protocolos pueden usarse como formas alternativas para lograr los mismos resultados.

Debido a que Objective-C usa escritura dinámica en tiempo de ejecución y dado que todas las llamadas a métodos son llamadas a funciones (o, en algunos casos, llamadas al sistema), muchas optimizaciones de rendimiento comunes no se pueden aplicar a los métodos de Objective-C (por ejemplo: en línea, propagación constante, optimizaciones interprocedimiento, y reemplazo escalar de agregados). Esto limita el rendimiento de las abstracciones de Objective-C en relación con abstracciones similares en lenguajes como C++ donde tales optimizaciones son posibles.

Gestión de la memoria

Las primeras versiones de Objective-C no admitían la recolección de basura. En ese momento, esta decisión fue un tema de debate, y muchas personas consideraron largos "tiempos muertos" (cuando Smalltalk realizaba la recopilación) para inutilizar todo el sistema. Algunas implementaciones de terceros han agregado esta característica (sobre todo GNUstep usando Boehm), y Apple la implementó a partir de Mac OS X v10.5. Sin embargo, en versiones más recientes de macOS e iOS, la recolección de elementos no utilizados ha quedado obsoleta en favor del recuento automático de referencias (ARC), introducido en 2011.

Con ARC, el compilador inserta llamadas de retención y liberación automáticamente en código Objective-C basado en análisis de código estático. La automatización libera al programador de tener que escribir código de administración de memoria. ARC también agrega referencias débiles al lenguaje Objective-C.

Diferencias filosóficas entre Objective-C y C++

El diseño y la implementación de C++ y Objective-C representan enfoques fundamentalmente diferentes para extender C.

Además del estilo de programación procedimental de C, C++ soporta directamente ciertas formas de programación orientada a objetos, programación genérica y metaprogramación. C++ también viene con una gran biblioteca estándar que incluye varias clases de contenedores. De manera similar, Objective-C agrega programación orientada a objetos, escritura dinámica y reflexión a C. Objective-C no proporciona una biblioteca estándar per se, pero en la mayoría de los lugares donde se usa Objective-C, se usa con una biblioteca similar a OpenStep. biblioteca como OPENSTEP, Cocoa o GNUstep, que proporciona una funcionalidad similar a la biblioteca estándar de C++.

Una diferencia notable es que Objective-C proporciona soporte de tiempo de ejecución para funciones reflectantes, mientras que C++ agrega solo una pequeña cantidad de soporte de tiempo de ejecución a C. En Objective-C, se puede consultar un objeto sobre sus propias propiedades, por ejemplo, si responderá a un mensaje determinado. En C++, esto no es posible sin el uso de bibliotecas externas.

El uso de la reflexión es parte de la distinción más amplia entre características dinámicas (tiempo de ejecución) y características estáticas (tiempo de compilación) de un lenguaje. Aunque Objective-C y C++ emplean cada uno una combinación de ambas funciones, Objective-C está decididamente orientado a las decisiones en tiempo de ejecución, mientras que C++ está orientado a las decisiones en tiempo de compilación. La tensión entre la programación dinámica y estática implica muchas de las ventajas y desventajas clásicas de la programación: las funciones dinámicas agregan flexibilidad, las funciones estáticas agregan velocidad y verificación de tipos.

La programación genérica y la metaprogramación se pueden implementar en ambos lenguajes utilizando el polimorfismo en tiempo de ejecución. En C++ esto toma la forma de funciones virtuales e identificación de tipo de tiempo de ejecución, mientras que Objective-C ofrece tipificación dinámica y reflexión. Tanto Objective-C como C++ admiten polimorfismo en tiempo de compilación (funciones genéricas), y Objective-C solo agregó esta característica en 2015.