Objective-C deriva su sintaxis de objeto de Smalltalk. Toda la sintaxis para operaciones no orientadas a objetos (incluyendo variables primitivas, preprocesamiento, expresiones, declaraciones de funciones y llamadas a funciones) son idénticas a las de C, mientras que la sintaxis para características orientadas a objetos es una implementación de mensajería de estilo Smalltalk.
MessagesEdit
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 al modelo de Programación Al 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 nombre del método está en la mayoría de los casos vinculado 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 interpretando el mensaje., Un método es identificado por un selector o SEL – un identificador único para cada nombre de mensaje, a menudo solo una cadena terminada en NUL que representa su nombre-y resuelto a 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 tipo. El objeto al que se dirige el mensaje — el receptor — no está garantizado para responder a un mensaje, y si no lo hace, plantea una excepción.,
enviar el método message al objeto apuntado por el puntero obj requeriría el siguiente código en C++:
obj->method(argument);
en Objective-C, esto se escribe de la siguiente manera:
;
la llamada «method» se traduce el compilador de objc_msgsend(ID SELF, sel op, …) familia de funciones en tiempo de ejecución. Diferentes implementaciones manejan adiciones modernas como super. En las familias GNU esta función se llama objc_msg_sendv, pero ha sido obsoleta en favor de un sistema de búsqueda Moderno Bajo objc_msg_lookup.,
Ambos estilos de programación tienen sus fortalezas y debilidades. La programación orientada a objetos en el estilo Simula (C++) permite una herencia múltiple y una ejecución más rápida mediante el uso del enlace 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 como se usa en Objective-C permite que los mensajes no se implementen, con el método resuelto a su implementación en tiempo de ejecución., Por ejemplo, se puede enviar un mensaje a una colección de objetos, a los que solo se espera que respondan algunos, sin temor a producir errores de tiempo de ejecución. El paso de mensajes tampoco requiere que un objeto sea definido en tiempo de compilación. Todavía se requiere una implementación para que el método sea llamado en el objeto derivado. (Consulte la sección de escritura dinámica a continuación para obtener más ventajas de la encuadernación dinámica (tardía).)
Interfaces e implementacionesedit
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 cabecera, normalmente con sufijo .h, son similares a los archivos de encabezado C, mientras que los archivos de implementación (método), normalmente con sufijo .m, puede ser muy similar a los archivos de código C.
InterfaceEdit
esto es análogo a las declaraciones de clase utilizadas 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 cabecera después del nombre de la clase, por ejemplo, Ball.,h contendría la interfaz para la bola de la clase.
una declaración de interfaz toma la forma:
en lo anterior, los signos más denotan métodos de clase, o métodos que pueden ser invocados en la propia clase (no en una instancia), y los signos menos denotan métodos de instancia, que solo pueden ser invocados 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 de c++:
tenga en cuenta que instanceMethod2With2Parameters:param2_callName: demuestra la intercalación de segmentos Selectores con expresiones de argumento, para las que no hay 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 (instancetype). El tipo de retorno predeterminado es el ID de tipo genérico Objective-C.,
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 seguidos del tipo de argumento esperado entre paréntesis y el nombre del argumento. La etiqueta se puede omitir.
una derivada de la definición de la interfaz es la categoría, que permite agregar métodos a las clases existentes.
ImplementationEdit
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».
@implementation classname+ (return_type)classMethod { // implementation}- (return_type)instanceMethod { // implementation}@end
Métodos se escriben con sus declaraciones de interfaz.La comparación de Objective-C y C:
- (int)method:(int)i { return ;}
int function(int i) { return square_root(i);}
La sintaxis permite pseudo-nomenclatura de los argumentos.
Las representaciones internas de un método varían entre diferentes implementaciones de Objective-C., Si myColor es de la clase Color, El método de instancia-changeColorToRed: green: blue: podría etiquetarse internamente _i_Color_changeColorToRed_green_blue. La i se refiere a un método de instancia, con los nombres de la clase y luego del método añadidos 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, los nombres internos de la función rara vez se utilizan directamente. Generalmente, los mensajes se convierten en llamadas a funciones definidas en la biblioteca de tiempo de ejecución de Objective-C., No se conoce 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óneditar
Una vez que se escribe una clase Objective-C, se puede instanciar. Esto se hace primero asignando 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 se deben realizar con una línea de código para que nunca haya un objeto asignado que no haya sufrido inicialización (y porque no es prudente mantener el resultado intermedio ya que -init
puede devolver un objeto diferente al que se llama).,
instanciación con el inicializador predeterminado sin parámetro:
MyObject *foo = init];
instanciación con un inicializador personalizado:
MyObject *foo = initWithString:myString];
en el caso de que no se realice una inicialización personalizada, el método «nuevo» a menudo se puede usar en lugar de los mensajes alloc-init:
MyObject *foo = ;
también, algunas clases implementan inicializadores de métodos de clase., Como +new
, se combinan +alloc
y -init
, pero a diferencia de +new
, devuelven un autoreleased instancia. Algunos inicializadores de métodos de clase toman parámetros:
MyObject *foo = ;MyObject *bar = ;
el mensaje alloc asigna suficiente memoria para contener todas las variables de instancia de un objeto, establece todas las variables de instancia a cero valores y convierte la memoria en una instancia de la clase; en ningún momento durante la inicialización es la memoria 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)init { self = ; if (self) { // perform initialization of object here } return self;}
en el ejemplo anterior, observe el tipo de retorno id
. Este tipo significa «puntero a cualquier objeto» en Objective-C (consulte la sección de escritura dinámica).
el patrón inicializador se utiliza para asegurar que el objeto es inicializado correctamente por su superclase antes de que el método init realice su inicialización., Realiza las siguientes acciones:
- self = envía a la instancia de superclase un mensaje init y asigna el resultado a self (puntero al objeto actual).
- if (self)comprueba si el puntero de objeto devuelto es válido antes de realizar cualquier inicialización.
- return selfretrata el valor de self al llamante.
un puntero de objeto no válido tiene el valor nil; las sentencias condicionales como «if» tratan a nil como un puntero nulo, por lo que el código de inicialización no se ejecutará si 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 mensaje «release» a self, y devolver nil Para indicar que la inicialización falló. Cualquier comprobació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 realice correctamente.
si una clase tiene más de un método de inicialización, solo uno de ellos (el» inicializador designado») necesita seguir este patrón; Otros deberían llamar al inicializador designado en lugar del inicializador de superclase.,
Protocoloseditar
en otros lenguajes de programación, estos se llaman «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 alcanzable ya sea como una clase base abstracta heredada múltiple en c++, o como una «interfaz» (como en Java y C#). Objective-C hace uso de protocolos ad hoc llamados protocolos informales y protocolos reforzados por compiladores 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 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 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 reflexión) y, de ser 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 implementar. Las versiones de Objective-C anteriores a la 2.0 requerían que una clase implementara todos los métodos en un protocolo que declarara adoptar; el compilador emitirá un error si la clase no implementa todos los métodos de sus protocolos declarados. Objetivo-C 2.,0 Se agregó soporte para marcar ciertos métodos en un protocolo como opcionales, y el compilador no hará cumplir la implementación de métodos opcionales.
se debe declarar una clase para implementar ese protocolo para que se diga 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 los llamantes que las clases que se ajustan al 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)lock;- (void)unlock;@end
denota que no es la idea abstracta de bloqueo. Al indicar en la definición de la clase que el protocolo está implementado,
@interface NSLock : NSObject <NSLocking>// ...@end
las instancias de NSLock afirman que proporcionarán una implementación para los dos métodos de instancia.
Dynamic typingEdit
Objective-C, al igual que Smalltalk, puede utilizar la tipificación dinámica: a un objeto se le puede enviar un mensaje que no está especificado en su interfaz., Esto puede permitir una mayor flexibilidad, ya que permite a un objeto «capturar» un mensaje y enviar el mensaje a un objeto diferente que puede responder al mensaje adecuadamente, o del mismo modo enviar el mensaje a otro objeto. Este comportamiento se conoce como reenvío o delegación de mensajes (Ver más abajo). Alternativamente, se puede usar un manejador de errores en caso de que el mensaje no se pueda reenviar. Si un objeto no reenvía un mensaje, no responde a él ni maneja un error, el sistema generará una excepción de tiempo de ejecución., Si los mensajes se envían a nil (el puntero de objeto nulo), se ignorarán silenciosamente o generarán una excepción, dependiendo de las opciones del compilador.
también se puede añadir información estática a las variables. Esta información se comprueba en tiempo de compilación. En las cuatro declaraciones siguientes, se proporciona información de tipo cada vez más específica. Las sentencias son equivalentes en tiempo de ejecución, pero la información adicional permite al compilador advertir al programador si el argumento pasado no coincide con el tipo especificado.,
- (void)setMyValue:(id)foo;
En la instrucción anterior, foo pueden ser de cualquier clase.
- (void)setMyValue:(id<NSCopying>)foo;
en la instrucción anterior, foo puede ser una instancia de cualquier clase que cumpla con el protocolo NSCopying
.
- (void)setMyValue:(NSNumber *)foo;
En la instrucción anterior, foo debe ser una instancia de la NSNumber clase.
- (void)setMyValue:(NSNumber<NSCopying> *)foo;
En la instrucción anterior, foo debe ser una instancia de la NSNumber clase, y debe ajustarse a la etiqueta NSCopying
protocolo.,
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 cambian porque no forman parte del sistema de objetos. Esta decisión difiere del modelo de objetos c++, donde las estructuras y las clases están unidas.
ForwardingEdit
Objective-C permite el envío de un mensaje a un objeto que no puede responder., En lugar de responder o simplemente dejar caer el mensaje, un objeto puede reenviar el mensaje a un objeto que puede responder. El reenvío se puede utilizar para simplificar la implementación de ciertos patrones de diseño, como el patrón observador o el patrón 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 ser sobrescrito, ya que este método simplemente realiza una acción basada en el selector y los argumentos., Observe el tipo SEL
, que es el tipo de mensajes en Objective-C.
Nota: En OpenStep, Cocoa y GNUstep, los frameworks comúnmente utilizados de Objective-C, uno no usa la clase Object. El método – (void)forwardInvocation: (NSInvocation *)anInvocation de la clase NSObject se utiliza para hacer el reenvío.
ExampleEdit
Aquí hay un ejemplo de un programa que demuestra los conceptos básicos de reenvío.
Forwarder.H Promotor.m Destinatario.h
#import <objc/Object.h>// A simple Recipient object.@interface Recipient : Object- (id)hello;@end
Destinatario.m
#import "Recipient.h"@implementation Recipient- (id)hello { printf("Recipient says hello!\n"); return self;}@end
main.,M
NotesEdit
Cuando se compila usando gcc, el compilador informa:
el compilador está reportando el punto hecho anteriormente, que el reenviador no responde a los mensajes de Hola. En esta circunstancia, es Seguro ignorar la advertencia desde que se implementó el reenvío. Ejecutar el programa produce esta salida:
$ ./a.outRecipient says hello!
CategoriesEdit
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 descomponerlo en partes más pequeñas. Objective-C tomó prestado y extendió 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 recompilar 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 cadena, podría agregarse sin modificar el código fuente de la cadena.
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 los métodos existentes., Esta característica se puede usar para corregir errores en otras clases reescribiendo sus métodos, o para causar 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 diferentes firmas de método, 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 permitió la adición de variables también. Otros lenguajes han utilizado soluciones basadas en prototipos en su lugar, el más notable es Self.
El C# y Visual Basic.,Los lenguajes 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 «monkey patching».
Logtalk implementa un concepto de categorías (como entidades de primera clase) que subsume la funcionalidad de las categorías Objective-C (Las categorías 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 Logtalk puede ser importada virtualmente por cualquier número de clases y prototipos).,
ejemplo uso de categoriesEdit
este ejemplo construye una clase entera, definiendo primero una clase básica con solo métodos de acceso implementados, y agregando dos categorías, aritmética y visualización, 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. La implementación de estos accesores 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 sobreescritura de subclases, también conocida como parcheo de monos. Los protocolos informales se implementan como una categoría en la clase base NSObject. Por convención, los archivos que contienen categorías que extienden clases base tomarán el nombre BaseClass + ExtensionClass.h.
Entero.h
#import <objc/Object.h>@interface Integer : Object { int integer;}- (int)integer;- (id)integer:(int)_integer;@end
Integer.m Entero+Aritmética.h
#import "Integer.h"@interface Integer (Arithmetic)- (id) add: (Integer *) addend;- (id) sub: (Integer *) subtrahend;@end
Integer+Aritmética.m Entero+Pantalla.h
#import "Integer.h"@interface Integer (Display)- (id) showstars;- (id) showint;@end
Integer + Display.m main.,M
NotesEdit
la compilación se realiza, por ejemplo, mediante:
gcc -x objective-c main.m Integer.m Integer+Arithmetic.m Integer+Display.m -lobjc
Se puede experimentar omitiendo el #import «Integer+aritmética.h » y líneas y omitiendo entero + aritmética.m en Compilación. El programa seguirá funcionando. Esto significa que es posible mezclar y emparejar categorías agregadas si es necesario; si una categoría no necesita tener alguna habilidad, simplemente no se puede compilar.
PosingEdit
Objective-C permite que una clase reemplace completamente a otra clase dentro de un programa. Se dice que la clase reemplazante «se hace pasar por» la clase objetivo.,
class posing fue declarado OBSOLETO 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 swizzling de métodos en categorías, que intercambia la implementación de un método con otra que tiene la misma firma.
Para las versiones siguen apoyando posando, todos los mensajes enviados a la clase de destino son recibidas por el planteamiento de la clase. Hay varias restricciones:
- Una clase solo puede presentarse como una de sus superclases directas o indirectas.,
- La Clase posing no debe definir ninguna variable de instancia nueva que esté ausente de 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 presentación.
posar, de manera similar con las categorías, permite un aumento global de las clases existentes. Posing permite dos características ausentes de las categorías:
- Una clase posing puede llamar a métodos anulados a través de super, incorporando así la implementación de la clase objetivo.
- Una clase posing puede anular métodos definidos en categorías.,
por ejemplo,
esto intercepta cada invocación de setMainMenu a NSApplication.
#importEdit
en el lenguaje C, la directiva pre-compilación #include
siempre hace que el contenido de un archivo se inserte en el origen en ese punto. Objective-C tiene la directiva #import
, equivalente excepto que cada archivo se incluye solo una vez por unidad de compilación, obviando la necesidad de incluir guardias.