Objective-C es un lenguaje de programación orientado a objetos de propósito general de alto nivel que agrega el paso de mensajes (mensajería) al estilo Smalltalk al lenguaje de programación C [3] . Originalmente desarrollado por Brad Cox y Tom Love a principios de la década de 1980, fue seleccionado por NeXT para su sistema operativo NeXTSTEP . Debido al linaje directo de Apple macOS de NeXTSTEP, [4] Objective-C fue el lenguaje estándar utilizado, respaldado y promovido por Apple para desarrollar aplicaciones macOS e iOS (a través de sus respectivas interfaces de programación de aplicaciones ( API ), Cocoa y Cocoa Touch ) desde 1997, cuando Apple compró NeXT hasta la introducción del lenguaje Swift en 2014. [3]
Los programas Objective-C desarrollados para sistemas operativos que no sean de Apple o que no dependan de las API de Apple también pueden compilarse para cualquier plataforma compatible con GNU GNU Compiler Collection (GCC) o LLVM / Clang .
Los archivos de programas de 'mensajería/implementación' del código fuente de Objective-C generalmente tienen .mextensiones de nombre de archivo, mientras que los archivos de 'encabezado/interfaz' de Objective-C tienen .hextensiones, al igual que los archivos de encabezado de C. Los archivos Objective-C++ se denotan con una .mmextensión de archivo.
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) . [5]
Antes de la creación de su empresa, ambos habían conocido Smalltalk mientras trabajaban en el Centro de Tecnología de Programación de ITT Corporation en 1981. Los primeros trabajos sobre Objective-C se remontan a esa época. [6] Cox estaba intrigado por los problemas de reutilización real en el diseño y la programación de software. Se dio cuenta de que un lenguaje como Smalltalk sería invaluable para crear 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. [7]
Cox comenzó a escribir un preprocesador para C para añadir algunas de las capacidades de Smalltalk . Pronto tuvo una implementación funcional de una extensión orientada a objetos para el lenguaje C , a la que llamó Object-Oriented Pre-Compiler (OOPC). [8] 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 idea original. Para demostrar que se podía lograr un progreso real, Cox demostró que hacer componentes de software intercambiables realmente necesitaba solo unos pocos cambios prácticos en las herramientas existentes. Específicamente, necesitaban soportar objetos de manera flexible, venir provistos de un conjunto utilizable de bibliotecas y permitir que el código (y cualquier recurso necesario para el código) se agrupara en un formato multiplataforma .
Love y Cox finalmente formaron PPI para comercializar su producto, que combinaba 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 Object-Oriented Programming, An Evolutionary Approach . Aunque tuvo cuidado de explicar que el problema de la reutilización implica más que lo que Objective-C proporciona, el lenguaje a menudo se comparaba 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 que fuera compatible con Objective-C. NeXT desarrolló las bibliotecas Application Kit (AppKit) y Foundation Kit en las que se basaron la interfaz de usuario 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. NeXT abandonó la producción de hardware y se centró en herramientas de software, vendiendo NeXTSTEP (y OPENSTEP) como una plataforma para programación personalizada.
Para eludir los términos de la GPL , NeXT originalmente tenía la intención de distribuir la interfaz de Objective-C por separado, lo que permitiría al usuario vincularla con GCC para producir el ejecutable del compilador. Aunque inicialmente fue aceptado por Richard M. Stallman , este plan fue rechazado después de que Stallman consultara con los abogados de GNU y NeXT aceptara hacer de Objective-C parte de GCC. [9]
El trabajo para ampliar GNU Compiler Collection (GCC) fue dirigido por 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 Pública General GNU (GPL), pero no así las bibliotecas de ejecución , lo que hizo que la contribución de código abierto no pudiera ser utilizada por el público en general. Esto llevó a otras partes a desarrollar dichas bibliotecas de ejecución bajo licencias de código abierto. Más tarde, Steve Naroff también fue el principal colaborador en Apple para construir la interfaz 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 . [10] Dennis Glatting escribió el primer entorno de ejecución GNU Objective-C en 1992. El entorno de ejecución GNU Objective-C actual, en uso desde 1993, es el desarrollado por Kresten Krab Thorup mientras era estudiante universitario en Dinamarca . [ cita requerida ] Thorup también trabajó en NeXT de 1993 a 1996. [11]
Desarrollo de Apple y Swift
Después de adquirir NeXT en 1996, Apple Computer utilizó 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 . Ambas 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 la WWDC 2014, Apple presentó un nuevo lenguaje, Swift , que se caracterizó como "Objective-C sin C".
Sintaxis
Objective-C es una capa fina sobre C y es un " superconjunto estricto " de C, lo que significa que es posible compilar cualquier programa C con un compilador Objective-C e incluir libremente código de lenguaje C dentro de una clase Objective-C. [12] [13] [14] [15] [16] [17]
Objective-C deriva su sintaxis de objetos de Smalltalk . Toda la sintaxis para operaciones no orientadas a objetos (incluidas las variables primitivas, el preprocesamiento, las expresiones, las declaraciones de funciones y las llamadas de funciones) son idénticas a las de C, mientras que la sintaxis para las funciones orientadas a objetos es una implementación de la mensajería de estilo Smalltalk.
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 no se llama a un método , se envía un mensaje . Esto es diferente del 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 nombre del método o del mensaje. En un lenguaje de estilo Simula, el nombre del método está en la mayoría de los casos ligado a una sección de código en la clase de destino por el compilador. En Smalltalk y Objective-C, el destino de un mensaje se resuelve en tiempo de ejecución, con el objeto receptor mismo interpretando el mensaje. Un método se identifica mediante un selector o SEL (un identificador único para cada nombre de mensaje, a menudo solo una NULcadena terminada en - que representa su nombre) y se resuelve en un puntero de método C que lo implementa: un IMP. [18] 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, lanza una excepción. [19]
Para enviar el mensaje methodal objeto señalado por el puntero objse requeriría el siguiente código en C++ :
obj -> método ( argumento );
En Objective-C, esto se escribe de la siguiente manera:
[ obj método : argumento ];
El compilador traduce la llamada "método" a la objc_msgSend(id self, SEL op, ...)familia de funciones de tiempo de ejecución. Diferentes implementaciones manejan adiciones modernas como super. [20] En las familias GNU esta función se llama objc_msg_sendv, pero ha quedado obsoleta en favor de un sistema de búsqueda moderno bajo objc_msg_lookup. [21]
Ambos estilos de programación tienen múltiples fortalezas y debilidades. 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 el enlace dinámico 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 que se usa en Objective-C permite que los mensajes no se implementen, y el método se resuelve en 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 solo respondan algunos, sin temor a producir errores en tiempo de ejecución. El paso de mensajes tampoco requiere que se defina un objeto en tiempo de compilación . Aún se requiere una implementación para que se llame al método en el objeto derivado. (Consulte la sección de tipado dinámico a continuación para obtener más ventajas del enlace dinámico (tardío)).
Interfaces e implementaciones
Objective-C requiere que la interfaz y la implementación de una clase se declaren por separado en bloques de código. 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 de C.
Interfaz
Esto es análogo a las declaraciones de clases que se utilizan en otros lenguajes orientados a objetos, como C++ o Python.
La interfaz de una clase se define normalmente 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.hcontendría la interfaz de la clase Ball.
Una declaración de interfaz toma la forma:
@interface classname : superclassname {
// variables de instancia } + classMethod1 ; + ( tipo_de_retorno ) classMethod2 ; + ( tipo_de_retorno ) classMethod3: ( tipo_param1 ) nombre_varparam1 ;
- ( tipo_de_retorno ) método_de_instancia1Con1Parámetro: ( tipo_de_parámetro1 ) nombre_var_parámetro1 ;
- ( tipo_de_retorno ) método_de_instancia2Con2Parámetros: ( tipo_de_parámetro1 ) nombre_var_parámetro1
nombre_de_llamada_parámetro2 :( tipo_de_parámetro2 ) nombre_var_parámetro2 ; @fin
En lo anterior, los signos más indican métodos de clase o métodos que se pueden llamar en la clase misma (no en una instancia), y los signos menos indican 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 variables de instancia .
El código anterior es aproximadamente equivalente a la siguiente interfaz C++ :
clase nombre_clase : public nombre_superclase { protected : // variables de instancia
público :
// Funciones de clase (estáticas) static void * classMethod1 (); static return_type classMethod2 (); static return_type classMethod3 ( param1_type param1_varName );
// Funciones de instancia (miembro)
tipo_de_retorno instanceMethod1With1Parameter ( tipo_de_parámetro1 param1_varName ); tipo_de_retorno instanceMethod2With2Parameters ( tipo_de_parámetro1 param1_varName , tipo_de_parámetro2 param2_varName = predeterminado ); };
Tenga en cuenta que instanceMethod2With2Parameters:param2_callName:demuestra el entrelazado de segmentos de selector con expresiones de argumentos, para lo cual no existe un equivalente directo en C/C++.
Los tipos de retorno pueden ser cualquier tipo estándar de C , un puntero a un objeto genérico de Objective-C, 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 retorno predeterminado es el tipo genérico de Objective-C id.
Los argumentos de un método comienzan con un nombre que etiqueta el argumento que forma parte del nombre del método, seguido de dos puntos y, a continuación, el tipo de argumento esperado entre paréntesis y el nombre del argumento. La etiqueta se puede omitir.
- ( void ) setRangeStart: ( int ) inicio fin: ( int ) fin ; - ( void ) importDocumentWithName: ( NSString * ) nombre withSpecifiedPreferences :( 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. [22]
Implementación
La interfaz sólo 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étodos) normalmente tienen la extensión de archivo .m, que originalmente significaba "mensajes". [23]
@implementation nombre_clase
+ ( tipo_retorno ) método_clase { // implementación } - ( tipo_retorno ) método_instancia { // implementación } @end
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 ) { devolver raíz_cuadrada ( i ); }
La sintaxis permite la pseudodenominación de argumentos .
- ( void ) changeColorToRed: ( float ) rojo verde: ( float ) verde azul : ( float ) azul { //... Implementación ... }
// Se llama 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:puede tener la etiqueta interna _i_Color_changeColorToRed_green_blue. El ies para hacer referencia a un método de instancia, con los nombres de la clase y del método 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 adaptarse al estilo de codificación o expresión como con los parámetros con nombre verdadero.
Sin embargo, rara vez se utilizan directamente los nombres internos de la función. Generalmente, los mensajes se convierten en llamadas de función definidas en la biblioteca de ejecución Objective-C. No se sabe necesariamente en el momento del enlace qué método se llamará porque no es necesario conocer la clase del receptor (el objeto al que se envía el mensaje) hasta el momento de la ejecución.
Instanciación
Una vez que se escribe una clase Objective-C, se puede crear una instancia de la misma. Para ello, primero se asigna una instancia no inicializada de la clase (un objeto) y luego se inicializa. Un objeto no es completamente funcional hasta que se hayan completado ambos pasos. Estos pasos se deben realizar con una línea de código para que nunca haya un objeto asignado que no haya pasado por la inicialización (y porque no es aconsejable conservar el resultado intermedio, ya que -initpuede devolver un objeto diferente de aquel en el que se lo llama).
Creación de instancias con el inicializador predeterminado, sin parámetros:
MiObjeto * foo = [[ MiObjeto alloc ] init ];
Instanciación con un inicializador personalizado:
MiObjeto * foo = [[ MiObjeto alloc ] initWithString : miCadena ];
En el caso en que no se realice ninguna inicialización personalizada, a menudo se puede utilizar 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. Como +new, combinan +allocy -init, pero a diferencia de +new, devuelven una instancia liberada automáticamente. Algunos inicializadores de métodos de clase toman parámetros:
MiObjeto * foo = [ MiObjeto objeto ]; MiObjeto * bar = [ MiObjeto objetoWithString : @"Wikipedia :)" ];
El mensaje de asignación 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 al momento de su creación. El método init suele escribirse de la siguiente manera:
- ( id ) init {
yo mismo = [ super init ];
si ( yo mismo ) {
// realiza la inicialización del objeto aquí
}
devolver yo mismo ;
}
En el ejemplo anterior, observe el idtipo de retorno. Este tipo representa un puntero a cualquier objeto en Objective-C (consulte la sección Tipos dinámicos).
El patrón de inicialización se utiliza para garantizar que el objeto sea inicializado correctamente por su superclase antes de que el método init realice su inicialización. Realiza las siguientes acciones:
- Línea 2
- Envía un
initmensaje a la instancia de la superclase y asigna el resultado aself(puntero al objeto actual).
- Envía un
- Línea 3
- Comprueba si el puntero del objeto devuelto es válido antes de realizar cualquier inicialización.
- Línea 6
- Devuelve el valor de self al llamador.
Un puntero a objeto no válido tiene el valor nil; las sentencias condicionales como iftratan nil como un puntero nulo, por lo que el código de inicialización no se ejecutará si [super init]se devuelve nil. Si hay un error en la inicialización, el método init debe realizar cualquier limpieza necesaria, incluido el envío de un releasemensaje a sí mismo y regresar nilpara 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; los demás deben llamar al inicializador designado en lugar del inicializador de la superclase.
Protocolos
En otros lenguajes de programación, estas se llaman interfaces .
Objective-C se amplió en NeXT para introducir el concepto de herencia múltiple de especificaciones, pero no de implementación, mediante la introducción de protocolos . Este es un patrón que se puede lograr ya sea como una clase base abstracta de herencia múltiple en C++ o como una interfaz (como en Java y C# ). Objective-C utiliza protocolos ad hoc llamados protocolos informales y protocolos aplicados 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 lenguaje. Los protocolos informales se implementan como una categoría (ver más abajo) 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 implementa un protocolo informal con un método opcional para realizar el autocompletado del texto escrito por el usuario. El campo de texto descubre si el delegado implementa ese método (a través de programación reflexiva (reflexión)) y, si es así, llama al método del delegado para admitir la función de autocompletado.
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 que va a implementar. Las versiones de Objective-C anteriores a la 2.0 requerían que una clase implementara todos los métodos de un protocolo que declara que adopta; el compilador emitirá un error si la clase no implementa todos los métodos de sus protocolos declarados. Objective-C 2.0 agregó compatibilidad para marcar ciertos métodos en un protocolo como opcionales, y el compilador no impondrá la implementación de métodos opcionales.
Se debe declarar una clase para implementar ese protocolo para que se pueda decir que cumple con él. Esto se puede detectar en tiempo de ejecución. Los protocolos formales no pueden proporcionar ninguna implementación; simplemente aseguran a los usuarios que las llaman que las clases que cumplen con el protocolo proporcionarán implementaciones. En la biblioteca NeXT/Apple, el sistema de objetos distribuidos utiliza con frecuencia protocolos para representar las capacidades de un objeto que se ejecuta en un sistema remoto.
La sintaxis
@protocol NSLocking
- ( void ) bloquear ;
- ( void ) desbloquear ;
@end
denota que existe la idea abstracta de bloqueo. Al indicar en la definición de clase que se implementa el protocolo,
@interface NSLock : NSObject < NSLocking > // ... @fin
Las instancias de NSLock afirman que proporcionarán una implementación para los dos métodos de instancia.
Tipificación dinámica
Objective-C, al igual que Smalltalk, puede utilizar tipado dinámico : se puede enviar a un objeto 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 lo envíe a un objeto diferente que pueda responder al mensaje de forma adecuada, o bien enviar el mensaje a otro objeto. Este comportamiento se conoce como reenvío o delegación de mensajes (véase más adelante). Alternativamente, se puede utilizar un controlador de errores en caso de que no se pueda reenviar el mensaje. Si un objeto no reenvía un mensaje, no responde a él o no controla un error, el sistema generará una excepción en tiempo de ejecución. [24] Si se envían mensajes a nil (el puntero de objeto nulo), se ignorarán silenciosamente o generarán una excepción genérica, según las opciones del compilador.
También se puede añadir opcionalmente información de tipado estático a las variables. Esta información se comprueba en el momento de la compilación. En las cuatro sentencias siguientes, se proporciona información de tipo cada vez más específica. Las sentencias son equivalentes en el momento de la ejecución, pero la información adicional permite al compilador advertir al programador si el argumento pasado no coincide con el tipo especificado.
- ( void ) establecerMiValor: ( id ) foo ;
En la declaración anterior, foo puede ser de cualquier clase.
- ( void ) establecerMiValor: ( id < NSCopying > ) foo ;
En la declaración anterior, foo puede ser una instancia de cualquier clase que se ajuste al NSCopyingprotocolo.
- ( void ) establecerMiValor: ( NSNumber * ) foo ;
En la declaración anterior, foo debe ser una instancia de la clase NSNumber .
- ( void ) establecerMiValor: ( NSNumber < NSCopying > * ) 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 las estructuras y las clases están unidas.
Reenvío
Objective-C permite enviar un mensaje a un objeto que puede no responder. En lugar de responder o simplemente descartar el mensaje, un objeto puede reenviar el mensaje a un objeto que sí puede 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 proxy .
El entorno de ejecución de Objective-C especifica un par de métodos enObject
- métodos de reenvío:
- ( retval_t ) forward: ( SEL ) sel args: ( arglist_t ) args ; // con GCC - ( id ) forward: ( SEL ) sel args: ( marg_list ) args ; // con sistemas NeXT/Apple
- métodos de acción:
- ( retval_t ) performv: ( SEL ) sel args: ( arglist_t ) args ; // con GCC - ( id ) performv: ( SEL ) sel args: ( marg_list ) args ; // con sistemas NeXT/Apple
Un objeto que desee implementar el reenvío solo necesita reemplazar el método de reenvío con un nuevo método para definir el comportamiento de reenvío. performv::No es necesario reemplazar el método de acción, ya que este método simplemente realiza una acción basada en el selector y los argumentos. Observe el SELtipo, que es el tipo de mensajes en Objective-C.
Nota: en OpenStep, Cocoa y GNUstep, los marcos de trabajo de Objective-C más utilizados, no se utiliza la Objectclase. El método de la clase se utiliza para realizar el reenvío.
- (void)forwardInvocation:(NSInvocation *)anInvocationNSObject
Ejemplo
A continuación se muestra un ejemplo de un programa que demuestra los conceptos básicos del reenvío.
- Reenviador.h
#importar <objc/Objeto.h>
@interface Forwarder : Object {
id destinatario ; // El objeto al que queremos reenviar el mensaje. }
// Métodos de acceso.
- ( id ) destinatario ;
- ( id ) setRecipient: ( id ) _recipient ;
@end
- Reenviador.m
#importar "Forwarder.h"
@implementation Forwarder
- ( retval_t ) forward: ( SEL ) sel args: ( arglist_t ) args { /* * Verifica 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 reenviarlo * él mismo. */ if ([ receiver respondsToSelector : sel ]) { return [ receiver performv : sel args : args ]; } else { return [ self error : "El destinatario no responde" ]; } }
- ( id ) setRecipient: ( id ) _recipient { [ liberación automática del destinatario ]; destinatario = [ retención del destinatario ]; devolver uno mismo ; }
- ( id ) destinatario { devolver destinatario ; } @end
- Destinatario.h
#importar <objc/Objeto.h>
// Un objeto Destinatario simple.
@interface Destinatario : Objeto
- ( id ) hola ;
@end
- Destinatario.m
#import "Destinatario.h"
Destinatario de @implementation
- ( id ) hola { printf ( "El destinatario dice hola! \n " );
devuelve yo mismo ; }
@fin
- principal.m
#import "Reenviador.h"
#import "Destinatario.h"
int main ( void ) { Reenviador * reenviador = [ Reenviador nuevo ]; Destinatario * destinatario = [ Destinatario nuevo ];
[ forwarder setRecipient : receiver ]; // Establece el destinatario. /* * ¡Observa que el reenviador no responde a un mensaje de saludo! Se * reenviará. Todos los métodos no reconocidos se * reenviarán al destinatario * (si el destinatario responde a ellos, como está escrito en el reenviador) */ [ forwarder hello ];
[ liberación del destinatario ]; [ liberación del reenvío ];
devuelve 0 ; }
Notas
Cuando se compila utilizando gcc , el compilador informa:
$ gcc -x objective-c -Wno-import Forwarder.m Recipient.m main.m -lobjc
main.m: En la función `main':
main.m:12: advertencia: `Forwarder' no responde a `hello'
$
El compilador informa sobre el punto mencionado anteriormente, que Forwarderno responde a los mensajes de saludo. En esta circunstancia, es seguro ignorar la advertencia ya que se implementó el reenvío. Al ejecutar el programa se produce este resultado:
$ ./a.out ¡
El destinatario dice hola!
Categorías
Durante el diseño de Objective-C, una de las principales preocupaciones era la capacidad de mantenimiento 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. [25]
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, se podría agregar sin modificar el código fuente de String.
Los métodos dentro de las categorías se vuelven indistinguibles de los métodos de una clase cuando se ejecuta el programa. Una categoría tiene acceso total 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 característica se puede utilizar 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étodo diferentes, no está definido qué método de la categoría se adopta.
Otros lenguajes han intentado añadir esta característica de diversas formas. TOM llevó el sistema Objective-C un paso más allá y permitió también la adición de variables. Otros lenguajes han utilizado soluciones basadas en prototipos , siendo la más notable Self .
Los lenguajes C# y Visual Basic (.NET) implementan funciones superficialmente similares en forma de métodos de extensión , pero estos carecen de acceso a las variables privadas de la clase. [26] Ruby y varios otros lenguajes de programación dinámica se refieren a la técnica como " parcheo de mono ".
Logtalk implementa un concepto de categorías (como entidades de primera clase) que subsume la función de categorías de Objective-C (las categorías de Logtalk también se pueden usar como unidades de composición de grano fino al definir, por ejemplo, nuevas clases o prototipos; en particular, una categoría de Logtalk puede ser importada virtualmente por cualquier número de clases y prototipos).
Ejemplo de uso de categorías
Este ejemplo crea una Integerclase definiendo primero una clase básica con solo métodos de acceso implementados y agregando dos categorías, Arithmeticy Display, que extienden 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. Implementar dichos métodos de acceso es un uso típico de las categorías. Otro es usar categorías para agregar métodos a la clase base. Sin embargo, no se considera una buena práctica usar categorías para anular subclases, también conocido como parcheo de mono . Los protocolos informales se implementan como una categoría en la NSObjectclase base. Por convención, los archivos que contienen categorías que extienden clases base tomarán el nombre BaseClass+ExtensionClass.h .
- Entero.h
#importar <objc/Objeto.h> @interface Entero : Objeto { int entero ; } - ( int ) entero ; - ( id ) entero: ( int ) _integer ; @end
- Entero.m
#importar "Entero.h" @implementation Entero - ( int ) entero { devolver entero ; } - ( id ) entero: ( int ) _integer { entero = _integer ; devuelve self ; } @end
- Entero+Aritmética.h
#importar "Entero.h" @interface Entero (Aritmética) - ( id ) suma: ( Entero * ) sumando ; - ( id ) sub: ( Entero * ) sustraendo ; @end
- Entero+Aritmética.m
#import "Entero+Aritmética.h" @implementation Entero (Aritmética) - ( id ) add: ( Entero * ) addend { return [ entero propio : [ entero propio ] + [ addend entero ]]; } - ( id ) sub: ( entero * ) sustraendo { return [ entero propio : [ entero propio ] - [ entero sustraendo ]]; } @end
- Entero+Mostrar.h
#importar "Entero.h" @interface Entero (Mostrar) - ( id ) showstars ; - ( id ) showint ; @end
- Entero+Mostrar.m
# importar "Integer+Display.h" @implementation Entero (Mostrar) - ( id ) muestra estrellas { int i , x = [ entero propio ]; para ( i = 0 ; i < x ; i ++ ) { printf ( "*" ); } printf ( " \n " ); devuelve yo mismo ; } - ( id ) showint { printf ( "%d \n " , [ entero propio ]); devuelve yo mismo ; } @end
- principal.m
#importar "Entero.h" #import "Entero+Aritmética.h" #import "Entero+Pantalla.h" int principal ( vacío ) { Entero * num1 = [ Entero nuevo ], * num2 = [ Entero nuevo ]; entero x ; printf ( "Ingrese un entero: " ); scanf ( "%d" , & x ); [ num1 entero : x ]; [ num1 estrellas del espectáculo ]; printf ( "Ingrese un entero: " ); scanf ( "%d" , & x ); [ num2 entero : x ]; [ num2 estrellas del espectáculo ]; [ num1 suma : num2 ]; [ num1 muestraint ]; devuelve 0 ; }
Notas
La compilación se realiza, por ejemplo, mediante:
$ gcc -x objective-c main.m Entero.m Entero+Aritmética.m Entero+Visualización.m -lobjc
Se puede experimentar omitiendo #import "Integer+Arithmetic.h"(línea 2) y (línea 21) y omitiendo la compilación. El programa seguirá ejecutándose. Esto significa que es posible combinar y mezclar categorías agregadas si es necesario; si una categoría no necesita tener alguna habilidad, simplemente no se puede compilar.
[num1 add:num2]Integer+Arithmetic.m
Posando
Objective-C permite que una clase reemplace por completo a otra clase dentro de un programa. Se dice que la clase que reemplaza "se hace pasar por" la clase de destino.
La presentación de clases se declaró obsoleta en Mac OS X v10.5 y no está disponible en el entorno de ejecución de 64 bits . Se puede lograr una función similar mediante el uso de la combinación de métodos en categorías, que intercambia la implementación de un método con la de otro que tenga la misma firma.
En las versiones que aún admiten la función de posado, todos los mensajes enviados a la clase de destino son recibidos por la clase de posado. Existen varias restricciones:
- Una clase sólo puede hacerse pasar por una de sus superclases directas o indirectas.
- La clase que presenta el problema no debe definir ninguna variable de instancia nueva que esté ausente en la clase de destino (aunque puede definir o anular métodos).
- Es posible que la clase objetivo no haya recibido ningún mensaje antes de la pose.
La presentación, al igual que las categorías, permite la ampliación global de las clases existentes. La presentación permite dos características que no están presentes en las categorías:
- Una clase que plantea puede llamar a métodos anulados a través de super, incorporando así la implementación de la clase de destino.
- Una clase que plantea puede anular los métodos definidos en categorías.
Por ejemplo,
@interface AplicaciónNS personalizada : AplicaciónNS
@fin
@implementation CustomNSApplication
- ( void ) setMainMenu: ( NSMenu * ) menu { // hacer algo con el menú } @end
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 el código 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 evita la necesidad de protecciones de inclusión .
Compilación gcc de Linux
// ARCHIVO: hola.m
#import <Foundation/Foundation.h>
int main ( int argc , const char * argv []) { /* mi primer programa en Objective-C */ NSLog ( @"¡Hola, mundo! \n " ); return 0 ; }
$ # Compilar línea de comandos para gcc y compilador 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 a los problemas de programación.
- La delegación de métodos a otros objetos y la invocación remota se pueden implementar fácilmente utilizando categorías y reenvío de mensajes.
- El swizzling del puntero isa permite que las clases cambien en tiempo de ejecución. Normalmente se utiliza para depurar , donde los objetos liberados se convierten en objetos zombi cuyo único propósito es informar un error cuando alguien los llama. El swizzling también se utilizó en Enterprise Objects Framework para crear errores en la base de datos. [ cita requerida ] El swizzling lo utiliza actualmente Apple Foundation Framework para implementar la observación de valores clave.
Variantes del lenguaje
Objetivo-C++
Objective-C++ es una variante del lenguaje aceptada por el front-end de GNU Compiler Collection y Clang , que puede compilar archivos fuente que utilizan una combinación de sintaxis de C++ y 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:
- Una clase C++ no puede derivar de una clase Objective-C y viceversa.
- Los espacios de nombres de C++ no se pueden declarar dentro de una declaración de Objective-C.
- Las declaraciones de Objective-C pueden aparecer solo en el ámbito global, no dentro de un espacio de nombres de C++
- Las clases Objective-C no pueden tener variables de instancia de clases C++ que carezcan de un constructor predeterminado o que tengan uno o más métodos virtuales , [ cita requerida ] pero los punteros a objetos C++ se pueden usar como variables de instancia sin restricción (asignelos con new en el método -init).
- La semántica "por valor" de C++ no se puede aplicar a objetos Objective-C, a los que solo se puede acceder mediante punteros.
- Una declaración Objective-C no puede estar dentro de una declaración de plantilla C++ y viceversa. Sin embargo, los tipos Objective-C (por ejemplo,
Classname *) se pueden usar como parámetros de plantilla C++. - El manejo de excepciones de Objective-C y C++ es distinto; los manejadores de cada uno no pueden manejar excepciones del otro tipo. Como resultado, no se ejecutan los destructores de objetos. Esto se mitiga en los entornos de ejecución "Objective-C 2.0" recientes, ya que las excepciones de Objective-C se reemplazan por excepciones de C++ completamente (entorno de ejecución de Apple) o parcialmente cuando se vincula la biblioteca Objective-C++ (libobjc2 de GNUstep). [27]
- Los bloques Objective-C y las lambdas de C++11 son entidades distintas. Sin embargo, un bloque se genera de forma transparente en macOS cuando se pasa una lambda donde se espera un bloque. [28]
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 que incluye "recolección de basura moderna, mejoras de sintaxis, [29] mejoras de rendimiento en tiempo de ejecución, [30] 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 características 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 GNU Objective-C. [31]
El nombre Objective-C 2.0 representa una ruptura en el sistema de control de versiones del lenguaje, ya que la última versión de Objective-C para NeXT fue "objc4". [32] Este nombre de proyecto se mantuvo en la última versión del código fuente del entorno de ejecución de Objective-C heredado en Mac OS X Leopard (10.5). [33]
Recolección de basura
Objective-C 2.0 proporcionó un recolector de basura generacional y conservador opcional . Cuando se ejecutaba en modo compatible con versiones anteriores , el entorno de ejecución convertía las operaciones de conteo de referencias como "retain" y "release" en no-ops . Todos los objetos estaban sujetos a la recolección de basura cuando se habilitaba la recolección de basura. Los punteros C regulares podían calificarse con "__strong" para activar también las intercepciones del compilador de barrera de escritura subyacentes y, por lo tanto, participar en la recolección de basura. [34] También se proporcionó un subsistema de cero débil de modo que los punteros marcados como "__weak" se establecieran en cero cuando se recolecta el objeto (o, más simplemente, la memoria GC). El recolector de basura no existe en la implementación iOS de Objective-C 2.0. [35] La recolección de basura en Objective-C se ejecuta en un subproceso en segundo plano de baja prioridad y puede detenerse en eventos de usuario, con la intención de mantener la experiencia del usuario responsiva. [36]
La recolección de basura quedó obsoleta en Mac OS X v10.8 en favor del conteo automático de referencias (ARC). [37] Objective-C en iOS 7 que se ejecuta en ARM64 usa 19 bits de una palabra de 64 bits para almacenar el conteo de referencias, como una forma de punteros etiquetados . [38] [39]
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úblicas; es decir, declarar una variable de instancia como una propiedad proporciona a las clases externas acceso (posiblemente limitado, p. ej., solo lectura) a esa propiedad. Una propiedad puede declararse como "solo lectura" y puede proporcionarse con semántica de almacenamiento como assign, copyo retain. De forma predeterminada, las propiedades se consideran atomic, lo que da como resultado un bloqueo que evita que varios subprocesos accedan a ellas al mismo tiempo. Una propiedad puede declararse como nonatomic, lo que elimina este bloqueo.
@interface Persona : NSObject {
@public
NSString * nombre ; @private int edad ; }
@property ( copiar ) NSString * nombre ; @property ( solo lectura ) int edad ;
- ( id ) initWithAge: ( int ) edad ;
@end
Las propiedades se implementan mediante la @synthesizepalabra clave, que genera métodos getter (y setter, si no son de solo lectura) según 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 utilizando clang 3.1 o superior, todas las propiedades que no se declaran explícitamente con @dynamic, están marcadas readonlyo tienen métodos getter y setter implementados por el usuario completos se convertirán automáticamente en @synthesize'd implícitamente.
@implementation Persona
@synthesize nombre ;
- ( id ) initWithAge: ( int ) initAge { self = [ super init ]; if ( self ) { // NOTA: asignación directa de variable de instancia, no establecedor de propiedades age = initAge ; } return self ; }
- (int)age {
return age;
}
@end
Properties can be accessed using the traditional message passing syntax, dot notation, or, in Key-Value Coding, by name via the "valueForKey:"/"setValue:forKey:" methods.
Person *aPerson = [[Person alloc] initWithAge:53];
aPerson.name = @"Steve"; // NOTE: dot notation, uses synthesized setter,
// equivalent to [aPerson setName: @"Steve"];
NSLog(@"Access by message (%@), dot notation(%@), property name(% @) and "
"direct instance variable access(% @) ",
[aPerson name],
aPerson.name, [aPerson valueForKey:@"name"], aPerson -> name);
To use dot notation to invoke property accessors within an instance method, the self keyword should be used:
- (void)introduceMyselfWithProperties:(BOOL)useGetter {
NSLog(@"Hi, my name is %@.", (useGetter ? self.name : name));
// NOTE: getter vs. ivar access
}
A class or protocol's properties may be dynamically introspected.
int i;
int propertyCount = 0;
objc_property_t *propertyList =
class_copyPropertyList([aPerson class], &propertyCount);
for (i = 0; i < propertyCount; i++) {
objc_property_t *thisProperty = propertyList + i;
const char *propertyName = property_getName(*thisProperty);
NSLog(@"Person has a property: '%s'", propertyName);
}
Non-fragile instance variables
Objective-C 2.0 provides non-fragile instance variables where supported by the runtime (i.e. when building code for 64-bit macOS, and all iOS). Under the modern runtime, an extra layer of indirection is added to instance variable access, allowing the dynamic linker to adjust instance layout at runtime. This feature allows for two important improvements to Objective-C code:
- It eliminates the fragile binary interface problem; superclasses can change sizes without affecting binary compatibility.
- It allows instance variables that provide the backing for properties to be synthesized at runtime without them being declared in the class's interface.
Fast enumeration
Instead of using an NSEnumerator object or indices to iterate through a collection, Objective-C 2.0 offers the fast enumeration syntax. In Objective-C 2.0, the following loops are functionally equivalent, but have different performance traits.
// Using NSEnumerator
NSEnumerator *enumerator = [thePeople objectEnumerator];
Person *p;
while ((p = [enumerator nextObject]) != nil) {
NSLog(@"%@ is %i years old.", [p name], [p age]);
}
// Using indexes
for (int i = 0; i < [thePeople count]; i++) {
Person *p = [thePeople objectAtIndex:i];
NSLog(@"%@ is %i years old.", [p name], [p age]);
}
// Using fast enumeration
for (Person *p in thePeople) {
NSLog(@"%@ is %i years old.", [p name], [p age]);
}
Fast enumeration generates more efficient code than standard enumeration because method calls to enumerate over objects are replaced by pointer arithmetic using the NSFastEnumeration protocol.[40]
Class extensions
A class extension has the same syntax as a category declaration with no category name, and the methods and properties declared in it are added directly to the main class. It is mostly used as an alternative to a category to add methods to a class without advertising them in the public headers, with the advantage that for class extensions the compiler checks that all the privately declared methods are actually implemented.[41]
Implications for Cocoa development
All Objective-C applications developed for macOS that make use of the above improvements for Objective-C 2.0 are incompatible with all operating systems prior to 10.5 (Leopard). Since fast enumeration does not generate exactly the same binaries as standard enumeration, its use will cause an application to crash on Mac OS X version 10.4 or earlier.
Blocks
Blocks is a nonstandard extension for Objective-C (and C and C++) that uses special syntax to create closures. Blocks are only supported in Mac OS X 10.6 "Snow Leopard" or later, iOS 4 or later, and GNUstep with libobjc2 1.7 and compiling with clang 3.1 or later.[42]
#include <stdio.h>
#include <Block.h>
typedef int (^IntBlock)();
IntBlock MakeCounter(int start, int increment) {
__block int i = start;
return Block_copy( ^ {
int ret = i;
i += increment;
return ret;
});
}
int main(void) {
IntBlock mycounter = MakeCounter(5, 2);
printf("First call: %d\n", mycounter());
printf("Second call: %d\n", mycounter());
printf("Third call: %d\n", mycounter());
/* because it was copied, it must also be released */
Block_release(mycounter);
return 0;
}
/* Output:
First call: 5
Second call: 7
Third call: 9
*/
Modern Objective-C
Apple has added some additional features to Objective 2.0 over time. The additions only apply to the "Apple LLVM compiler", i.e. clang frontend of the language. Confusingly, the versioning used by Apple differs from that of the LLVM upstream; refer to Xcode § Toolchain versions for a translation to open-source LLVM version numbers.[43]
Automatic Reference Counting
Automatic Reference Counting (ARC) is a compile-time feature that eliminates the need for programmers to manually manage retain counts using retain and release.[44] Unlike garbage collection, which occurs at run time, ARC eliminates the overhead of a separate process managing retain counts. ARC and manual memory management are not mutually exclusive; programmers can continue to use non-ARC code in ARC-enabled projects by disabling ARC for individual code files. Xcode can also attempt to automatically upgrade a project to ARC.
ARC was introduced in LLVM 3.0. This translates to Xcode 4.2 (2011), or Apple LLVM compiler 3.0.[45]
Literals
NeXT and Apple Obj-C runtimes have long included a short-form way to create new strings, using the literal syntax @"a new string", or drop to CoreFoundation constants kCFBooleanTrue and kCFBooleanFalse for NSNumber with Boolean values. Using this format saves the programmer from having to use the longer initWithString or similar methods when doing certain operations.
When using Apple LLVM compiler 4.0 (Xcode 4.4) or later, arrays, dictionaries, and numbers (NSArray, NSDictionary, NSNumber classes) can also be created using literal syntax instead of methods.[46] (Apple LLVM compiler 4.0 translates to open source LLVM and Clang 3.1.)[47]
Example without literals:
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];
Example with literals:
NSArray *myArray = @[ object1, object2, object3 ];
NSDictionary *myDictionary1 = @{ @"key" : someObject };
NSDictionary *myDictionary2 = @{ key1: object1, key2: object2 };
NSNumber *myNumber = @(myInt);
NSNumber *mySumNumber = @(2+3);
NSNumber *myBoolNumber = @YES;
NSNumber *myIntegerNumber = @8;
However, different from string literals, which compile to constants in the executable, these literals compile to code equivalent to the above method calls. In particular, under manually reference-counted memory management, these objects are autoreleased, which requires added care when e.g., used with function-static variables or other kinds of globals.
Subscripting
When using Apple LLVM compiler 4.0 or later, arrays and dictionaries (NSArray and NSDictionary classes) can be manipulated using subscripting.[46] Subscripting can be used to retrieve values from indexes (array) or keys (dictionary), and with mutable objects, can also be used to set objects to indexes or keys. In code, subscripting is represented using brackets [ ].[48]
Example without subscripting:
id object1 = [someArray objectAtIndex:0];
id object2 = [someDictionary objectForKey:@"key"];
[someMutableArray replaceObjectAtIndex:0 withObject:object3];
[someMutableDictionary setObject:object4 forKey:@"key"];
Example with subscripting:
id object1 = someArray[0];
id object2 = someDictionary[@"key"];
someMutableArray[0] = object3;
someMutableDictionary[@"key"] = object4;
"Modern" Objective-C syntax (1997)
After the purchase of NeXT by Apple, attempts were made to make the language more acceptable to programmers more familiar with Java than Smalltalk. One of these attempts was introducing what was termed "Modern Syntax" for Objective-C at the time[49] (in contrast to the current, "classic" syntax). There was no change in behaviour, this was merely an alternative syntax. Instead of writing a method invocation like:
object = [[MyClass alloc] init];
[object firstLabel: param1 secondLabel: param2];
It was instead written as
object = (MyClass.alloc).init;
object.labels ( param1, param2 );
Similarly, declarations went from the form
-(void) firstLabel: (int)param1 secondLabel: (int)param2;
to
-(void) labels ( int param1, int param2 );
This "modern" syntax is no longer supported in current dialects of the Objective-C language.
mulle-objc
The mulle-objc project is another re-implementation of Objective-C. It supports GCC or Clang/LLVM compilers as backends. It diverges from other runtimes in terms of syntax, semantics and ABI compatibility. It supports Linux, FreeBSD, and Windows.
Portable Object Compiler
Besides the GCC/NeXT/Apple implementation, which added several extensions to the original Stepstone implementation, another free, open-source Objective-C implementation called the Portable Object Compiler also exists.[50] The set of extensions implemented by the Portable Object Compiler differs from the GCC/NeXT/Apple implementation; in particular, it includes Smalltalk-like blocks for Objective-C, while it lacks protocols and categories, two features used extensively in OpenStep and its derivatives and relatives. Overall, POC represents an older, pre-NeXT stage in the language's evolution, roughly conformant to Brad Cox's 1991 book.
It also includes a runtime library called ObjectPak, which is based on Cox's original ICPak101 library (which in turn derives from the Smalltalk-80 class library), and is quite radically different from the OpenStep FoundationKit.
GEOS Objective-C
The PC GEOS system used a programming language known as GEOS Objective-C or goc;[51] despite the name similarity, the two languages are similar only in overall concept and the use of keywords prefixed with an @ sign.
Clang
The Clang compiler suite, part of the LLVM project, implements Objective-C and other languages. After GCC 4.3 (2008) switched to GPLv3, Apple abandoned it in favor of clang, a compiler it has more legal power to modify. As a result, many of the modern Objective-C language features are supported only by Clang.
Apple's versioning scheme for its clang-based "LLVM compiler" differs from the LLVM's open-source versioning. See Xcode § Toolchain versions for a translation[43]
GNU, GNUstep, and WinObjC
The GNU project has, for a long time, been interested in a platform to port NeXT and Obj-C programs to. The ChangeLog for the libobjc directory in GCC suggests that it existed before 1998 (GCC 2.95), and its README further points at a rewrite in 1993 (GCC 2.4).[52]
The NeXT frontend source code was released since it was made as part of GCC, released GNU General Public License which forces ones making derivative works to do so.[when?] Apple continued this tradition in releasing its fork of GCC up to 4.2.1, after which they abandoned the compiler. GCC maintainers took in the changes, but did not invest much in supporting newer features such as the Objective-C 2.0 language.[32]: Which compiler
The GNUstep developers, interested in the new language, forked the GCC libobjc to a project independent of GCC called libobjc2 in 2009. They also arranged for the runtime to be used with Clang to take advantage of the new language syntax.[32]: Which compiler GCC moved slowly at the same time, but at GCC 4.6.0 (2011) they have moved on to Objective-C 2.0 in their libobjc as well.[31][53] GNUstep documentation suggest that the GCC implementation still lacks support for blocks, non-fragile variables, and the newer ARC.[32]: Which runtime
Microsoft forked libobjc2 into a part of WinObjC, the iOS bridge for Universal Windows Platform, in 2015. Combined with its own implementation of Cocoa Touch and underlying APIs, the project allows the reuse of iOS Application code inside of UWP apps.[54]
On Windows, Objective-C Development tools are provided for download on GNUStep's website. The GNUStep Development System consists of the following packages: GNUstep MSYS System, GNUstep Core, GNUstep Devel, GNUstep Cairo, ProjectCenter IDE (Like Xcode, but not as complex), Gorm (Interface Builder Like Xcode NIB builder). These binary installers have not been updated since 2016,[55] so it could be a better idea to just install by building under Cygwin or MSYS2 instead.
Library use
Objective-C today is often used in tandem with a fixed library of standard objects (often known as a "kit" or "framework"), such as Cocoa, GNUstep or ObjFW. These libraries often come with the operating system: the GNUstep libraries often come with Linux-based distributions and Cocoa comes with macOS. The programmer is not forced to inherit functions from the existing base class (NSObject – OFObject). Objective-C allows for the declaration of new root classes that do not inherit any existing function. Originally, Objective-C-based programming environments typically offered an Object class as the base class from which almost all other classes inherited. With the introduction of OpenStep, NeXT created a new base class named NSObject, which offered additional features over Object (an emphasis on using object references and reference counting instead of raw pointers, for example). Almost all classes in Cocoa inherit from NSObject.
Not only did the renaming serve to differentiate the new default behavior of classes within the OpenStep API, but it allowed code that used Object—the original base class used on NeXTSTEP (and, more or less, other Objective-C class libraries)—to co-exist in the same runtime with code that used NSObject (with some limitations). The introduction of the two letter prefix also became a simplistic form of namespaces, which Objective-C lacks. Using a prefix to create an informal packaging identifier became an informal coding standard in the Objective-C community, and continues to this day.
More recently, package managers have started appearing, such as CocoaPods, which aims to be both a package manager and a repository of packages. A lot of open-source Objective-C code that was written in the last few years can now be installed using CocoaPods.
Analysis of the language
Objective-C implementations use a thin runtime system written in C[citation needed], which adds little to the size of the application. In contrast, most object-oriented systems at the time that it was created used large virtual machine runtimes. Programs written in Objective-C tend to be not much larger than the size of their code and that of the libraries (which generally do not need to be included in the software distribution), in contrast to Smalltalk systems where a large amount of memory was used just to open a window. Objective-C applications tend to be larger than similar C or C++ applications because Objective-C dynamic typing does not allow methods to be stripped or inlined. Since the programmer has such freedom to delegate, forward calls, build selectors on the fly, and pass them to the runtime system, the Objective-C compiler cannot assume it is safe to remove unused methods or to inline calls.
Likewise, the language can be implemented atop extant C compilers (in GCC, first as a preprocessor, then as a module) rather than as a new compiler. This allows Objective-C to leverage the huge existing collection of C code, libraries, tools, etc. Existing C libraries can be wrapped in Objective-C wrappers to provide an OO-style interface. In this aspect, it is similar to GObject library and Vala language, which are widely used in development of GTK applications.
All of these practical changes lowered the barrier to entry, likely the biggest problem for the widespread acceptance of Smalltalk in the 1980s.
A common criticism is that Objective-C does not have language support for namespaces. Instead, programmers are forced to add prefixes to their class names, which are traditionally shorter than namespace names and thus more prone to collisions. As of 2007, all macOS classes and functions in the Cocoa programming environment are prefixed with "NS" (e.g. NSObject, NSButton) to identify them as belonging to the macOS or iOS core; the "NS" derives from the names of the classes as defined during the development of NeXTSTEP.
Since Objective-C is a strict superset of C, it does not treat C primitive types as first-class objects.
Unlike C++, Objective-C does not support operator overloading. Also unlike C++, Objective-C allows an object to directly inherit from only one class (forbidding multiple inheritance). However, in most cases, categories and protocols may be used as alternative ways to achieve the same results.
Because Objective-C uses dynamic runtime typing and because all method calls are function calls (or, in some cases, syscalls), many common performance optimizations cannot be applied to Objective-C methods (for example: inlining, constant propagation, interprocedural optimizations, and scalar replacement of aggregates). This limits the performance of Objective-C abstractions relative to similar abstractions in languages such as C++ where such optimizations are possible.
Memory management
The first versions of Objective-C did not support garbage collection. At the time this decision was a matter of some debate, and many people considered long "dead times" (when Smalltalk performed collection) to render the entire system unusable. Some 3rd party implementations have added this feature (most notably GNUstep using Boehm), and Apple has implemented it as of Mac OS X v10.5.[56] However, in more recent versions of macOS and iOS, garbage collection has been deprecated in favor of Automatic Reference Counting (ARC), introduced in 2011.
With ARC, the compiler inserts retain and release calls automatically into Objective-C code based on static code analysis. The automation relieves the programmer of having to write in memory management code. ARC also adds weak references to the Objective-C language.[57]
Philosophical differences between Objective-C and C++
The design and implementation of C++ and Objective-C represent fundamentally different approaches to extending C.
In addition to C's style of procedural programming, C++ directly supports certain forms of object-oriented programming, generic programming, and metaprogramming. C++ also comes with a large standard library that includes several container classes. Similarly, Objective-C adds object-oriented programming, dynamic typing, and reflection to C. Objective-C does not provide a standard library per se, but in most places where Objective-C is used, it is used with an OpenStep-like library such as OPENSTEP, Cocoa, or GNUstep, which provides functions similar to C++'s standard library.
One notable difference is that Objective-C provides runtime support for reflective programming features, whereas C++ adds only a small amount of runtime support to C. In Objective-C, an object can be queried about its own properties, e.g., whether it will respond to a certain message. In C++, this is not possible without the use of external libraries.
The use of reflection is part of the wider distinction between dynamic (run-time) features and static (compile-time) features of a language. Although Objective-C and C++ each employ a mix of both features, Objective-C favors run-time decisions while C++ favors compile-time decisions. The tension between dynamic and static programming involves many of the classic trade-offs in programming: dynamic features add flexibility, static features add speed and type checking.
Generic programming and metaprogramming can be implemented in both languages using runtime polymorphism (dynamic dispatch). In C++, this takes the form of virtual functions and runtime type identification, while Objective-C offers dynamic typing and reflection. Both Objective-C and C++ support compile-time polymorphism (generic functions), with Objective-C adding this feature in 2015.
See also
- C (programming language)
- C++
- Comparison of programming languages
- Comparison with COM, GObject, SOM, Windows Runtime, XPCOM
- Swift (programming language)
- Xcode
- WinObjC (aka: Windows Bridge for iOS)
References
- ^ "Runtime Versions and Platforms". Developer.apple.com. Archived from the original on July 20, 2016. Retrieved December 24, 2017.
- ^ Lattner, Chris (June 3, 2014). "Chris Lattner's Homepage". Chris Lattner. Archived from the original on June 4, 2014. Retrieved June 3, 2014.
The Swift language is the product of tireless effort from a team of language experts, documentation gurus, compiler optimization ninjas, and an incredibly important internal dogfooding group who provided feedback to help refine and battle-test ideas. Of course, it also greatly benefited from the experiences hard-won by many other languages in the field, drawing ideas from Objective-C, Rust, Haskell, Ruby, Python, C#, CLU, and far too many others to list.
- ^ a b "App Frameworks". Apple. June 2014. Archived from the original on February 16, 2019. Retrieved February 13, 2019.
- ^ Singh, Amit (December 2003). "A Brief History of Mac OS X". Mac OS X Internals. Archived from the original on May 14, 2012. Retrieved June 11, 2012.
- ^ Garling, Caleb. "iPhone Coding Language Now World's Third Most Popular". Wired. Archived from the original on September 9, 2013. Retrieved May 20, 2013.
- ^ Wentk, Richard (2009). Cocoa: Volume 5 of Developer Reference Apple Developer Series. John Wiley and Sons. ISBN 978-0-470-49589-6. Archived from the original on February 16, 2017. Retrieved July 22, 2016.
- ^ Biancuzzi, Federico; Warden, Shane (2009). Masterminds of Programming. O'Reilly Media, Inc. pp. 242–246. ISBN 978-0-596-51517-1. Archived from the original on February 17, 2017. Retrieved July 22, 2016.
- ^ Cox, Brad (1983). "The object oriented pre-compiler: programming Smalltalk-80 methods in C language". ACM SIGPLAN Notices. 18 (1). New York, NY: ACM. doi:10.1145/948093.948095. S2CID 6975032. Retrieved February 17, 2011.
- ^ "Common Lisp and Readline". GitHub. Archived from the original on September 6, 2014. Retrieved September 15, 2014.
The issue first arose when NeXT proposed to distribute a modified GCC in two parts and let the user link them. Jobs asked me whether this was lawful. It seemed to me at the time that it was, following reasoning like what you are using; but since the result was very undesirable for free software, I said I would have to ask the lawyer. What the lawyer said surprised me; he said that judges would consider such schemes to be "subterfuges" and would be very harsh toward them. He said a judge would ask whether it is "really" one program, rather than how it is labeled. So I went back to Jobs and said we believed his plan was not allowed by the GPL. The direct result of this is that we now have an Objective-C front end. They had wanted to distribute the Objective C parser as a separate proprietary package to link with the GCC back end, but since I didn't agree this was allowed, they made it free.
- ^ "GNUstep: Introduction". GNUstep developers/GNU Project. Archived from the original on August 6, 2012. Retrieved July 29, 2012.
- ^ "Kresten Krab Thorup | LinkedIn". www.linkedin.com. Archived from the original on July 15, 2014. Retrieved June 23, 2016.
- ^ "Write Objective-C Code". apple.com. April 23, 2013. Archived from the original on December 24, 2013. Retrieved December 22, 2013.
- ^ "Objective-C Boot Camp". Archived from the original on February 11, 2018. Retrieved February 11, 2018.
Objective-C is a strict superset of ANSI C
- ^ "Examining Objective-C". Archived from the original on September 4, 2014. Retrieved September 4, 2014.
Objective-C is an object-oriented strict superset of C
- ^ Lee, Keith (September 3, 2013). Pro Objective-C. Apress. ISBN 9781430250500. Archived from the original on May 14, 2018. Retrieved December 24, 2017 – via Google Books.
- ^ "Tags for Objective-C Headers". Archived from the original on April 1, 2017. Retrieved February 11, 2018.
Objective-C is a superset of C
- ^ "AppScan Source 8.7 now available". Archived from the original on February 3, 2017. Retrieved February 11, 2018.
The Objective-C programming language is a superset of the C programming language
- ^ Apple, Inc. (October 19, 2009). "Dynamic Method Resolution". Objective-C Runtime Programming Guide. Archived from the original on September 7, 2010. Retrieved November 25, 2014.
- ^ Apple, Inc. (October 19, 2009). "Avoiding Messaging Errors". The Objective-C Programming Language. Archived from the original on September 8, 2010.
- ^ "objc_msgSend - Objective-C Runtime". Apple Developer Documentation. Retrieved February 10, 2020.
- ^ "Messaging with the GNU Objective-C runtime". Using the GNU Compiler Collection (GCC). Retrieved February 10, 2020.
- ^ "Category". Apple Developer (Cocoa Core Competencies).
- ^ Dalrymple, Mark; Knaster, Scott (June 27, 2012). Learn Objective-C on the Mac. Apress. p. 9. ISBN 9781430241881.
The .m extension originally stood for "messages" when Objective-C was first introduced, referring to a central feature of Objective-C
- ^ "Objective-C Runtime Programming Guide". Apple Inc. Archived from the original on April 4, 2014. Retrieved October 21, 2013.
- ^ "ACM SIGGRAPH 1983 Issue 8 - Smalltalk". Archived from the original on 15 April 2009. Retrieved 7 October 2008.
- ^ "Extension Methods (C# Programming Guide)". Microsoft. October 2010. Archived from the original on July 11, 2011. Retrieved July 10, 2011.
- ^ "Using C++ With Objective-C". Mac OS X Reference Library. Archived from the original on September 5, 2010. Retrieved February 10, 2010.
- ^ "Clang Language Extensions — Clang 3.5 documentation". Clang.llvm.org. Archived from the original on February 24, 2014. Retrieved April 16, 2014.
- ^ "Objective-C 2.0: more clues". Lists.apple.com. August 10, 2006. Archived from the original on June 18, 2009. Retrieved May 30, 2010.
- ^ "Re: Objective-C 2.0". Lists.apple.com. Archived from the original on November 24, 2010. Retrieved May 30, 2010.
- ^ a b "GCC 4.6 Release Series — Changes, New Features, and Fixes : GNU Project : Free Software Foundation". Gcc.gnu.org. Archived from the original on January 5, 2018. Retrieved December 24, 2017.
- ^ a b c d "ObjC2 FAQ". GNUstep. Retrieved January 6, 2020.
- ^ "Source Browser: objc4, 756.2". Apple Open Source. Retrieved January 6, 2020.
- ^ Garbage Collection Programming Guide: Garbage Collection API Archived June 9, 2012, at the Wayback Machine (Apple developer website - search for "__strong")
- ^ "Garbage Collection Programming Guide: Introduction to Garbage Collection". Apple Inc. October 3, 2011. Archived from the original on June 9, 2012. Retrieved December 23, 2011.
- ^ "Leopard Technology Series for Developers: Objective-C 2.0 Overview". Apple Inc. November 6, 2007. Archived from the original on July 24, 2010. Retrieved May 30, 2010.
- ^ "Transitioning to ARC Release Notes". Apple Inc. July 17, 2012. Archived from the original on June 9, 2012. Retrieved August 26, 2012.
- ^ Mike Ash. "Friday Q&A 2013-09-27: ARM64 and You". mikeash.com. Archived from the original on April 26, 2014. Retrieved April 27, 2014.
- ^ "Hamster Emporium: [objc explain]: Non-pointer isa". Sealiesoftware.com. September 24, 2013. Archived from the original on June 3, 2014. Retrieved April 27, 2014.
- ^ Apple, Inc. (2009). "Fast Enumeration". apple.com. Archived from the original on December 17, 2009. Retrieved December 31, 2009.
- ^ Free Software Foundation, Inc. (2011). "GCC 4.6 Release Series – Changes, New Features, and Fixes". Gcc.gnu.org. Archived from the original on December 2, 2013. Retrieved November 27, 2013.
- ^ "Blocks Programming Topics – Mac Developer Library". Apple Inc. March 8, 2011. Archived from the original on June 9, 2012. Retrieved November 28, 2012.
- ^ a b "Objective-C Automatic Reference Counting (ARC) — Clang 11 documentation". Clang documentation. Retrieved February 20, 2020.
For now, it is sensible to version this document by the releases of its sole implementation (and its host project), clang. "LLVM X.Y" refers to an open-source release of clang from the LLVM project. "Apple X.Y" refers to an Apple-provided release of the Apple LLVM Compiler.
- ^ "Transitioning to ARC". Apple Inc. Archived from the original on September 7, 2011. Retrieved October 8, 2012.
- ^ "LLVM 3.0 Release Notes". releases.llvm.org.
- ^ a b "Programming with Objective-C: Values and Collections". Apple Inc. Archived from the original on September 7, 2011. Retrieved October 8, 2012.
- ^ "Clang 3.1 Release Notes". releases.llvm.org.
- ^ "Objective-C Literals — Clang 3.5 documentation". Clang.llvm.org. Archived from the original on June 6, 2014. Retrieved April 16, 2014.
- ^ Rhapsody Developer's Guide, AP Professional, 1997, pp. 76–84
- ^ "Portable Object Compiler". Users.pandora.be. January 1, 1970. Archived from the original on August 2, 2008. Retrieved May 30, 2010.
- ^ "Breadbox Computer Company LLC homepage". Archived from the original on July 27, 2011. Retrieved December 8, 2010.
- ^ "gcc/libobjc". GitHub. gcc-mirror. January 6, 2020. Retrieved January 6, 2020.
he runtime has been completely rewritten in gcc 2.4. The earlier runtime had several severe bugs and was rather incomplete.
- ^ "GNU Objective-C runtime API". Using GCC. Retrieved January 6, 2020.
- ^ "WinObjC en GitHub". GitHub . Archivado desde el original el 2 de diciembre de 2017 . Consultado el 13 de febrero de 2018 .
- ^ "Instalador de GNUStep". Archivado desde el original el 17 de febrero de 2018 . Consultado el 14 de febrero de 2018 .
- ^ Apple, Inc. (22 de agosto de 2006). «Mac OS X Leopard – Xcode 3.0». apple.com. Archivado desde el original el 24 de octubre de 2007. Consultado el 22 de agosto de 2006 .
- ^ "Notas de la versión de transición a ARC". Biblioteca para desarrolladores de iOS . Developer.apple.com. Archivado desde el original el 7 de septiembre de 2011 . Consultado el 16 de abril de 2014 .
Lectura adicional
- Cox, Brad J. (1991). Programación orientada a objetos: un enfoque evolutivo . Addison Wesley. ISBN 0-201-54834-8.
Enlaces externos
- Programación con Objective-C, de Apple (13-12-2012)
- El lenguaje de programación Objective-C de Apple (11/10/2011)
- Guía de programación en tiempo de ejecución Objective-C , de Apple (19 de octubre de 2009)
- Manual de programación básica de Objective-C GNUstep
- Objective-C por Brad Cox
- Preguntas frecuentes sobre Objective-C
- Ejemplo de Objective-C
