Guía rápida de Objective-C
Objective-C es un lenguaje de propósito general que se desarrolla sobre el lenguaje de programación C al agregar características del lenguaje de programación Small Talk, lo que lo convierte en un lenguaje orientado a objetos. Se utiliza principalmente en el desarrollo de sistemas operativos iOS y Mac OS X, así como en sus aplicaciones.
Inicialmente, Objective-C fue desarrollado por NeXT para su sistema operativo NeXTSTEP de quien fue adquirido por Apple para su iOS y Mac OS X.
Programación orientada a objetos
Es totalmente compatible con la programación orientada a objetos, incluidos los cuatro pilares del desarrollo orientado a objetos:
- Encapsulation
- Ocultación de datos
- Inheritance
- Polymorphism
Código de ejemplo
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSLog (@"hello world");
[pool drain];
return 0;
}
Marco de la Fundación
Foundation Framework proporciona un gran conjunto de características y se enumeran a continuación.
Incluye una lista de tipos de datos extendidos como NSArray, NSDictionary, NSSet, etc.
Consiste en un amplio conjunto de funciones que manipulan archivos, cadenas, etc.
Proporciona funciones para el manejo de URL, utilidades como formato de fecha, manejo de datos, manejo de errores, etc.
Objetivo de aprendizaje-C
Lo más importante que debe hacer al aprender Objective-C es concentrarse en los conceptos y no perderse en los detalles técnicos del lenguaje.
El propósito de aprender un lenguaje de programación es convertirse en un mejor programador; es decir, volverse más eficaces en el diseño e implementación de nuevos sistemas y en el mantenimiento de los antiguos.
Uso de Objective-C
Objective-C, como se mencionó anteriormente, se usa en iOS y Mac OS X. Tiene una gran base de usuarios de iOS y un gran número de usuarios de Mac OS X. Y dado que Apple se enfoca en la calidad primero y es maravilloso para aquellos que comenzaron a aprender Objective-C.
Configuración del entorno local
Si aún está dispuesto a configurar su entorno para el lenguaje de programación Objective-C, necesita los siguientes dos softwares disponibles en su computadora, (a) Editor de texto y (b) El compilador GCC.
Editor de texto
Esto se utilizará para escribir su programa. Algunos ejemplos de algunos editores incluyen el Bloc de notas de Windows, el comando de edición del sistema operativo, Brief, Epsilon, EMACS y vim o vi.
El nombre y la versión del editor de texto pueden variar en diferentes sistemas operativos. Por ejemplo, el Bloc de notas se usará en Windows, y vim o vi se pueden usar en Windows, así como en Linux o UNIX.
Los archivos que crea con su editor se denominan archivos fuente y contienen el código fuente del programa. Los archivos de origen de los programas Objective-C generalmente se nombran con la extensión ".m".
Antes de comenzar a programar, asegúrese de tener un editor de texto en su lugar y de tener suficiente experiencia para escribir un programa de computadora, guardarlo en un archivo, compilarlo y finalmente ejecutarlo.
El compilador de GCC
El código fuente escrito en el archivo fuente es la fuente legible por humanos para su programa. Necesita ser "compilado" para convertirse en lenguaje de máquina, de modo que su CPU pueda ejecutar el programa según las instrucciones dadas.
Este compilador GCC se utilizará para compilar su código fuente en el programa ejecutable final. Supongo que tiene conocimientos básicos sobre un compilador de lenguajes de programación.
El compilador GCC está disponible de forma gratuita en varias plataformas y el procedimiento para configurar en varias plataformas se explica a continuación.
Instalación en UNIX / Linux
El paso inicial es instalar gcc junto con el paquete gcc Objective-C. Esto se hace por -
$ su - $ yum install gcc
$ yum install gcc-objc
El siguiente paso es configurar las dependencias del paquete usando el siguiente comando:
$ yum install make libpng libpng-devel libtiff libtiff-devel libobjc
libxml2 libxml2-devel libX11-devel libXt-devel libjpeg libjpeg-devel
Para obtener todas las funciones de Objective-C, descargue e instale GNUStep. Esto se puede hacer descargando el paquete desdehttp://main.gnustep.org/resources/downloads.php.
Ahora, debemos cambiar a la carpeta descargada y descomprimir el archivo por -
$ tar xvfz gnustep-startup-
.tar.gz
Ahora, debemos cambiar a la carpeta gnustep-startup que se crea usando -
$ cd gnustep-startup-<version>
A continuación, necesitamos configurar el proceso de compilación:
$ ./configure
Entonces, podemos construir por -
$ make
Necesitamos finalmente configurar el medio ambiente:
$ . /usr/GNUstep/System/Library/Makefiles/GNUstep.sh
Tenemos un helloWorld.m Objective-C de la siguiente manera:
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSLog (@"hello world");
[pool drain];
return 0;
}
Ahora, podemos compilar y ejecutar un archivo Objective-C digamos holaWorld.m cambiando a la carpeta que contiene el archivo usando cd y luego usando los siguientes pasos:
$ gcc `gnustep-config --objc-flags`
-L/usr/GNUstep/Local/Library/Libraries
-lgnustep-base helloWorld.m -o helloWorld
$ ./helloWorld
Podemos ver la siguiente salida:
2013-09-07 10:48:39.772 tutorialsPoint[12906] hello world
Instalación en Mac OS
Si utiliza Mac OS X, la forma más sencilla de obtener GCC es descargar el entorno de desarrollo Xcode del sitio web de Apple y seguir las sencillas instrucciones de instalación. Una vez que haya configurado Xcode, podrá usar el compilador GNU para C / C ++.
Xcode está disponible actualmente en developer.apple.com/technologies/tools/ .
Instalación en Windows
Para ejecutar el programa Objective-C en Windows, necesitamos instalar MinGW y GNUStep Core. Ambos están disponibles enhttps://www.gnu.org/software/gnustep/windows/installer.html.
Primero, necesitamos instalar el paquete del sistema MSYS / MinGW. Luego, necesitamos instalar el paquete GNUstep Core. Ambos proporcionan un instalador de Windows, que se explica por sí mismo.
Luego, para usar Objective-C y GNUstep seleccionando Inicio -> Todos los programas -> GNUstep -> Shell
Cambie a la carpeta que contiene helloWorld.m
Podemos compilar el programa usando -
$ gcc `gnustep-config --objc-flags`
-L /GNUstep/System/Library/Libraries hello.m -o hello -lgnustep-base -lobjc
Podemos ejecutar el programa usando -
./hello.exe
Obtenemos el siguiente resultado:
2013-09-07 10:48:39.772 tutorialsPoint[1200] hello world
Antes de estudiar los bloques de construcción básicos del lenguaje de programación Objective-C, veamos una estructura mínima del programa Objective-C para que podamos tomarla como referencia en los próximos capítulos.
Ejemplo de Objective-C Hello World
Un programa de Objective-C consta básicamente de las siguientes partes:
- Comandos del preprocesador
- Interface
- Implementation
- Method
- Variables
- Declaraciones y expresiones
- Comments
Veamos un código simple que imprimiría las palabras "Hola mundo" -
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
- (void)sampleMethod;
@end
@implementation SampleClass
- (void)sampleMethod {
NSLog(@"Hello, World! \n");
}
@end
int main() {
/* my first program in Objective-C */
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass sampleMethod];
return 0;
}
Veamos varias partes del programa anterior:
La primera línea del programa #import <Foundation / Foundation.h> es un comando de preprocesador, que le dice al compilador de Objective-C que incluya el archivo Foundation.h antes de ir a la compilación real.
La siguiente línea @interface SampleClass: NSObject muestra cómo crear una interfaz. Hereda NSObject, que es la clase base de todos los objetos.
La siguiente línea - (void) sampleMethod; muestra cómo declarar un método.
La siguiente línea @end marca el final de una interfaz.
La siguiente línea @implementation SampleClass muestra cómo implementar la interfaz SampleClass.
La siguiente línea - (void) sampleMethod {} muestra la implementación del sampleMethod.
La siguiente línea @end marca el final de una implementación.
La siguiente línea int main () es la función principal donde comienza la ejecución del programa.
La siguiente línea /*...*/ será ignorada por el compilador y se ha puesto para agregar comentarios adicionales en el programa. Por eso, estas líneas se denominan comentarios en el programa.
La siguiente línea NSLog (...) es otra función disponible en Objective-C que genera el mensaje "¡Hola, mundo!" que se mostrará en la pantalla.
La siguiente linea return 0; termina la función main () y devuelve el valor 0.
Compilar y ejecutar el programa Objective-C
Ahora, cuando compilemos y ejecutemos el programa, obtendremos el siguiente resultado.
2017-10-06 07:48:32.020 demo[65832] Hello, World!
Ha visto una estructura básica del programa Objective-C, por lo que será fácil comprender otros bloques de construcción básicos del lenguaje de programación Objective-C.
Fichas en Objective-C
Un programa Objective-C consta de varios tokens y un token es una palabra clave, un identificador, una constante, una cadena literal o un símbolo. Por ejemplo, la siguiente declaración de Objective-C consta de seis tokens:
NSLog(@"Hello, World! \n");
Los tokens individuales son:
NSLog
@
(
"Hello, World! \n"
)
;
Punto y coma;
En el programa Objective-C, el punto y coma es un terminador de instrucciones. Es decir, cada declaración individual debe terminar con un punto y coma. Indica el final de una entidad lógica.
Por ejemplo, a continuación se muestran dos declaraciones diferentes:
NSLog(@"Hello, World! \n");
return 0;
Comentarios
Los comentarios son como texto de ayuda en su programa Objective-C y el compilador los ignora. Comienzan con / * y terminan con los caracteres * / como se muestra a continuación -
/* my first program in Objective-C */
No puede tener comentarios en comentarios y no ocurren dentro de una cadena o caracteres literales.
Identificadores
Un identificador Objective-C es un nombre que se usa para identificar una variable, función o cualquier otro elemento definido por el usuario. Un identificador comienza con una letra de la A a la Z o de la aa la z o un guión bajo _ seguido de cero o más letras, guiones bajos y dígitos (0 a 9).
Objective-C no permite caracteres de puntuación como @, $ y% dentro de los identificadores. Objective-C es uncase-sensitivelenguaje de programación. Por lo tanto, mano de obra y mano de obra son dos identificadores diferentes en Objective-C. A continuación, se muestran algunos ejemplos de identificadores aceptables:
mohd zara abc move_name a_123
myname50 _temp j a23b9 retVal
Palabras clave
La siguiente lista muestra algunas de las palabras reservadas en Objective-C. Estas palabras reservadas no se pueden utilizar como constantes o variables o cualquier otro nombre de identificación.
auto | más | largo | cambiar |
romper | enumeración | Registrarse | typedef |
caso | externo | regreso | Unión |
carbonizarse | flotador | corto | no firmado |
constante | para | firmado | vacío |
Seguir | ir | tamaño de | volátil |
defecto | Si | estático | mientras |
hacer | En t | estructura | _Lleno |
doble | protocolo | interfaz | implementación |
NSObject | NSInteger | NSNumber | CGFloat |
propiedad | no atómico; | conservar | fuerte |
débiles | unsafe_unretained; | leer escribir | solo lectura |
Espacio en blanco en Objective-C
Una línea que contiene solo espacios en blanco, posiblemente con un comentario, se conoce como una línea en blanco y un compilador de Objective-C la ignora por completo.
Espacio en blanco es el término utilizado en Objective-C para describir espacios en blanco, tabulaciones, caracteres de nueva línea y comentarios. El espacio en blanco separa una parte de una declaración de otra y permite al compilador identificar dónde termina un elemento de una declaración, como int, y comienza el siguiente. Por lo tanto, en la siguiente declaración:
int age;
Debe haber al menos un carácter de espacio en blanco (generalmente un espacio) entre int y age para que el compilador pueda distinguirlos. Por otro lado, en el siguiente comunicado,
fruit = apples + oranges; // get the total fruit
No se necesitan espacios en blanco entre fruta y =, o entre = y manzanas, aunque puede incluir algunos si lo desea por motivos de legibilidad.
En el lenguaje de programación Objective-C, los tipos de datos se refieren a un amplio sistema utilizado para declarar variables o funciones de diferentes tipos. El tipo de variable determina cuánto espacio ocupa en el almacenamiento y cómo se interpreta el patrón de bits almacenado.
Los tipos en Objective-C se pueden clasificar de la siguiente manera:
No Señor. | Tipos y descripción |
---|---|
1 | Basic Types − Son tipos aritméticos y constan de dos tipos: (a) tipos enteros y (b) tipos de coma flotante. |
2 | Enumerated types − De nuevo son tipos aritméticos y se utilizan para definir variables a las que solo se les pueden asignar ciertos valores enteros discretos en todo el programa. |
3 | The type void − El especificador de tipo void indica que no hay ningún valor disponible. |
4 | Derived types − Incluyen (a) tipos de puntero, (b) tipos de matriz, (c) tipos de estructura, (d) tipos de unión y (e) tipos de función. |
Los tipos de matriz y los tipos de estructura se denominan colectivamente tipos agregados. El tipo de una función especifica el tipo de valor de retorno de la función. Veremos los tipos básicos en la siguiente sección, mientras que otros tipos se tratarán en los próximos capítulos.
Tipos de enteros
La siguiente tabla le brinda detalles sobre los tipos de enteros estándar con sus tamaños de almacenamiento y rangos de valores:
Tipo | Tamaño de almacenamiento | Rango de valores |
---|---|---|
carbonizarse | 1 byte | -128 a 127 o 0 a 255 |
char sin firmar | 1 byte | 0 hasta 255 |
char firmado | 1 byte | -128 hasta 127 |
En t | 2 o 4 bytes | -32,768 a 32,767 o -2,147,483,648 a 2,147,483,647 |
int sin firmar | 2 o 4 bytes | 0 a 65,535 o 0 a 4,294,967,295 |
corto | 2 bytes | -32.768 hasta 32.767 |
corto sin firmar | 2 bytes | 0 hasta 65.535 |
largo | 4 bytes | -2,147,483,648 a 2,147,483,647 |
largo sin firmar | 4 bytes | 0 a 4.294.967.295 |
Para obtener el tamaño exacto de un tipo o variable en una plataforma en particular, puede usar el sizeofoperador. La expresión sizeof (tipo) da como resultado el tamaño de almacenamiento del objeto o tipo en bytes. A continuación se muestra un ejemplo para obtener el tamaño del tipo int en cualquier máquina:
#import <Foundation/Foundation.h>
int main() {
NSLog(@"Storage size for int : %d \n", sizeof(int));
return 0;
}
Cuando compila y ejecuta el programa anterior, produce el siguiente resultado en Linux:
2013-09-07 22:21:39.155 demo[1340] Storage size for int : 4
Tipos de punto flotante
La siguiente tabla le brinda detalles sobre los tipos de punto flotante estándar con tamaños de almacenamiento y rangos de valores y su precisión:
Tipo | Tamaño de almacenamiento | Rango de valores | Precisión |
---|---|---|---|
flotador | 4 bytes | 1.2E-38 a 3.4E + 38 | 6 lugares decimales |
doble | 8 bytes | 2.3E-308 a 1.7E + 308 | 15 decimales |
doble largo | 10 bytes | 3.4E-4932 hasta 1.1E + 4932 | 19 posiciones decimales |
El archivo de encabezado float.h define macros que le permiten usar estos valores y otros detalles sobre la representación binaria de números reales en sus programas. El siguiente ejemplo imprimirá el espacio de almacenamiento tomado por un tipo flotante y sus valores de rango:
#import <Foundation/Foundation.h>
int main() {
NSLog(@"Storage size for float : %d \n", sizeof(float));
return 0;
}
Cuando compila y ejecuta el programa anterior, produce el siguiente resultado en Linux:
2013-09-07 22:22:21.729 demo[3927] Storage size for float : 4
El tipo vacío
El tipo vacío especifica que no hay ningún valor disponible. Se utiliza en tres tipos de situaciones:
No Señor. | Tipos y descripción |
---|---|
1 | Function returns as void Hay varias funciones en Objective-C que no devuelven valor o se puede decir que devuelven vacío. Una función sin valor de retorno tiene el tipo de retorno como vacío. Por ejemplo,void exit (int status); |
2 | Function arguments as void Hay varias funciones en Objective-C que no aceptan ningún parámetro. Una función sin parámetro puede aceptarse como nula. Por ejemplo,int rand(void); |
Es posible que en este momento no entienda el tipo vacío, así que continuemos y cubriremos estos conceptos en los próximos capítulos.
Una variable no es más que un nombre que se le da a un área de almacenamiento que nuestros programas pueden manipular. Cada variable en Objective-C tiene un tipo específico, que determina el tamaño y el diseño de la memoria de la variable; el rango de valores que se pueden almacenar dentro de esa memoria; y el conjunto de operaciones que se pueden aplicar a la variable.
El nombre de una variable puede estar compuesto por letras, dígitos y el carácter de subrayado. Debe comenzar con una letra o un guión bajo. Las letras mayúsculas y minúsculas son distintas porque Objective-C distingue entre mayúsculas y minúsculas. Según los tipos básicos explicados en el capítulo anterior, habrá los siguientes tipos de variables básicas:
No Señor. | Tipo y descripción |
---|---|
1 | char Normalmente, un solo octeto (un byte). Este es un tipo entero. |
2 | int El tamaño más natural de número entero para la máquina. |
3 | float Un valor de coma flotante de precisión simple. |
4 | double Un valor de coma flotante de doble precisión. |
5 | void Representa la ausencia de tipo. |
El lenguaje de programación Objective-C también permite definir varios otros tipos de variables, que cubriremos en capítulos posteriores como Enumeración, Puntero, Array, Estructura, Unión, etc. Para este capítulo, estudiemos solo los tipos de variables básicas.
Definición de variable en Objective-C
Una definición de variable significa decirle al compilador dónde y cuánto crear el almacenamiento para la variable. Una definición de variable especifica un tipo de datos y contiene una lista de una o más variables de ese tipo de la siguiente manera:
type variable_list;
Aquí, type debe ser un tipo de datos Objective-C válido que incluya char, w_char, int, float, double, bool o cualquier objeto definido por el usuario, etc., y variable_listpuede constar de uno o más nombres de identificadores separados por comas. Aquí se muestran algunas declaraciones válidas:
int i, j, k;
char c, ch;
float f, salary;
double d;
La línea int i, j, k;declara y define las variables i, j y k; que indica al compilador que cree variables denominadas i, j y k de tipo int.
Las variables se pueden inicializar (asignar un valor inicial) en su declaración. El inicializador consta de un signo igual seguido de una expresión constante de la siguiente manera:
type variable_name = value;
Algunos ejemplos son:
extern int d = 3, f = 5; // declaration of d and f.
int d = 3, f = 5; // definition and initializing d and f.
byte z = 22; // definition and initializes z.
char x = 'x'; // the variable x has the value 'x'.
Para la definición sin un inicializador: las variables con duración de almacenamiento estático se inicializan implícitamente con NULL (todos los bytes tienen el valor 0); el valor inicial de todas las demás variables no está definido.
Declaración de variable en Objective-C
Una declaración de variable proporciona seguridad al compilador de que existe una variable con el tipo y nombre dados, de modo que el compilador proceda a una compilación adicional sin necesidad de detalles completos sobre la variable. Una declaración de variable tiene su significado solo en el momento de la compilación, el compilador necesita una declaración de variable real en el momento de vincular el programa.
Una declaración de variable es útil cuando está utilizando varios archivos y define su variable en uno de los archivos, que estará disponible en el momento de vincular el programa. Usarásexternpalabra clave para declarar una variable en cualquier lugar. Aunque puede declarar una variable varias veces en su programa Objective-C, solo se puede definir una vez en un archivo, una función o un bloque de código.
Ejemplo
Pruebe el siguiente ejemplo, donde las variables se han declarado en la parte superior, pero se han definido e inicializado dentro de la función principal:
#import <Foundation/Foundation.h>
// Variable declaration:
extern int a, b;
extern int c;
extern float f;
int main () {
/* variable definition: */
int a, b;
int c;
float f;
/* actual initialization */
a = 10;
b = 20;
c = a + b;
NSLog(@"value of c : %d \n", c);
f = 70.0/3.0;
NSLog(@"value of f : %f \n", f);
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-07 22:43:31.695 demo[14019] value of c : 30
2013-09-07 22:43:31.695 demo[14019] value of f : 23.333334
El mismo concepto se aplica a la declaración de función, donde se proporciona un nombre de función en el momento de su declaración y su definición real se puede dar en cualquier otro lugar. En el siguiente ejemplo, se explica el uso de la función C y, como sabe, Objective-C también admite funciones de estilo C:
// function declaration
int func();
int main() {
// function call
int i = func();
}
// function definition
int func() {
return 0;
}
Valores L y valores R en Objective-C
Hay dos tipos de expresiones en Objective-C:
lvalue- Las expresiones que se refieren a una ubicación de memoria se denominan expresión "lvalue". Un lvalue puede aparecer como el lado izquierdo o derecho de una tarea.
rvalue- El término rvalue se refiere a un valor de datos que se almacena en alguna dirección de la memoria. Un rvalue es una expresión a la que no se le puede asignar un valor, lo que significa que un rvalue puede aparecer en el lado derecho pero no en el izquierdo de una asignación.
Las variables son valores l y, por lo tanto, pueden aparecer en el lado izquierdo de una tarea. Los literales numéricos son valores r y, por lo tanto, no se pueden asignar y no pueden aparecer en el lado izquierdo. A continuación se muestra una declaración válida:
int g = 20;
Pero lo siguiente no es una declaración válida y generaría un error en tiempo de compilación:
10 = 20;
Las constantes se refieren a valores fijos que el programa no puede alterar durante su ejecución. Estos valores fijos también se denominanliterals.
Las constantes pueden ser de cualquiera de los tipos de datos básicos, como una constante entera, una constante flotante, una constante de carácter o una cadena literal . También hay constantes de enumeración.
los constants se tratan como variables regulares excepto que sus valores no se pueden modificar después de su definición.
Literales enteros
Un literal entero puede ser una constante decimal, octal o hexadecimal. Un prefijo especifica la base o la raíz: 0x o 0X para hexadecimal, 0 para octal y nada para decimal.
Un literal entero también puede tener un sufijo que sea una combinación de U y L, para unsigned y long, respectivamente. El sufijo puede estar en mayúsculas o minúsculas y puede estar en cualquier orden.
Aquí hay algunos ejemplos de literales enteros:
212 /* Legal */
215u /* Legal */
0xFeeL /* Legal */
078 /* Illegal: 8 is not an octal digit */
032UU /* Illegal: cannot repeat a suffix */
A continuación se muestran otros ejemplos de varios tipos de literales enteros:
85 /* decimal */
0213 /* octal */
0x4b /* hexadecimal */
30 /* int */
30u /* unsigned int */
30l /* long */
30ul /* unsigned long */
Literales de punto flotante
Un literal de coma flotante tiene una parte entera, una coma decimal, una parte fraccionaria y una parte exponente. Puede representar literales de coma flotante en forma decimal o exponencial.
Mientras representa en forma decimal, debe incluir el punto decimal, el exponente o ambos y mientras representa en forma exponencial, debe incluir la parte entera, la parte fraccionaria o ambas. El exponente con signo se introduce mediante e o E.
Aquí hay algunos ejemplos de literales de punto flotante:
3.14159 /* Legal */
314159E-5L /* Legal */
510E /* Illegal: incomplete exponent */
210f /* Illegal: no decimal or exponent */
.e55 /* Illegal: missing integer or fraction */
Constantes de caracteres
Los literales de caracteres se encierran entre comillas simples, por ejemplo, 'x' y se pueden almacenar en una variable simple de char tipo.
Un literal de carácter puede ser un carácter simple (por ejemplo, 'x'), una secuencia de escape (por ejemplo, '\ t') o un carácter universal (por ejemplo, '\ u02C0').
There are certain characters in C when they are proceeded by a backslash they will have special meaning and they are used to represent like newline (\n) or tab (\t). Here, you have a list of some of such escape sequence codes −
Escape sequence | Meaning |
---|---|
\\ | \ character |
\' | ' character |
\" | " character |
\? | ? character |
\a | Alert or bell |
\b | Backspace |
\f | Form feed |
\n | Newline |
\r | Carriage return |
\t | Horizontal tab |
\v | Vertical tab |
\ooo | Octal number of one to three digits |
\xhh . . . | Hexadecimal number of one or more digits |
Following is the example to show few escape sequence characters −
#import <Foundation/Foundation.h>
int main() {
NSLog(@"Hello\tWorld\n\n");
return 0;
}
When the above code is compiled and executed, it produces the following result −
2013-09-07 22:17:17.923 demo[17871] Hello World
String literals
String literals or constants are enclosed in double quotes "". A string contains characters that are similar to character literals: plain characters, escape sequences, and universal characters.
You can break a long line into multiple lines using string literals and separating them using whitespaces.
Here are some examples of string literals. All the three forms are identical strings.
"hello, dear"
"hello, \
dear"
"hello, " "d" "ear"
Defining Constants
There are two simple ways in C to define constants −
Using #define preprocessor.
Using const keyword.
The #define Preprocessor
Following is the form to use #define preprocessor to define a constant −
#define identifier value
Following example explains it in detail −
#import <Foundation/Foundation.h>
#define LENGTH 10
#define WIDTH 5
#define NEWLINE '\n'
int main() {
int area;
area = LENGTH * WIDTH;
NSLog(@"value of area : %d", area);
NSLog(@"%c", NEWLINE);
return 0;
}
When the above code is compiled and executed, it produces the following result −
2013-09-07 22:18:16.637 demo[21460] value of area : 50
2013-09-07 22:18:16.638 demo[21460]
The const Keyword
You can use const prefix to declare constants with a specific type as follows −
const type variable = value;
Following example explains it in detail −
#import <Foundation/Foundation.h>
int main() {
const int LENGTH = 10;
const int WIDTH = 5;
const char NEWLINE = '\n';
int area;
area = LENGTH * WIDTH;
NSLog(@"value of area : %d", area);
NSLog(@"%c", NEWLINE);
return 0;
}
When the above code is compiled and executed, it produces the following result −
2013-09-07 22:19:24.780 demo[25621] value of area : 50
2013-09-07 22:19:24.781 demo[25621]
Note that it is a good programming practice to define constants in CAPITALS.
An operator is a symbol that tells the compiler to perform specific mathematical or logical manipulations. Objective-C language is rich in built-in operators and provides following types of operators −
- Arithmetic Operators
- Relational Operators
- Logical Operators
- Bitwise Operators
- Assignment Operators
- Misc Operators
This tutorial will explain the arithmetic, relational, logical, bitwise, assignment and other operators one by one.
Arithmetic Operators
Following table shows all the arithmetic operators supported by Objective-C language. Assume variable A holds 10 and variable B holds 20, then −
Show Examples
Operator | Description | Example |
---|---|---|
+ | Adds two operands | A + B will give 30 |
- | Subtracts second operand from the first | A - B will give -10 |
* | Multiplies both operands | A * B will give 200 |
/ | Divides numerator by denominator | B / A will give 2 |
% | Modulus Operator and remainder of after an integer division | B % A will give 0 |
++ | Increment operator increases integer value by one | A++ will give 11 |
-- | Decrement operator decreases integer value by one | A-- will give 9 |
Relational Operators
Following table shows all the relational operators supported by Objective-C language. Assume variable A holds 10 and variable B holds 20, then −
Show Examples
Operator | Description | Example |
---|---|---|
== | Checks if the values of two operands are equal or not; if yes, then condition becomes true. | (A == B) is not true. |
!= | Checks if the values of two operands are equal or not; if values are not equal, then condition becomes true. | (A != B) is true. |
> | Checks if the value of left operand is greater than the value of right operand; if yes, then condition becomes true. | (A > B) is not true. |
< | Checks if the value of left operand is less than the value of right operand; if yes, then condition becomes true. | (A < B) is true. |
>= | Checks if the value of left operand is greater than or equal to the value of right operand; if yes, then condition becomes true. | (A >= B) is not true. |
<= | Checks if the value of left operand is less than or equal to the value of right operand; if yes, then condition becomes true. | (A <= B) is true. |
Logical Operators
Following table shows all the logical operators supported by Objective-C language. Assume variable A holds 1 and variable B holds 0, then −
Show Examples
Operator | Description | Example |
---|---|---|
&& | Called Logical AND operator. If both the operands are non zero then condition becomes true. | (A && B) is false. |
|| | Called Logical OR Operator. If any of the two operands is non zero then condition becomes true. | (A || B) is true. |
! | Called Logical NOT Operator. Use to reverses the logical state of its operand. If a condition is true, then Logical NOT operator will make false. | !(A && B) is true. |
Bitwise Operators
Bitwise operator works on bits and perform bit by bit operation. The truth tables for &, |, and ^ are as follows −
p | q | p & q | p | q | p ^ q |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
Assume if A = 60; and B = 13; now in binary format they will be as follows −
A = 0011 1100
B = 0000 1101
-----------------
A&B = 0000 1100
A|B = 0011 1101
A^B = 0011 0001
~A = 1100 0011
The Bitwise operators supported by Objective-C language are listed in the following table. Assume variable A holds 60 and variable B holds 13 then −
Show Examples
Operator | Description | Example |
---|---|---|
& | Binary AND Operator copies a bit to the result if it exists in both operands. | (A & B) will give 12, which is 0000 1100 |
| | Binary OR Operator copies a bit if it exists in either operand. | (A | B) will give 61, which is 0011 1101 |
^ | Binary XOR Operator copies the bit if it is set in one operand but not both. | (A ^ B) will give 49, which is 0011 0001 |
~ | Binary Ones Complement Operator is unary and has the effect of 'flipping' bits. | (~A ) will give -61, which is 1100 0011 in 2's complement form. |
<< | Binary Left Shift Operator. The left operands value is moved left by the number of bits specified by the right operand. | A << 2 will give 240, which is 1111 0000 |
>> | Binary Right Shift Operator. The left operands value is moved right by the number of bits specified by the right operand. | A >> 2 will give 15, which is 0000 1111 |
Assignment Operators
There are following assignment operators supported by Objective-C language −
Show Examples
Operator | Description | Example |
---|---|---|
= | Simple assignment operator, Assigns values from right side operands to left side operand | C = A + B will assign value of A + B into C |
+= | Add AND assignment operator, It adds right operand to the left operand and assigns the result to left operand | C += A is equivalent to C = C + A |
-= | Subtract AND assignment operator, It subtracts right operand from the left operand and assigns the result to left operand | C -= A is equivalent to C = C - A |
*= | Multiply AND assignment operator, It multiplies right operand with the left operand and assigns the result to left operand | C *= A is equivalent to C = C * A |
/= | Divide AND assignment operator, It divides left operand with the right operand and assigns the result to left operand | C /= A is equivalent to C = C / A |
%= | Modulus AND assignment operator, It takes modulus using two operands and assigns the result to left operand | C %= A is equivalent to C = C % A |
<<= | Left shift AND assignment operator | C <<= 2 is same as C = C << 2 |
>>= | Right shift AND assignment operator | C >>= 2 is same as C = C >> 2 |
&= | Bitwise AND assignment operator | C &= 2 is same as C = C & 2 |
^= | bitwise exclusive OR and assignment operator | C ^= 2 is same as C = C ^ 2 |
|= | bitwise inclusive OR and assignment operator | C |= 2 is same as C = C | 2 |
Misc Operators ↦ sizeof & ternary
There are few other important operators including sizeof and ? : supported by Objective-C Language.
Show Examples
Operator | Description | Example |
---|---|---|
sizeof() | Returns the size of an variable. | sizeof(a), where a is integer, will return 4. |
& | Returns the address of an variable. | &a; will give actual address of the variable. |
* | Pointer to a variable. | *a; will pointer to a variable. |
? : | Conditional Expression | If Condition is true ? Then value X : Otherwise value Y |
Operators Precedence in Objective-C
Operator precedence determines the grouping of terms in an expression. This affects how an expression is evaluated. Certain operators have higher precedence than others; for example, the multiplication operator has higher precedence than the addition operator −
For example, x = 7 + 3 * 2; here, x is assigned 13, not 20 because operator * has higher precedence than +, so it first gets multiplied with 3*2 and then adds into 7.
Here, operators with the highest precedence appear at the top of the table, those with the lowest appear at the bottom. Within an expression, higher precedence operators will be evaluated first.
Category | Operator | Associativity |
---|---|---|
Postfix | () [] -> . ++ - - | Left to right |
Unary | + - ! ~ ++ - - (type)* & sizeof | Right to left |
Multiplicative | * / % | Left to right |
Additive | + - | Left to right |
Shift | << >> | Left to right |
Relational | < <= > >= | Left to right |
Equality | == != | Left to right |
Bitwise XOR | ^ | Left to right |
Bitwise OR | | | Left to right |
Logical AND | && | Left to right |
Logical OR | || | Left to right |
Conditional | ?: | Right to left |
Assignment | = += -= *= /= %=>>= <<= &= ^= |= | Right to left |
Comma | , | Left to right |
There may be a situation, when you need to execute a block of code several number of times. In general, statements are executed sequentially: The first statement in a function is executed first, followed by the second, and so on.
Programming languages provide various control structures that allow for more complicated execution paths.
A loop statement allows us to execute a statement or group of statements multiple times and following is the general form of a loop statement in most of the programming languages −
Objective-C programming language provides the following types of loop to handle looping requirements. Click the following links to check their details.
Sr.No. | Loop Type & Description |
---|---|
1 | while loop Repeats a statement or group of statements while a given condition is true. It tests the condition before executing the loop body. |
2 | for loop Execute a sequence of statements multiple times and abbreviates the code that manages the loop variable. |
3 | do...while loop Like a while statement, except that it tests the condition at the end of the loop body. |
4 | nested loops You can use one or more loops inside any another while, for or do..while loop. |
Loop Control Statements
Loop control statements change execution from its normal sequence. When execution leaves a scope, all automatic objects that were created in that scope are destroyed.
Objective-C supports the following control statements. Click the following links to check their details.
Sr.No. | Control Statement & Description |
---|---|
1 | break statement Terminates the loop or switch statement and transfers execution to the statement immediately following the loop or switch. |
2 | continue statement Causes the loop to skip the remainder of its body and immediately retest its condition prior to reiterating. |
The Infinite Loop
A loop becomes infinite loop if a condition never becomes false. The for loop is traditionally used for this purpose. Since none of the three expressions that form the for loop are required, you can make an endless loop by leaving the conditional expression empty.
#import <Foundation/Foundation.h>
int main () {
for( ; ; ) {
NSLog(@"This loop will run forever.\n");
}
return 0;
}
When the conditional expression is absent, it is assumed to be true. You may have an initialization and increment expression, but Objective-C programmers more commonly use the for(;;) construct to signify an infinite loop.
Decision making structures require that the programmer specify one or more conditions to be evaluated or tested by the program, along with a statement or statements to be executed if the condition is determined to be true, and optionally, other statements to be executed if the condition is determined to be false.
Following is the general form of a typical decision making structure found in most of the programming languages −
Objective-C programming language assumes any non-zero and non-null values as true, and if it is either zero or null, then it is assumed as false value.
Objective-C programming language provides following types of decision making statements. Click the following links to check their details −
Sr.No. | Statement & Description |
---|---|
1 | if statement An if statement consists of a boolean expression followed by one or more statements. |
2 | if...else statement An if statement can be followed by an optional else statement, which executes when the boolean expression is false. |
3 | nested if statements You can use one if or else if statement inside another if or else if statement(s). |
4 | switch statement A switch statement allows a variable to be tested for equality against a list of values. |
5 | nested switch statements You can use one switch statement inside another switch statement(s). |
The ? : Operator
We have covered conditional operator ? : in previous chapter which can be used to replace if...else statements. It has the following general form −
Exp1 ? Exp2 : Exp3;
Where Exp1, Exp2, and Exp3 are expressions. Notice the use and placement of the colon.
The value of a ? expression is determined like this: Exp1 is evaluated. If it is true, then Exp2 is evaluated and becomes the value of the entire ? expression. If Exp1 is false, then Exp3 is evaluated and its value becomes the value of the expression.
A function is a group of statements that together perform a task. Every Objective-C program has one C function, which is main(), and all of the most trivial programs can define additional functions.
You can divide up your code into separate functions. How you divide up your code among different functions is up to you, but logically the division usually is so each function performs a specific task.
A function declaration tells the compiler about a function's name, return type, and parameters. A function definition provides the actual body of the function.
Basically in Objective-C, we call the function as method.
The Objective-C foundation framework provides numerous built-in methods that your program can call. For example, method appendString() to append string to another string.
A method is known with various names like a function or a sub-routine or a procedure, etc.
Defining a Method
The general form of a method definition in Objective-C programming language is as follows −
- (return_type) method_name:( argumentType1 )argumentName1
joiningArgument2:( argumentType2 )argumentName2 ...
joiningArgumentn:( argumentTypen )argumentNamen {
body of the function
}
A method definition in Objective-C programming language consists of a method header and a method body. Here are all the parts of a method −
Return Type − A method may return a value. The return_type is the data type of the value the function returns. Some methods perform the desired operations without returning a value. In this case, the return_type is the keyword void.
Method Name − This is the actual name of the method. The method name and the parameter list together constitute the method signature.
Arguments − A argument is like a placeholder. When a function is invoked, you pass a value to the argument. This value is referred to as actual parameter or argument. The parameter list refers to the type, order, and number of the arguments of a method. Arguments are optional; that is, a method may contain no argument.
Joining Argument − A joining argument is to make it easier to read and to make it clear while calling it.
Method Body − The method body contains a collection of statements that define what the method does.
Ejemplo
A continuación se muestra el código fuente de un método llamado max(). Este método toma dos parámetros num1 y num2 y devuelve el máximo entre los dos -
/* function returning the max between two numbers */
- (int) max:(int) num1 secondNumber:(int) num2 {
/* local variable declaration */
int result;
if (num1 > num2) {
result = num1;
} else {
result = num2;
}
return result;
}
Declaraciones de métodos
Un método declarationle dice al compilador sobre el nombre de una función y cómo llamar al método. El cuerpo real de la función se puede definir por separado.
Una declaración de método tiene las siguientes partes:
- (return_type) function_name:( argumentType1 )argumentName1
joiningArgument2:( argumentType2 )argumentName2 ...
joiningArgumentn:( argumentTypen )argumentNamen;
Para la función max () definida anteriormente, la siguiente es la declaración del método:
-(int) max:(int)num1 andNum2:(int)num2;
La declaración de método es necesaria cuando define un método en un archivo fuente y llama a ese método en otro archivo. En tal caso, debe declarar la función en la parte superior del archivo que llama a la función.
Llamar a un método
Al crear un método Objective-C, das una definición de lo que tiene que hacer la función. Para utilizar un método, tendrá que llamar a esa función para realizar la tarea definida.
Cuando un programa llama a una función, el control del programa se transfiere al método llamado. Un método llamado realiza una tarea definida, y cuando se ejecuta su declaración de retorno o cuando se alcanza su llave de cierre de finalización de función, devuelve el control del programa al programa principal.
Para llamar a un método, simplemente necesita pasar los parámetros requeridos junto con el nombre del método, y si el método devuelve un valor, entonces puede almacenar el valor devuelto. Por ejemplo
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
/* method declaration */
- (int)max:(int)num1 andNum2:(int)num2;
@end
@implementation SampleClass
/* method returning the max between two numbers */
- (int)max:(int)num1 andNum2:(int)num2 {
/* local variable declaration */
int result;
if (num1 > num2) {
result = num1;
} else {
result = num2;
}
return result;
}
@end
int main () {
/* local variable definition */
int a = 100;
int b = 200;
int ret;
SampleClass *sampleClass = [[SampleClass alloc]init];
/* calling a method to get max value */
ret = [sampleClass max:a andNum2:b];
NSLog(@"Max value is : %d\n", ret );
return 0;
}
Mantuve la función max () junto con la función main () y cumplí con el código fuente. Mientras se ejecuta el ejecutable final, produciría el siguiente resultado:
2013-09-07 22:28:45.912 demo[26080] Max value is : 200
Argumentos de función
Si una función va a utilizar argumentos, debe declarar variables que acepten los valores de los argumentos. Estas variables se denominanformal parameters de la función.
Los parámetros formales se comportan como otras variables locales dentro de la función y se crean al entrar en la función y se destruyen al salir.
Mientras se llama a una función, hay dos formas de pasar argumentos a una función:
No Señor. | Tipo de llamada y descripción |
---|---|
1 | Llamar por valor Este método copia el valor real de un argumento en el parámetro formal de la función. En este caso, los cambios realizados en el parámetro dentro de la función no tienen ningún efecto en el argumento. |
2 | Llamar por referencia Este método copia la dirección de un argumento en el parámetro formal. Dentro de la función, la dirección se usa para acceder al argumento real usado en la llamada. Esto significa que los cambios realizados en el parámetro afectan el argumento. |
Por defecto, Objective-C usa call by valuepara pasar argumentos. En general, esto significa que el código dentro de una función no puede alterar los argumentos utilizados para llamar a la función, y el ejemplo mencionado anteriormente al llamar a la función max () utilizó el mismo método.
Una clase Objective-C define un objeto que combina datos con comportamientos relacionados. A veces, tiene sentido representar una sola tarea o unidad de comportamiento, en lugar de una colección de métodos.
Los bloques son una característica de nivel de lenguaje agregada a C, Objective-C y C ++ que le permiten crear segmentos distintos de código que se pueden pasar a métodos o funciones como si fueran valores. Los bloques son objetos Objective-C, lo que significa que se pueden agregar a colecciones como NSArray o NSDictionary. También tienen la capacidad de capturar valores del alcance adjunto, haciéndolos similares a los cierres o lambdas en otros lenguajes de programación.
Sintaxis de declaración de bloque simple
returntype (^blockName)(argumentType);
Implementación de bloque simple
returntype (^blockName)(argumentType)= ^{
};
He aquí un ejemplo sencillo
void (^simpleBlock)(void) = ^{
NSLog(@"This is a block");
};
Podemos invocar el bloque usando
simpleBlock();
Los bloques toman argumentos y devuelven valores
Los bloques también pueden tomar argumentos y devolver valores como métodos y funciones.
Aquí hay un ejemplo simple para implementar e invocar un bloque con argumentos y valores de retorno.
double (^multiplyTwoValues)(double, double) =
^(double firstValue, double secondValue) {
return firstValue * secondValue;
};
double result = multiplyTwoValues(2,4);
NSLog(@"The result is %f", result);
Bloques que utilizan definiciones de tipo
Aquí hay un ejemplo simple usando typedef en block. Tenga en cuenta esta muestradoesn't work sobre el online compilerpor ahora. UtilizarXCode para ejecutar lo mismo.
#import <Foundation/Foundation.h>
typedef void (^CompletionBlock)();
@interface SampleClass:NSObject
- (void)performActionWithCompletion:(CompletionBlock)completionBlock;
@end
@implementation SampleClass
- (void)performActionWithCompletion:(CompletionBlock)completionBlock {
NSLog(@"Action Performed");
completionBlock();
}
@end
int main() {
/* my first program in Objective-C */
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass performActionWithCompletion:^{
NSLog(@"Completion is called to intimate action is performed.");
}];
return 0;
}
Compilemos y ejecutemos, producirá el siguiente resultado:
2013-09-10 08:13:57.155 demo[284:303] Action Performed
2013-09-10 08:13:57.157 demo[284:303] Completion is called to intimate action is performed.
Los bloques se utilizan más en aplicaciones iOS y Mac OS X. Por lo tanto, es más importante comprender el uso de bloques.
En el lenguaje de programación Objective-C, para guardar los tipos de datos básicos como int, float, bool en forma de objeto,
Objective-C proporciona una variedad de métodos para trabajar con NSNumber y los más importantes se enumeran en la siguiente tabla.
No Señor. | Método y descripción |
---|---|
1 | + (NSNumber *)numberWithBool:(BOOL)value Crea y devuelve un objeto NSNumber que contiene un valor dado, tratándolo como un BOOL. |
2 | + (NSNumber *)numberWithChar:(char)value Crea y devuelve un objeto NSNumber que contiene un valor dado, tratándolo como un carácter firmado. |
3 | + (NSNumber *)numberWithDouble:(double)value Crea y devuelve un objeto NSNumber que contiene un valor dado, tratándolo como un doble. |
4 | + (NSNumber *)numberWithFloat:(float)value Crea y devuelve un objeto NSNumber que contiene un valor dado, tratándolo como un flotante. |
5 | + (NSNumber *)numberWithInt:(int)value Crea y devuelve un objeto NSNumber que contiene un valor dado, tratándolo como un int firmado. |
6 | + (NSNumber *)numberWithInteger:(NSInteger)value Crea y devuelve un objeto NSNumber que contiene un valor dado, tratándolo como un NSInteger. |
7 | - (BOOL)boolValue Devuelve el valor del receptor como BOOL. |
8 | - (char)charValue Devuelve el valor del receptor como un carácter. |
9 | - (double)doubleValue Devuelve el valor del receptor como un doble. |
10 | - (float)floatValue Devuelve el valor del receptor como flotante. |
11 | - (NSInteger)integerValue Devuelve el valor del receptor como NSInteger. |
12 | - (int)intValue Devuelve el valor del receptor como int. |
13 | - (NSString *)stringValue Devuelve el valor del receptor como una cadena legible por humanos. |
Aquí hay un ejemplo simple para usar NSNumber que multiplica dos números y devuelve el producto.
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
- (NSNumber *)multiplyA:(NSNumber *)a withB:(NSNumber *)b;
@end
@implementation SampleClass
- (NSNumber *)multiplyA:(NSNumber *)a withB:(NSNumber *)b {
float number1 = [a floatValue];
float number2 = [b floatValue];
float product = number1 * number2;
NSNumber *result = [NSNumber numberWithFloat:product];
return result;
}
@end
int main() {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
SampleClass *sampleClass = [[SampleClass alloc]init];
NSNumber *a = [NSNumber numberWithFloat:10.5];
NSNumber *b = [NSNumber numberWithFloat:10.0];
NSNumber *result = [sampleClass multiplyA:a withB:b];
NSString *resultString = [result stringValue];
NSLog(@"The product is %@",resultString);
[pool drain];
return 0;
}
Ahora, cuando compilemos y ejecutemos el programa, obtendremos el siguiente resultado.
2013-09-14 18:53:40.575 demo[16787] The product is 105
El lenguaje de programación Objective-C proporciona una estructura de datos llamada the array, que puede almacenar una colección secuencial de tamaño fijo de elementos del mismo tipo. Una matriz se usa para almacenar una colección de datos, pero a menudo es más útil pensar en una matriz como una colección de variables del mismo tipo.
En lugar de declarar variables individuales, como número0, número1, ... y número99, declara una variable de matriz como números y utiliza números [0], números [1] y ..., números [99] para representar variables individuales. Se accede a un elemento específico de una matriz mediante un índice.
Todas las matrices constan de ubicaciones de memoria contiguas. La dirección más baja corresponde al primer elemento y la dirección más alta al último elemento.
Declaración de matrices
Para declarar una matriz en Objective-C, un programador especifica el tipo de elementos y el número de elementos requeridos por una matriz de la siguiente manera:
type arrayName [ arraySize ];
Esto se llama matriz unidimensional . losarraySize debe ser una constante entera mayor que cero y typepuede ser cualquier tipo de datos de Objective-C válido. Por ejemplo, para declarar una matriz de 10 elementos llamadabalance de tipo doble, use esta declaración -
double balance[10];
Ahora, el equilibrio es una matriz variable, que es suficiente para contener hasta 10 números dobles.
Inicialización de matrices
Puede inicializar una matriz en Objective-C uno por uno o usando una sola declaración de la siguiente manera:
double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
El número de valores entre llaves {} no puede ser mayor que el número de elementos que declaramos para el arreglo entre corchetes []. A continuación se muestra un ejemplo para asignar un solo elemento de la matriz:
Si omite el tamaño de la matriz, se crea una matriz lo suficientemente grande como para contener la inicialización. Por lo tanto, si escribe -
double balance[] = {1000.0, 2.0, 3.4, 17.0, 50.0};
Creará exactamente la misma matriz que hizo en el ejemplo anterior.
balance[4] = 50.0;
La declaración anterior asigna al elemento número 5 en la matriz un valor de 50,0. La matriz con el cuarto índice será el quinto, es decir, el último elemento porque todas las matrices tienen 0 como índice de su primer elemento, que también se llama índice base. A continuación se muestra la representación pictórica de la misma matriz que discutimos anteriormente:
Acceso a elementos de matriz
Se accede a un elemento indexando el nombre de la matriz. Esto se hace colocando el índice del elemento entre corchetes después del nombre de la matriz. Por ejemplo
double salary = balance[9];
La declaración anterior tomará el décimo elemento de la matriz y asignará el valor a la variable de salario. A continuación se muestra un ejemplo, que utilizará los tres conceptos mencionados anteriormente, a saber. declaración, asignación y acceso a matrices -
#import <Foundation/Foundation.h>
int main () {
int n[ 10 ]; /* n is an array of 10 integers */
int i,j;
/* initialize elements of array n to 0 */
for ( i = 0; i < 10; i++ ) {
n[ i ] = i + 100; /* set element at location i to i + 100 */
}
/* output each array element's value */
for (j = 0; j < 10; j++ ) {
NSLog(@"Element[%d] = %d\n", j, n[j] );
}
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-14 01:24:06.669 demo[16508] Element[0] = 100
2013-09-14 01:24:06.669 demo[16508] Element[1] = 101
2013-09-14 01:24:06.669 demo[16508] Element[2] = 102
2013-09-14 01:24:06.669 demo[16508] Element[3] = 103
2013-09-14 01:24:06.669 demo[16508] Element[4] = 104
2013-09-14 01:24:06.669 demo[16508] Element[5] = 105
2013-09-14 01:24:06.669 demo[16508] Element[6] = 106
2013-09-14 01:24:06.669 demo[16508] Element[7] = 107
2013-09-14 01:24:06.669 demo[16508] Element[8] = 108
2013-09-14 01:24:06.669 demo[16508] Element[9] = 109
Matrices de Objective-C en detalle
Las matrices son importantes para Objective-C y necesitan muchos más detalles. Hay algunos conceptos importantes relacionados con la matriz que deben ser claros para un programador de Objective-C:
No Señor. | Concepto y descripción |
---|---|
1 | Matrices multidimensionales Objective-C admite matrices multidimensionales. La forma más simple de la matriz multidimensional es la matriz bidimensional. |
2 | Pasar matrices a funciones Puede pasar a la función un puntero a una matriz especificando el nombre de la matriz sin un índice. |
3 | Devolver matriz de una función Objective-C permite que una función devuelva una matriz. |
4 | Puntero a una matriz Puede generar un puntero al primer elemento de una matriz simplemente especificando el nombre de la matriz, sin ningún índice. |
Los punteros en Objective-C son fáciles y divertidos de aprender. Algunas tareas de programación de Objective-C se realizan más fácilmente con punteros, y otras tareas, como la asignación de memoria dinámica, no se pueden realizar sin usar punteros. Por lo tanto, es necesario aprender los consejos para convertirse en un programador perfecto de Objective-C. Comencemos a aprenderlos en pasos simples y sencillos.
Como sabe, cada variable es una ubicación de memoria y cada ubicación de memoria tiene su dirección definida a la que se puede acceder usando el operador y comercial (&), que denota una dirección en la memoria. Considere el siguiente ejemplo, que imprimirá la dirección de las variables definidas:
#import <Foundation/Foundation.h>
int main () {
int var1;
char var2[10];
NSLog(@"Address of var1 variable: %x\n", &var1 );
NSLog(@"Address of var2 variable: %x\n", &var2 );
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-13 03:18:45.727 demo[17552] Address of var1 variable: 1c0843fc
2013-09-13 03:18:45.728 demo[17552] Address of var2 variable: 1c0843f0
Entonces, entendió qué es la dirección de memoria y cómo acceder a ella, por lo que la base del concepto se acabó. Ahora veamos qué es un puntero.
¿Qué son los punteros?
UN pointeres una variable cuyo valor es la dirección de otra variable, es decir, la dirección directa de la ubicación de la memoria. Como cualquier variable o constante, debe declarar un puntero antes de poder usarlo para almacenar cualquier dirección de variable. La forma general de una declaración de variable de puntero es:
type *var-name;
Aquí, typees el tipo base del puntero; debe ser un tipo de datos Objective-C válido yvar-namees el nombre de la variable de puntero. El asterisco * que usó para declarar un puntero es el mismo asterisco que usa para la multiplicación. Sin embargo, en esta declaración, el asterisco se utiliza para designar una variable como puntero. A continuación se muestra la declaración de puntero válida:
int *ip; /* pointer to an integer */
double *dp; /* pointer to a double */
float *fp; /* pointer to a float */
char *ch /* pointer to a character */
El tipo de datos real del valor de todos los punteros, ya sean enteros, flotantes, de caracteres u otros, es el mismo, un número hexadecimal largo que representa una dirección de memoria. La única diferencia entre punteros de diferentes tipos de datos es el tipo de datos de la variable o constante a la que apunta el puntero.
¿Cómo utilizar los punteros?
Hay pocas operaciones importantes, que haremos con la ayuda de punteros con mucha frecuencia. (a) definimos una variable de puntero, (b) asignar la dirección de una variable a un puntero, y (c)finalmente acceda al valor en la dirección disponible en la variable de puntero. Esto se hace usando un operador unario*que devuelve el valor de la variable ubicada en la dirección especificada por su operando. El siguiente ejemplo hace uso de estas operaciones:
#import <Foundation/Foundation.h>
int main () {
int var = 20; /* actual variable declaration */
int *ip; /* pointer variable declaration */
ip = &var; /* store address of var in pointer variable*/
NSLog(@"Address of var variable: %x\n", &var );
/* address stored in pointer variable */
NSLog(@"Address stored in ip variable: %x\n", ip );
/* access the value using the pointer */
NSLog(@"Value of *ip variable: %d\n", *ip );
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-13 03:20:21.873 demo[24179] Address of var variable: 337ed41c
2013-09-13 03:20:21.873 demo[24179] Address stored in ip variable: 337ed41c
2013-09-13 03:20:21.874 demo[24179] Value of *ip variable: 20
Punteros NULL en Objective-C
Siempre es una buena práctica asignar un valor NULL a una variable de puntero en caso de que no tenga una dirección exacta para asignar. Esto se hace en el momento de la declaración de la variable. Un puntero al que se le asigna NULL se llamanull puntero.
El puntero NULL es una constante con un valor de cero definido en varias bibliotecas estándar. Considere el siguiente programa:
#import <Foundation/Foundation.h>
int main () {
int *ptr = NULL;
NSLog(@"The value of ptr is : %x\n", ptr );
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-13 03:21:19.447 demo[28027] The value of ptr is : 0
En la mayoría de los sistemas operativos, los programas no pueden acceder a la memoria en la dirección 0 porque esa memoria está reservada por el sistema operativo. Sin embargo, la dirección de memoria 0 tiene un significado especial; indica que el puntero no está destinado a apuntar a una ubicación de memoria accesible. Pero por convención, si un puntero contiene el valor nulo (cero), se supone que no apunta a nada.
Para verificar si hay un puntero nulo, puede usar una instrucción if de la siguiente manera:
if(ptr) /* succeeds if p is not null */
if(!ptr) /* succeeds if p is null */
Punteros de Objective-C en detalle
Los punteros tienen muchos conceptos, pero fáciles, y son muy importantes para la programación de Objective-C. A continuación se presentan algunos conceptos importantes de punteros, que deberían ser claros para un programador de Objective-C:
No Señor. | Concepto y descripción |
---|---|
1 | Objective-C - Aritmética de punteros Hay cuatro operadores aritméticos que se pueden usar en punteros: ++, -, +, - |
2 | Objective-C: matriz de punteros Puede definir matrices para contener varios punteros. |
3 | Objective-C: puntero a puntero Objective-C le permite tener un puntero en un puntero y así sucesivamente. |
4 | Pasando punteros a funciones en Objective-C Pasar un argumento por referencia o por dirección permite que la función llamada cambie el argumento pasado en la función que llama. |
5 | Puntero de retorno de funciones en Objective-C Objective-C permite que una función devuelva un puntero a la variable local, variable estática y también a la memoria asignada dinámicamente. |
La cadena en el lenguaje de programación Objective-C se representa mediante NSString y su subclase NSMutableString proporciona varias formas de crear objetos de cadena. La forma más sencilla de crear un objeto de cadena es utilizar la construcción Objective-C @ "..." -
NSString *greeting = @"Hello";
A continuación, se muestra un ejemplo sencillo para crear e imprimir una cadena.
#import <Foundation/Foundation.h>
int main () {
NSString *greeting = @"Hello";
NSLog(@"Greeting message: %@\n", greeting );
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-11 01:21:39.922 demo[23926] Greeting message: Hello
Objective-C admite una amplia gama de métodos para manipular cadenas:
No Señor. | Método y propósito |
---|---|
1 | - (NSString *)capitalizedString; Devuelve una representación en mayúscula del receptor. |
2 | - (unichar)characterAtIndex:(NSUInteger)index; Devuelve el carácter en una posición de matriz determinada. |
3 | - (double)doubleValue; Devuelve el valor de punto flotante del texto del receptor como un doble. |
4 | - (float)floatValue; Devuelve el valor de coma flotante del texto del receptor como flotante. |
5 | - (BOOL)hasPrefix:(NSString *)aString; Devuelve un valor booleano que indica si una cadena dada coincide con los caracteres iniciales del receptor. |
6 | - (BOOL)hasSuffix:(NSString *)aString; Devuelve un valor booleano que indica si una cadena dada coincide con los caracteres finales del receptor. |
7 | - (id)initWithFormat:(NSString *)format ...; Devuelve un objeto NSString inicializado utilizando una cadena de formato determinada como plantilla en la que se sustituyen los valores restantes de los argumentos. |
8 | - (NSInteger)integerValue; Devuelve el valor NSInteger del texto del receptor. |
9 | - (BOOL)isEqualToString:(NSString *)aString; Devuelve un valor booleano que indica si una cadena dada es igual al receptor mediante una comparación literal basada en Unicode. |
10 | - (NSUInteger)length; Devuelve el número de caracteres Unicode en el receptor. |
11 | - (NSString *)lowercaseString; Devuelve la representación del receptor en minúsculas. |
12 | - (NSRange)rangeOfString:(NSString *)aString; Busca y devuelve el rango de la primera aparición de una cadena dada dentro del receptor. |
13 | - (NSString *)stringByAppendingFormat:(NSString *)format ...; Devuelve una cadena hecha al agregar al receptor una cadena construida a partir de una cadena de formato dada y los siguientes argumentos. |
14 | - (NSString *)stringByTrimmingCharactersInSet:(NSCharacterSet *)set; Devuelve una nueva cadena creada al eliminar de ambos extremos los caracteres del receptor contenidos en un conjunto de caracteres dado. |
15 | - (NSString *)substringFromIndex:(NSUInteger)anIndex; Devuelve una nueva cadena que contiene los caracteres del receptor desde el que está en un índice dado hasta el final. |
El siguiente ejemplo hace uso de algunas de las funciones mencionadas anteriormente:
#import <Foundation/Foundation.h>
int main () {
NSString *str1 = @"Hello";
NSString *str2 = @"World";
NSString *str3;
int len ;
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
/* uppercase string */
str3 = [str2 uppercaseString];
NSLog(@"Uppercase String : %@\n", str3 );
/* concatenates str1 and str2 */
str3 = [str1 stringByAppendingFormat:@"World"];
NSLog(@"Concatenated string: %@\n", str3 );
/* total length of str3 after concatenation */
len = [str3 length];
NSLog(@"Length of Str3 : %d\n", len );
/* InitWithFormat */
str3 = [[NSString alloc] initWithFormat:@"%@ %@",str1,str2];
NSLog(@"Using initWithFormat: %@\n", str3 );
[pool drain];
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-11 01:15:45.069 demo[30378] Uppercase String : WORLD
2013-09-11 01:15:45.070 demo[30378] Concatenated string: HelloWorld
2013-09-11 01:15:45.070 demo[30378] Length of Str3 : 10
2013-09-11 01:15:45.070 demo[30378] Using initWithFormat: Hello World
Puede encontrar una lista completa de los métodos relacionados con Objective-C NSString en NSString Class Reference.
Las matrices de Objective-C le permiten definir el tipo de variables que pueden contener varios elementos de datos del mismo tipo pero structure es otro tipo de datos definido por el usuario disponible en la programación de Objective-C que le permite combinar elementos de datos de diferentes tipos.
Las estructuras se utilizan para representar un registro. Suponga que desea realizar un seguimiento de sus libros en una biblioteca. Es posible que desee realizar un seguimiento de los siguientes atributos sobre cada libro:
- Title
- Author
- Subject
- ID del libro
Definición de una estructura
Para definir una estructura, debe utilizar el structdeclaración. La declaración de estructura define un nuevo tipo de datos, con más de un miembro para su programa. El formato de la declaración de estructura es este:
struct [structure tag] {
member definition;
member definition;
...
member definition;
} [one or more structure variables];
los structure tages opcional y cada definición de miembro es una definición de variable normal, como int i; o flotar f; o cualquier otra definición de variable válida. Al final de la definición de la estructura, antes del punto y coma final, puede especificar una o más variables de estructura, pero es opcional. Esta es la forma en que declararía la estructura del libro:
struct Books {
NSString *title;
NSString *author;
NSString *subject;
int book_id;
} book;
Acceso a miembros de estructura
Para acceder a cualquier miembro de una estructura, usamos el member access operator (.). El operador de acceso a miembros se codifica como un punto entre el nombre de la variable de estructura y el miembro de estructura al que deseamos acceder. Usaríasstructpalabra clave para definir variables de tipo de estructura. A continuación se muestra el ejemplo para explicar el uso de la estructura:
#import <Foundation/Foundation.h>
struct Books {
NSString *title;
NSString *author;
NSString *subject;
int book_id;
};
int main() {
struct Books Book1; /* Declare Book1 of type Book */
struct Books Book2; /* Declare Book2 of type Book */
/* book 1 specification */
Book1.title = @"Objective-C Programming";
Book1.author = @"Nuha Ali";
Book1.subject = @"Objective-C Programming Tutorial";
Book1.book_id = 6495407;
/* book 2 specification */
Book2.title = @"Telecom Billing";
Book2.author = @"Zara Ali";
Book2.subject = @"Telecom Billing Tutorial";
Book2.book_id = 6495700;
/* print Book1 info */
NSLog(@"Book 1 title : %@\n", Book1.title);
NSLog(@"Book 1 author : %@\n", Book1.author);
NSLog(@"Book 1 subject : %@\n", Book1.subject);
NSLog(@"Book 1 book_id : %d\n", Book1.book_id);
/* print Book2 info */
NSLog(@"Book 2 title : %@\n", Book2.title);
NSLog(@"Book 2 author : %@\n", Book2.author);
NSLog(@"Book 2 subject : %@\n", Book2.subject);
NSLog(@"Book 2 book_id : %d\n", Book2.book_id);
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-14 04:20:07.947 demo[20591] Book 1 title : Objective-C Programming
2013-09-14 04:20:07.947 demo[20591] Book 1 author : Nuha Ali
2013-09-14 04:20:07.947 demo[20591] Book 1 subject : Objective-C Programming Tutorial
2013-09-14 04:20:07.947 demo[20591] Book 1 book_id : 6495407
2013-09-14 04:20:07.947 demo[20591] Book 2 title : Telecom Billing
2013-09-14 04:20:07.947 demo[20591] Book 2 author : Zara Ali
2013-09-14 04:20:07.947 demo[20591] Book 2 subject : Telecom Billing Tutorial
2013-09-14 04:20:07.947 demo[20591] Book 2 book_id : 6495700
Estructuras como argumentos de función
Puede pasar una estructura como un argumento de función de forma muy similar a como pasa cualquier otra variable o puntero. Accederá a las variables de estructura de manera similar a como lo hizo en el ejemplo anterior:
#import <Foundation/Foundation.h>
struct Books {
NSString *title;
NSString *author;
NSString *subject;
int book_id;
};
@interface SampleClass:NSObject
/* function declaration */
- (void) printBook:( struct Books) book ;
@end
@implementation SampleClass
- (void) printBook:( struct Books) book {
NSLog(@"Book title : %@\n", book.title);
NSLog(@"Book author : %@\n", book.author);
NSLog(@"Book subject : %@\n", book.subject);
NSLog(@"Book book_id : %d\n", book.book_id);
}
@end
int main() {
struct Books Book1; /* Declare Book1 of type Book */
struct Books Book2; /* Declare Book2 of type Book */
/* book 1 specification */
Book1.title = @"Objective-C Programming";
Book1.author = @"Nuha Ali";
Book1.subject = @"Objective-C Programming Tutorial";
Book1.book_id = 6495407;
/* book 2 specification */
Book2.title = @"Telecom Billing";
Book2.author = @"Zara Ali";
Book2.subject = @"Telecom Billing Tutorial";
Book2.book_id = 6495700;
SampleClass *sampleClass = [[SampleClass alloc]init];
/* print Book1 info */
[sampleClass printBook: Book1];
/* Print Book2 info */
[sampleClass printBook: Book2];
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-14 04:34:45.725 demo[8060] Book title : Objective-C Programming
2013-09-14 04:34:45.725 demo[8060] Book author : Nuha Ali
2013-09-14 04:34:45.725 demo[8060] Book subject : Objective-C Programming Tutorial
2013-09-14 04:34:45.725 demo[8060] Book book_id : 6495407
2013-09-14 04:34:45.725 demo[8060] Book title : Telecom Billing
2013-09-14 04:34:45.725 demo[8060] Book author : Zara Ali
2013-09-14 04:34:45.725 demo[8060] Book subject : Telecom Billing Tutorial
2013-09-14 04:34:45.725 demo[8060] Book book_id : 6495700
Punteros a estructuras
Puede definir punteros a estructuras de manera muy similar a como define puntero a cualquier otra variable de la siguiente manera:
struct Books *struct_pointer;
Ahora, puede almacenar la dirección de una variable de estructura en la variable de puntero definida anteriormente. Para encontrar la dirección de una variable de estructura, coloque el operador & antes del nombre de la estructura de la siguiente manera:
struct_pointer = &Book1;
Para acceder a los miembros de una estructura usando un puntero a esa estructura, debe usar el operador -> de la siguiente manera -
struct_pointer->title;
Reescribamos el ejemplo anterior usando el puntero de estructura, espero que esto le sea fácil de entender el concepto -
#import <Foundation/Foundation.h>
struct Books {
NSString *title;
NSString *author;
NSString *subject;
int book_id;
};
@interface SampleClass:NSObject
/* function declaration */
- (void) printBook:( struct Books *) book ;
@end
@implementation SampleClass
- (void) printBook:( struct Books *) book {
NSLog(@"Book title : %@\n", book->title);
NSLog(@"Book author : %@\n", book->author);
NSLog(@"Book subject : %@\n", book->subject);
NSLog(@"Book book_id : %d\n", book->book_id);
}
@end
int main() {
struct Books Book1; /* Declare Book1 of type Book */
struct Books Book2; /* Declare Book2 of type Book */
/* book 1 specification */
Book1.title = @"Objective-C Programming";
Book1.author = @"Nuha Ali";
Book1.subject = @"Objective-C Programming Tutorial";
Book1.book_id = 6495407;
/* book 2 specification */
Book2.title = @"Telecom Billing";
Book2.author = @"Zara Ali";
Book2.subject = @"Telecom Billing Tutorial";
Book2.book_id = 6495700;
SampleClass *sampleClass = [[SampleClass alloc]init];
/* print Book1 info by passing address of Book1 */
[sampleClass printBook:&Book1];
/* print Book2 info by passing address of Book2 */
[sampleClass printBook:&Book2];
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-14 04:38:13.942 demo[20745] Book title : Objective-C Programming
2013-09-14 04:38:13.942 demo[20745] Book author : Nuha Ali
2013-09-14 04:38:13.942 demo[20745] Book subject : Objective-C Programming Tutorial
2013-09-14 04:38:13.942 demo[20745] Book book_id : 6495407
2013-09-14 04:38:13.942 demo[20745] Book title : Telecom Billing
2013-09-14 04:38:13.942 demo[20745] Book author : Zara Ali
2013-09-14 04:38:13.942 demo[20745] Book subject : Telecom Billing Tutorial
2013-09-14 04:38:13.942 demo[20745] Book book_id : 6495700
Campos de bits
Los campos de bits permiten el empaquetado de datos en una estructura. Esto es especialmente útil cuando la memoria o el almacenamiento de datos son limitados. Ejemplos típicos -
Empaquetando varios objetos en una palabra de máquina. por ejemplo, se pueden compactar banderas de 1 bit.
Lectura de formatos de archivo externos: se pueden leer formatos de archivo no estándar. Por ejemplo, números enteros de 9 bits.
Objective-C nos permite hacer esto en una definición de estructura poniendo: bit length después de la variable. Por ejemplo
struct packed_struct {
unsigned int f1:1;
unsigned int f2:1;
unsigned int f3:1;
unsigned int f4:1;
unsigned int type:4;
unsigned int my_int:9;
} pack;
Aquí, la estructura empaquetada contiene 6 miembros: Cuatro indicadores de 1 bit f1..f3, un tipo de 4 bits y un my_int de 9 bits.
Objective-C empaqueta automáticamente los campos de bits anteriores de la forma más compacta posible, siempre que la longitud máxima del campo sea menor o igual que la longitud de la palabra entera de la computadora. Si este no es el caso, algunos compiladores pueden permitir la superposición de memoria para los campos, mientras que otros almacenarían el siguiente campo en la siguiente palabra.
los Objective-C Preprocessorno es parte del compilador, pero es un paso separado en el proceso de compilación. En términos simplistas, un preprocesador de Objective-C es solo una herramienta de sustitución de texto e indica al compilador que realice el preprocesamiento requerido antes de la compilación real. Nos referiremos al preprocesador de Objective-C como OCPP.
Todos los comandos del preprocesador comienzan con un símbolo de almohadilla (#). Debe ser el primer carácter que no esté en blanco y, para facilitar la lectura, una directiva de preprocesador debe comenzar en la primera columna. La siguiente sección enumera todas las directivas importantes del preprocesador:
No Señor. | Directiva y descripción |
---|---|
1 | #define Sustituye a una macro de preprocesador |
2 | #include Inserta un encabezado particular de otro archivo |
3 | #undef Elimina la definición de una macro de preprocesador |
4 | #ifdef Devuelve verdadero si esta macro está definida |
5 | #ifndef Devuelve verdadero si esta macro no está definida |
6 | #if Prueba si una condición de tiempo de compilación es verdadera |
7 | #else La alternativa para #if |
8 | #elif #else an #if in one statement |
9 | #endif Finaliza el preprocesador condicional |
10 | #error Imprime mensaje de error en stderr |
11 | #pragma Emite comandos especiales al compilador mediante un método estandarizado |
Ejemplos de preprocesadores
Analice los siguientes ejemplos para comprender varias directivas.
#define MAX_ARRAY_LENGTH 20
Esta directiva le dice al OCPP que reemplace las instancias de MAX_ARRAY_LENGTH con 20. Use #define para las constantes para aumentar la legibilidad.
#import <Foundation/Foundation.h>
#include "myheader.h"
Estas directivas le dicen al OCPP que obtenga foundation.h de Foundation Frameworky agregue el texto al archivo fuente actual. La siguiente línea le dice a OCPP que obtengamyheader.h del directorio local y agregue el contenido al archivo fuente actual.
#undef FILE_SIZE
#define FILE_SIZE 42
Esto le dice al OCPP que anule la definición de FILE_SIZE existente y lo defina como 42.
#ifndef MESSAGE
#define MESSAGE "You wish!"
#endif
Esto le dice al OCPP que defina MESSAGE solo si MESSAGE aún no está definido.
#ifdef DEBUG
/* Your debugging statements here */
#endif
Esto le dice al OCPP que haga el proceso de las declaraciones adjuntas si DEBUG está definido. Esto es útil si pasa el indicador -DDEBUG al compilador gcc en el momento de la compilación. Esto definirá DEBUG, por lo que puede activar y desactivar la depuración sobre la marcha durante la compilación.
Macros predefinidas
ANSI C define una serie de macros. Aunque cada uno está disponible para su uso en programación, las macros predefinidas no deben modificarse directamente.
No Señor. | Macro y descripción |
---|---|
1 | __DATE__ La fecha actual como un carácter literal en formato "MMM DD AAAA" |
2 | __TIME__ La hora actual como un carácter literal en formato "HH: MM: SS" |
3 | __FILE__ Contiene el nombre de archivo actual como una cadena literal. |
4 | __LINE__ Contiene el número de línea actual como una constante decimal. |
5 | __STDC__ Definido como 1 cuando el compilador cumple con el estándar ANSI. |
Probemos con el siguiente ejemplo:
#import <Foundation/Foundation.h>
int main() {
NSLog(@"File :%s\n", __FILE__ );
NSLog(@"Date :%s\n", __DATE__ );
NSLog(@"Time :%s\n", __TIME__ );
NSLog(@"Line :%d\n", __LINE__ );
NSLog(@"ANSI :%d\n", __STDC__ );
return 0;
}
Cuando el código anterior en un archivo main.m se compila y ejecuta, produce el siguiente resultado:
2013-09-14 04:46:14.859 demo[20683] File :main.m
2013-09-14 04:46:14.859 demo[20683] Date :Sep 14 2013
2013-09-14 04:46:14.859 demo[20683] Time :04:46:14
2013-09-14 04:46:14.859 demo[20683] Line :8
2013-09-14 04:46:14.859 demo[20683] ANSI :1
Operadores de preprocesadores
El preprocesador de Objective-C ofrece los siguientes operadores para ayudarlo a crear macros:
Continuación macro (\)
Por lo general, una macro debe estar contenida en una sola línea. El operador de continuación de macro se utiliza para continuar una macro que es demasiado larga para una sola línea. Por ejemplo
#define message_for(a, b) \
NSLog(@#a " and " #b ": We love you!\n")
Stringize (#)
El operador de cadena o signo de número ('#'), cuando se usa dentro de una definición de macro, convierte un parámetro de macro en una constante de cadena. Este operador solo se puede usar en una macro que tenga un argumento o una lista de parámetros especificados. Por ejemplo
#import <Foundation/Foundation.h>
#define message_for(a, b) \
NSLog(@#a " and " #b ": We love you!\n")
int main(void) {
message_for(Carole, Debra);
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-14 05:46:14.859 demo[20683] Carole and Debra: We love you!
Pegado de tokens (##)
El operador de pegado de tokens (##) dentro de una definición de macro combina dos argumentos. Permite que dos tokens separados en la definición de macro se unan en un solo token. Por ejemplo
#import <Foundation/Foundation.h>
#define tokenpaster(n) NSLog (@"token" #n " = %d", token##n)
int main(void) {
int token34 = 40;
tokenpaster(34);
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-14 05:48:14.859 demo[20683] token34 = 40
Cómo sucedió, porque este ejemplo da como resultado la siguiente salida real del preprocesador:
NSLog (@"token34 = %d", token34);
Este ejemplo muestra la concatenación del token ## n en token34 y aquí hemos usado ambos stringize y token-pasting.
El operador definido ()
El preprocesador definedEl operador se usa en expresiones constantes para determinar si un identificador se define usando #define. Si se define el identificador especificado, el valor es verdadero (distinto de cero). Si el símbolo no está definido, el valor es falso (cero). El operador definido se especifica de la siguiente manera:
#import <Foundation/Foundation.h>
#if !defined (MESSAGE)
#define MESSAGE "You wish!"
#endif
int main(void) {
NSLog(@"Here is the message: %s\n", MESSAGE);
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-14 05:48:19.859 demo[20683] Here is the message: You wish!
Macros parametrizados
Una de las poderosas funciones del OCPP es la capacidad de simular funciones utilizando macros parametrizadas. Por ejemplo, podríamos tener algún código para elevar al cuadrado un número de la siguiente manera:
int square(int x) {
return x * x;
}
Podemos reescribir el código anterior usando una macro de la siguiente manera:
#define square(x) ((x) * (x))
Las macros con argumentos deben definirse mediante la #definedirectiva antes de que se puedan utilizar. La lista de argumentos está entre paréntesis y debe seguir inmediatamente al nombre de la macro. No se permiten espacios entre el nombre de la macro y los paréntesis abiertos. Por ejemplo
#import <Foundation/Foundation.h>
#define MAX(x,y) ((x) > (y) ? (x) : (y))
int main(void) {
NSLog(@"Max between 20 and 10 is %d\n", MAX(10, 20));
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-14 05:52:15.859 demo[20683] Max between 20 and 10 is 20
El lenguaje de programación Objective-C proporciona una palabra clave llamada typedef, que puede utilizar para asignar un nuevo nombre a un tipo. A continuación se muestra un ejemplo para definir un términoBYTE para números de un byte -
typedef unsigned char BYTE;
Después de esta definición de tipo, el identificador BYTE se puede utilizar como abreviatura del tipo unsigned char, for example:.
BYTE b1, b2;
Por convención, las letras mayúsculas se utilizan para estas definiciones para recordar al usuario que el nombre del tipo es realmente una abreviatura simbólica, pero puede utilizar minúsculas, de la siguiente manera:
typedef unsigned char byte;
Puedes usar typedefpara dar un nombre al tipo de datos definido por el usuario también. Por ejemplo, puede usar typedef con estructura para definir un nuevo tipo de datos y luego usar ese tipo de datos para definir variables de estructura directamente de la siguiente manera:
#import <Foundation/Foundation.h>
typedef struct Books {
NSString *title;
NSString *author;
NSString *subject;
int book_id;
} Book;
int main() {
Book book;
book.title = @"Objective-C Programming";
book.author = @"TutorialsPoint";
book.subject = @"Programming tutorial";
book.book_id = 100;
NSLog( @"Book title : %@\n", book.title);
NSLog( @"Book author : %@\n", book.author);
NSLog( @"Book subject : %@\n", book.subject);
NSLog( @"Book Id : %d\n", book.book_id);
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-12 12:21:53.745 demo[31183] Book title : Objective-C Programming
2013-09-12 12:21:53.745 demo[31183] Book author : TutorialsPoint
2013-09-12 12:21:53.745 demo[31183] Book subject : Programming tutorial
2013-09-12 12:21:53.745 demo[31183] Book Id : 100
typedef vs #define
los #define es una directiva Objective-C, que también se utiliza para definir los alias para varios tipos de datos similares a typedef pero con las siguientes diferencias:
los typedef se limita a dar nombres simbólicos a tipos solo mientras que #define también se puede usar para definir alias para valores, como si se pudiera definir 1 como UNO, etc.
los typedef La interpretación es realizada por el compilador donde como #define Las declaraciones son procesadas por el preprocesador.
A continuación se muestra un uso más simple de #define:
#import <Foundation/Foundation.h>
#define TRUE 1
#define FALSE 0
int main( ) {
NSLog( @"Value of TRUE : %d\n", TRUE);
NSLog( @"Value of FALSE : %d\n", FALSE);
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-12 12:23:37.993 demo[5160] Value of TRUE : 1
2013-09-12 12:23:37.994 demo[5160] Value of FALSE : 0
La conversión de tipos es una forma de convertir una variable de un tipo de datos a otro tipo de datos. Por ejemplo, si desea almacenar un valor largo en un entero simple, puede escribir cast long a int. Puede convertir valores de un tipo a otro explícitamente utilizando elcast operator como sigue -
(type_name) expression
En Objective-C, generalmente usamos CGFloat para realizar operaciones de punto flotante, que se deriva del tipo básico de float en el caso de 32 bits y doble en el caso de 64 bits. Considere el siguiente ejemplo en el que el operador de conversión hace que la división de una variable entera por otra se realice como una operación de punto flotante:
#import <Foundation/Foundation.h>
int main() {
int sum = 17, count = 5;
CGFloat mean;
mean = (CGFloat) sum / count;
NSLog(@"Value of mean : %f\n", mean );
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-11 01:35:40.047 demo[20634] Value of mean : 3.400000
Cabe señalar aquí que el operador de conversión tiene prioridad sobre la división, por lo que el valor de sum primero se convierte a tipo double y finalmente se divide por conteo dando un valor doble.
Las conversiones de tipos pueden ser implícitas, lo que el compilador realiza automáticamente o se pueden especificar explícitamente mediante el uso de la cast operator. Se considera una buena práctica de programación utilizar el operador de conversión siempre que sea necesario realizar conversiones de tipo.
Promoción de enteros
La promoción de enteros es el proceso mediante el cual los valores de tipo entero "menores" que int o unsigned int se convierten en int o unsigned int. Considere un ejemplo de agregar un carácter en un int -
#import <Foundation/Foundation.h>
int main() {
int i = 17;
char c = 'c'; /* ascii value is 99 */
int sum;
sum = i + c;
NSLog(@"Value of sum : %d\n", sum );
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-11 01:38:28.492 demo[980] Value of sum : 116
Aquí, el valor de la suma es 116 porque el compilador realiza una promoción de enteros y convierte el valor de 'c' en ascii antes de realizar la operación de suma real.
Conversión aritmética habitual
los usual arithmetic conversionsse realizan implícitamente para convertir sus valores en un tipo común. El compilador primero realiza la promoción de enteros , si los operandos aún tienen tipos diferentes, se convierten al tipo que aparece más alto en la siguiente jerarquía:
Las conversiones aritméticas habituales no se realizan para los operadores de asignación, ni para los operadores lógicos && y ||. Tomemos el siguiente ejemplo para entender el concepto:
#import <Foundation/Foundation.h>
int main() {
int i = 17;
char c = 'c'; /* ascii value is 99 */
CGFloat sum;
sum = i + c;
NSLog(@"Value of sum : %f\n", sum );
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-11 01:41:39.192 demo[15351] Value of sum : 116.000000
Aquí, es simple entender que la primera c se convierte en un entero, pero debido a que el valor final es flotante, se aplica la conversión aritmética habitual y el compilador convierte i y c en flotantes y los agrega, lo que produce un resultado flotante.
Método NSLog
Para imprimir registros, usamos el método NSLog en el lenguaje de programación Objective-C que hemos usado directamente desde el ejemplo de Hello World.
Veamos un código simple que imprimiría las palabras "Hola mundo" -
#import <Foundation/Foundation.h>
int main() {
NSLog(@"Hello, World! \n");
return 0;
}
Ahora, cuando compilemos y ejecutemos el programa, obtendremos el siguiente resultado.
2013-09-16 00:32:50.888 demo[16669] Hello, World!
Deshabilitar registros en aplicaciones en vivo
Dado que los NSLogs que usamos en nuestra aplicación, se imprimirán en los registros del dispositivo y no es bueno imprimir los registros en una compilación en vivo. Por lo tanto, usamos una definición de tipo para imprimir registros y podemos usarlos como se muestra a continuación.
#import <Foundation/Foundation.h>
#if DEBUG == 0
#define DebugLog(...)
#elif DEBUG == 1
#define DebugLog(...) NSLog(__VA_ARGS__)
#endif
int main() {
DebugLog(@"Debug log, our custom addition gets \
printed during debug only" );
NSLog(@"NSLog gets printed always" );
return 0;
}
Ahora, cuando compilemos y ejecutemos el programa en modo de depuración, obtendremos el siguiente resultado.
2013-09-11 02:47:07.723 demo[618] Debug log, our custom addition gets printed during debug only
2013-09-11 02:47:07.723 demo[618] NSLog gets printed always
Ahora, cuando compilemos y ejecutemos el programa en modo de lanzamiento, obtendremos el siguiente resultado.
2013-09-11 02:47:45.248 demo[3158] NSLog gets printed always
En la programación de Objective-C, el manejo de errores se proporciona con la clase NSError disponible en Foundation framework.
Un objeto NSError encapsula información de error más rica y extensible de lo que es posible usando solo un código de error o una cadena de error. Los atributos principales de un objeto NSError son un dominio de error (representado por una cadena), un código de error específico del dominio y un diccionario de información de usuario que contiene información específica de la aplicación.
NSError
Los programas Objective-C utilizan objetos NSError para transmitir información sobre los errores en tiempo de ejecución sobre los que los usuarios deben estar informados. En la mayoría de los casos, un programa muestra esta información de error en un cuadro de diálogo o en una hoja. Pero también puede interpretar la información y pedirle al usuario que intente recuperarse del error o que intente corregir el error por su cuenta.
El objeto NSError consta de:
Domain - El dominio de error puede ser uno de los dominios NSError predefinidos o una cadena arbitraria que describe un dominio personalizado y el dominio no debe ser nulo.
Code - El código de error del error.
User Info - El diccionario userInfo para el error y userInfo puede ser nulo.
El siguiente ejemplo muestra cómo crear un error personalizado
NSString *domain = @"com.MyCompany.MyApplication.ErrorDomain";
NSString *desc = NSLocalizedString(@"Unable to complete the process", @"");
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : desc };
NSError *error = [NSError errorWithDomain:domain code:-101 userInfo:userInfo];
Aquí está el código completo de la muestra de error anterior pasada como referencia a un puntero:
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
-(NSString *) getEmployeeNameForID:(int) id withError:(NSError **)errorPtr;
@end
@implementation SampleClass
-(NSString *) getEmployeeNameForID:(int) id withError:(NSError **)errorPtr {
if(id == 1) {
return @"Employee Test Name";
} else {
NSString *domain = @"com.MyCompany.MyApplication.ErrorDomain";
NSString *desc =@"Unable to complete the process";
NSDictionary *userInfo = [[NSDictionary alloc]
initWithObjectsAndKeys:desc,
@"NSLocalizedDescriptionKey",NULL];
*errorPtr = [NSError errorWithDomain:domain code:-101
userInfo:userInfo];
return @"";
}
}
@end
int main() {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
SampleClass *sampleClass = [[SampleClass alloc]init];
NSError *error = nil;
NSString *name1 = [sampleClass getEmployeeNameForID:1 withError:&error];
if(error) {
NSLog(@"Error finding Name1: %@",error);
} else {
NSLog(@"Name1: %@",name1);
}
error = nil;
NSString *name2 = [sampleClass getEmployeeNameForID:2 withError:&error];
if(error) {
NSLog(@"Error finding Name2: %@",error);
} else {
NSLog(@"Name2: %@",name2);
}
[pool drain];
return 0;
}
En el ejemplo anterior, devolvemos un nombre si el id es 1; de lo contrario, establecemos el objeto de error definido por el usuario.
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-14 18:01:00.809 demo[27632] Name1: Employee Test Name
2013-09-14 18:01:00.809 demo[27632] Error finding Name2: Unable to complete the process
Es posible pasar algunos valores de la línea de comando a sus programas Objective-C cuando se ejecutan. Estos valores se llamancommand line arguments y muchas veces son importantes para su programa, especialmente cuando desea controlar su programa desde fuera en lugar de codificar esos valores dentro del código.
Los argumentos de la línea de comando se manejan usando argumentos de la función main () donde argc se refiere al número de argumentos pasados, y argv[]es una matriz de punteros, que apunta a cada argumento que se pasa al programa. A continuación se muestra un ejemplo simple, que verifica si hay algún argumento proporcionado desde la línea de comando y toma las medidas correspondientes:
#import <Foundation/Foundation.h>
int main( int argc, char *argv[] ) {
if( argc == 2 ) {
NSLog(@"The argument supplied is %s\n", argv[1]);
} else if( argc > 2 ) {
NSLog(@"Too many arguments supplied.\n");
} else {
NSLog(@"One argument expected.\n");
}
}
Cuando el código anterior se compila y ejecuta con un solo argumento, diga "prueba", produce el siguiente resultado.
2013-09-13 03:01:17.333 demo[7640] The argument supplied is testing
Cuando el código anterior se compila y ejecuta con dos argumentos, digamos testing1 y testing2, produce el siguiente resultado.
2013-09-13 03:01:18.333 demo[7640] Too many arguments supplied.
Cuando el código anterior se compila y ejecuta sin pasar ningún argumento, produce el siguiente resultado.
2013-09-13 03:01:18.333 demo[7640] One argument expected
se debe notar que argv[0] contiene el nombre del programa y argv[1]es un puntero al primer argumento de línea de comandos proporcionado, y * argv [n] es el último argumento. Si no se proporcionan argumentos, argc será uno; de lo contrario, si pasa un argumento, entoncesargc se fija en 2.
Pasas todos los argumentos de la línea de comando separados por un espacio, pero si el argumento en sí tiene un espacio, entonces puedes pasar dichos argumentos poniéndolos entre comillas dobles "" o comillas simples ". Reescribamos el ejemplo anterior una vez más, donde imprimiremos el nombre del programa y también pasamos un argumento de línea de comandos poniendo entre comillas dobles:
#import <Foundation/Foundation.h>
int main( int argc, char *argv[] ) {
NSLog(@"Program name %s\n", argv[0]);
if( argc == 2 ) {
NSLog(@"The argument supplied is %s\n", argv[1]);
} else if( argc > 2 ) {
NSLog(@"Too many arguments supplied.\n");
} else {
NSLog(@"One argument expected.\n");
}
return 0;
}
Cuando el código anterior se compila y ejecuta con un solo argumento separado por un espacio pero entre comillas dobles dice "Testing1 Testing2", produce el siguiente resultado.
2017-11-30 06:36:59.081 main[71010] Program name main
2017-11-30 06:36:59.082 main[71010] One argument expected.
El propósito principal del lenguaje de programación Objective-C es agregar orientación a objetos al lenguaje de programación C y las clases son la característica central de Objective-C que admiten la programación orientada a objetos y a menudo se denominan tipos definidos por el usuario.
Una clase se usa para especificar la forma de un objeto y combina la representación de datos y métodos para manipular esos datos en un paquete ordenado. Los datos y métodos dentro de una clase se denominan miembros de la clase.
Características de Objective-C
La clase se define en dos secciones diferentes, a saber @interface y @implementation.
Casi todo está en forma de objetos.
Los objetos reciben mensajes y los objetos a menudo se denominan receptores.
Los objetos contienen variables de instancia.
Los objetos y las variables de instancia tienen alcance.
Las clases ocultan la implementación de un objeto.
Las propiedades se utilizan para proporcionar acceso a variables de instancia de clase en otras clases.
Definiciones de clase Objective-C
Cuando define una clase, define un plano para un tipo de datos. En realidad, esto no define ningún dato, pero sí define lo que significa el nombre de la clase, es decir, en qué consistirá un objeto de la clase y qué operaciones se pueden realizar en dicho objeto.
Una definición de clase comienza con la palabra clave @interfaceseguido del nombre de la interfaz (clase); y el cuerpo de la clase, encerrado por un par de llaves. En Objective-C, todas las clases se derivan de la clase base llamadaNSObject. Es la superclase de todas las clases de Objective-C. Proporciona métodos básicos como la asignación de memoria y la inicialización. Por ejemplo, definimos el tipo de datos Box usando la palabra claveclass como sigue -
@interface Box:NSObject {
//Instance variables
double length; // Length of a box
double breadth; // Breadth of a box
}
@property(nonatomic, readwrite) double height; // Property
@end
Las variables de instancia son privadas y solo se puede acceder a ellas dentro de la implementación de la clase.
Asignar e inicializar objetos Objective-C
Una clase proporciona los planos de los objetos, por lo que básicamente un objeto se crea a partir de una clase. Declaramos objetos de una clase con exactamente el mismo tipo de declaración que declaramos variables de tipos básicos. Las siguientes declaraciones declaran dos objetos de la clase Box:
Box box1 = [[Box alloc]init]; // Create box1 object of type Box
Box box2 = [[Box alloc]init]; // Create box2 object of type Box
Ambos objetos box1 y box2 tendrán su propia copia de miembros de datos.
Acceso a los miembros de datos
Se puede acceder a las propiedades de los objetos de una clase mediante el operador de acceso directo a miembros (.). Intentemos el siguiente ejemplo para aclarar las cosas:
#import <Foundation/Foundation.h>
@interface Box:NSObject {
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
}
@property(nonatomic, readwrite) double height; // Property
-(double) volume;
@end
@implementation Box
@synthesize height;
-(id)init {
self = [super init];
length = 1.0;
breadth = 1.0;
return self;
}
-(double) volume {
return length*breadth*height;
}
@end
int main() {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Box *box1 = [[Box alloc]init]; // Create box1 object of type Box
Box *box2 = [[Box alloc]init]; // Create box2 object of type Box
double volume = 0.0; // Store the volume of a box here
// box 1 specification
box1.height = 5.0;
// box 2 specification
box2.height = 10.0;
// volume of box 1
volume = [box1 volume];
NSLog(@"Volume of Box1 : %f", volume);
// volume of box 2
volume = [box2 volume];
NSLog(@"Volume of Box2 : %f", volume);
[pool drain];
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-22 21:25:33.314 ClassAndObjects[387:303] Volume of Box1 : 5.000000
2013-09-22 21:25:33.316 ClassAndObjects[387:303] Volume of Box2 : 10.000000
Propiedades
Las propiedades se introducen en Objective-C para garantizar que se pueda acceder a la variable de instancia de la clase fuera de la clase.
Las propiedades comienzan con @property, que es una palabra clave
Le siguen especificadores de acceso, que son atómicos o no atómicos, de lectura y escritura o de solo lectura y fuertes, inseguros_no retenidos o débiles. Esto varía según el tipo de variable. Para cualquier tipo de puntero, podemos usar fuerte, unsafe_unretained o débil. Del mismo modo, para otros tipos, podemos usar readwrite o readonly.
A esto le sigue el tipo de datos de la variable.
Finalmente, tenemos el nombre de la propiedad terminado con un punto y coma.
Podemos agregar una declaración de síntesis en la clase de implementación. Pero en el último XCode, la parte de síntesis está a cargo del XCode y no es necesario incluir la declaración de síntesis.
Solo es posible con las propiedades podemos acceder a las variables de instancia de la clase. En realidad, se crean métodos getter y setter internos para las propiedades.
Por ejemplo, supongamos que tenemos una propiedad @property (nonatomic ,readonly ) BOOL isDone. Debajo del capó, hay setters y getters creados como se muestra a continuación.
-(void)setIsDone(BOOL)isDone;
-(BOOL)isDone;
Uno de los conceptos más importantes de la programación orientada a objetos es el de herencia. La herencia nos permite definir una clase en términos de otra clase, lo que facilita la creación y el mantenimiento de una aplicación. Esto también brinda la oportunidad de reutilizar la funcionalidad del código y un tiempo de implementación rápido.
Al crear una clase, en lugar de escribir miembros de datos y funciones de miembros completamente nuevos, el programador puede designar que la nueva clase herede los miembros de una clase existente. Esta clase existente se llamabase clase, y la nueva clase se conoce como el derived clase.
La idea de herencia implementa la is arelación. Por ejemplo, mamífero IS-A animal, perro IS-A mamífero, por lo tanto perro IS-A animal también y así sucesivamente.
Clases base y derivadas
Objective-C solo permite la herencia multinivel, es decir, puede tener solo una clase base pero permite la herencia multinivel. Todas las clases en Objective-C se derivan de la superclaseNSObject.
@interface derived-class: base-class
Considere una clase base Person y su clase derivada Employee como sigue -
#import <Foundation/Foundation.h>
@interface Person : NSObject {
NSString *personName;
NSInteger personAge;
}
- (id)initWithName:(NSString *)name andAge:(NSInteger)age;
- (void)print;
@end
@implementation Person
- (id)initWithName:(NSString *)name andAge:(NSInteger)age {
personName = name;
personAge = age;
return self;
}
- (void)print {
NSLog(@"Name: %@", personName);
NSLog(@"Age: %ld", personAge);
}
@end
@interface Employee : Person {
NSString *employeeEducation;
}
- (id)initWithName:(NSString *)name andAge:(NSInteger)age
andEducation:(NSString *)education;
- (void)print;
@end
@implementation Employee
- (id)initWithName:(NSString *)name andAge:(NSInteger)age
andEducation: (NSString *)education {
personName = name;
personAge = age;
employeeEducation = education;
return self;
}
- (void)print {
NSLog(@"Name: %@", personName);
NSLog(@"Age: %ld", personAge);
NSLog(@"Education: %@", employeeEducation);
}
@end
int main(int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSLog(@"Base class Person Object");
Person *person = [[Person alloc]initWithName:@"Raj" andAge:5];
[person print];
NSLog(@"Inherited Class Employee Object");
Employee *employee = [[Employee alloc]initWithName:@"Raj"
andAge:5 andEducation:@"MBA"];
[employee print];
[pool drain];
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-22 21:20:09.842 Inheritance[349:303] Base class Person Object
2013-09-22 21:20:09.844 Inheritance[349:303] Name: Raj
2013-09-22 21:20:09.844 Inheritance[349:303] Age: 5
2013-09-22 21:20:09.845 Inheritance[349:303] Inherited Class Employee Object
2013-09-22 21:20:09.845 Inheritance[349:303] Name: Raj
2013-09-22 21:20:09.846 Inheritance[349:303] Age: 5
2013-09-22 21:20:09.846 Inheritance[349:303] Education: MBA
Control de acceso y herencia
Una clase derivada puede acceder a todos los miembros privados de su clase base si está definida en la clase de interfaz, pero no puede acceder a los miembros privados que están definidos en el archivo de implementación.
Podemos resumir los diferentes tipos de acceso según quién puede acceder a ellos de la siguiente manera:
Una clase derivada hereda todos los métodos y variables de la clase base con las siguientes excepciones:
Las variables declaradas en el archivo de implementación con la ayuda de extensiones no son accesibles.
Los métodos declarados en el archivo de implementación con la ayuda de extensiones no son accesibles.
En caso de que la clase heredada implemente el método en la clase base, entonces se ejecuta el método en la clase derivada.
La palabra polymorphismsignifica tener muchas formas. Normalmente, el polimorfismo se produce cuando hay una jerarquía de clases y están relacionadas por herencia.
El polimorfismo de Objective-C significa que una llamada a una función miembro hará que se ejecute una función diferente dependiendo del tipo de objeto que invoca la función.
Considere el ejemplo, tenemos una clase Shape que proporciona la interfaz básica para todas las formas. Square y Rectangle se derivan de la clase base Shape.
Tenemos el método printArea que se mostrará sobre la función OOP polymorphism.
#import <Foundation/Foundation.h>
@interface Shape : NSObject {
CGFloat area;
}
- (void)printArea;
- (void)calculateArea;
@end
@implementation Shape
- (void)printArea {
NSLog(@"The area is %f", area);
}
- (void)calculateArea {
}
@end
@interface Square : Shape {
CGFloat length;
}
- (id)initWithSide:(CGFloat)side;
- (void)calculateArea;
@end
@implementation Square
- (id)initWithSide:(CGFloat)side {
length = side;
return self;
}
- (void)calculateArea {
area = length * length;
}
- (void)printArea {
NSLog(@"The area of square is %f", area);
}
@end
@interface Rectangle : Shape {
CGFloat length;
CGFloat breadth;
}
- (id)initWithLength:(CGFloat)rLength andBreadth:(CGFloat)rBreadth;
@end
@implementation Rectangle
- (id)initWithLength:(CGFloat)rLength andBreadth:(CGFloat)rBreadth {
length = rLength;
breadth = rBreadth;
return self;
}
- (void)calculateArea {
area = length * breadth;
}
@end
int main(int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Shape *square = [[Square alloc]initWithSide:10.0];
[square calculateArea];
[square printArea];
Shape *rect = [[Rectangle alloc]
initWithLength:10.0 andBreadth:5.0];
[rect calculateArea];
[rect printArea];
[pool drain];
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-22 21:21:50.785 Polymorphism[358:303] The area of square is 100.000000
2013-09-22 21:21:50.786 Polymorphism[358:303] The area is 50.000000
En el ejemplo anterior basado en la disponibilidad del método calculateArea y printArea, ya sea el método en la clase base o la clase derivada ejecutada.
El polimorfismo maneja el cambio de métodos entre la clase base y la clase derivada según la implementación del método de las dos clases.
Todos los programas de Objective-C se componen de los siguientes dos elementos fundamentales:
Program statements (code) - Esta es la parte de un programa que realiza acciones y se llaman métodos.
Program data - Los datos son la información del programa que se ve afectada por las funciones del programa.
La encapsulación es un concepto de programación orientada a objetos que une los datos y las funciones que manipulan los datos y que los mantiene a salvo de interferencias externas y uso indebido. La encapsulación de datos llevó al importante concepto de programación orientada a objetos dedata hiding.
Data encapsulation es un mecanismo para agrupar los datos y las funciones que los utilizan, y data abstraction es un mecanismo para exponer solo las interfaces y ocultar al usuario los detalles de implementación.
Objective-C admite las propiedades de encapsulación y ocultación de datos mediante la creación de tipos definidos por el usuario, llamados classes. Por ejemplo
@interface Adder : NSObject {
NSInteger total;
}
- (id)initWithInitialNumber:(NSInteger)initialNumber;
- (void)addNumber:(NSInteger)newNumber;
- (NSInteger)getTotal;
@end
La variable total es privada y no podemos acceder desde fuera de la clase. Esto significa que solo pueden acceder a ellos otros miembros de la clase Adder y no ninguna otra parte de su programa. Esta es una forma de lograr la encapsulación.
Los métodos dentro del archivo de interfaz son accesibles y tienen un alcance público.
Hay métodos privados, que se escriben con la ayuda de extensions, que aprenderemos en los próximos capítulos.
Ejemplo de encapsulación de datos
Cualquier programa de Objective-C en el que implemente una clase con variables de miembros públicos y privados es un ejemplo de encapsulación y abstracción de datos. Considere el siguiente ejemplo:
#import <Foundation/Foundation.h>
@interface Adder : NSObject {
NSInteger total;
}
- (id)initWithInitialNumber:(NSInteger)initialNumber;
- (void)addNumber:(NSInteger)newNumber;
- (NSInteger)getTotal;
@end
@implementation Adder
-(id)initWithInitialNumber:(NSInteger)initialNumber {
total = initialNumber;
return self;
}
- (void)addNumber:(NSInteger)newNumber {
total = total + newNumber;
}
- (NSInteger)getTotal {
return total;
}
@end
int main(int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Adder *adder = [[Adder alloc]initWithInitialNumber:10];
[adder addNumber:5];
[adder addNumber:4];
NSLog(@"The total is %ld",[adder getTotal]);
[pool drain];
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
2013-09-22 21:17:30.485 DataEncapsulation[317:303] The total is 19
La clase anterior suma números y devuelve la suma. Los miembros públicosaddNum y getTotal son las interfaces con el mundo exterior y un usuario necesita conocerlas para usar la clase. El miembro privadototal es algo que está oculto al mundo exterior, pero es necesario para que la clase funcione correctamente.
Estrategia de diseño
La mayoría de nosotros hemos aprendido a través de una amarga experiencia a hacer que los miembros de la clase sean privados por defecto a menos que realmente necesitemos exponerlos. Eso es simplemente buenoencapsulation.
Es importante comprender la encapsulación de datos, ya que es una de las características principales de todos los lenguajes de programación orientada a objetos (OOP), incluido Objective-C.
A veces, puede encontrar que desea ampliar una clase existente agregando un comportamiento que es útil solo en ciertas situaciones. Para agregar dicha extensión a las clases existentes, Objective-C proporcionacategories y extensions.
Si necesita agregar un método a una clase existente, tal vez, para agregar funcionalidad para que sea más fácil hacer algo en su propia aplicación, la forma más fácil es usar una categoría.
La sintaxis para declarar una categoría utiliza la palabra clave @interface, al igual que una descripción de clase estándar de Objective-C, pero no indica ninguna herencia de una subclase. En cambio, especifica el nombre de la categoría entre paréntesis, así:
@interface ClassName (CategoryName)
@end
Características de la categoría
Se puede declarar una categoría para cualquier clase, incluso si no tiene el código fuente de implementación original.
Cualquier método que declare en una categoría estará disponible para todas las instancias de la clase original, así como para las subclases de la clase original.
En tiempo de ejecución, no hay diferencia entre un método agregado por una categoría y uno implementado por la clase original.
Ahora, veamos una implementación de categoría de muestra. Agreguemos una categoría a la clase Cocoa NSString. Esta categoría nos permitirá agregar un nuevo método getCopyRightString que nos ayuda a devolver la cadena de derechos de autor. Se muestra a continuación.
#import <Foundation/Foundation.h>
@interface NSString(MyAdditions)
+(NSString *)getCopyRightString;
@end
@implementation NSString(MyAdditions)
+(NSString *)getCopyRightString {
return @"Copyright TutorialsPoint.com 2013";
}
@end
int main(int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *copyrightString = [NSString getCopyRightString];
NSLog(@"Accessing Category: %@",copyrightString);
[pool drain];
return 0;
}
Ahora, cuando compilemos y ejecutemos el programa, obtendremos el siguiente resultado.
2013-09-22 21:19:12.125 Categories[340:303] Accessing Category: Copyright TutorialsPoint.com 2013
Aunque los métodos agregados por una categoría están disponibles para todas las instancias de la clase y sus subclases, deberá importar el archivo de encabezado de categoría en cualquier archivo de código fuente donde desee utilizar los métodos adicionales; de lo contrario, se encontrará con advertencias y errores del compilador.
En nuestro ejemplo, dado que solo tenemos una clase única, no hemos incluido ningún archivo de encabezado, en tal caso deberíamos incluir los archivos de encabezado como se dijo anteriormente.
Antes de comenzar con Posing en Objective-C, me gustaría informarle que Posing se declaró obsoleto en Mac OS X 10.5 y no está disponible para su uso posterior. Entonces, para aquellos que no estén preocupados por estos métodos obsoletos, pueden omitir este capítulo.
Objective-C permite que una clase reemplace completamente a otra clase dentro de un programa. Se dice que la clase que reemplaza "se hace pasar por" la clase objetivo.
Para las versiones que admitían la presentación, todos los mensajes enviados a la clase de destino son recibidos por la clase de presentación.
NSObject contiene el método poseAsClass: que nos permite reemplazar la clase existente como se dijo anteriormente.
Restricciones para posar
Una clase solo puede presentarse como una de sus superclases directas o indirectas.
La clase de presentación 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.
Una clase de presentación puede llamar a métodos anulados a través de super, incorporando así la implementación de la clase de destino.
Una clase de poses puede anular los métodos definidos en categorías.
#import <Foundation/Foundation.h>
@interface MyString : NSString
@end
@implementation MyString
- (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target
withString:(NSString *)replacement {
NSLog(@"The Target string is %@",target);
NSLog(@"The Replacement string is %@",replacement);
}
@end
int main() {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
[MyString poseAsClass:[NSString class]];
NSString *string = @"Test";
[string stringByReplacingOccurrencesOfString:@"a" withString:@"c"];
[pool drain];
return 0;
}
Ahora, cuando compilemos y ejecutemos el programa en un Mac OS X anterior (V_10.5 o anterior), obtendremos el siguiente resultado.
2013-09-22 21:23:46.829 Posing[372:303] The Target string is a
2013-09-22 21:23:46.830 Posing[372:303] The Replacement string is c
En el ejemplo anterior, simplemente contaminamos el método original con nuestra implementación y esto se verá afectado en todas las operaciones de NSString con el método anterior.
Una extensión de clase tiene cierta similitud con una categoría, pero solo se puede agregar a una clase para la que tiene el código fuente en tiempo de compilación (la clase se compila al mismo tiempo que la extensión de clase).
Los métodos declarados por una extensión de clase se implementan en el bloque de implementación de la clase original, por lo que no puede, por ejemplo, declarar una extensión de clase en una clase de marco, como una clase Cocoa o Cocoa Touch como NSString.
Las extensiones son en realidad categorías sin el nombre de la categoría. A menudo se lo conoce comoanonymous categories.
La sintaxis para declarar una extensión usa la palabra clave @interface, al igual que una descripción de clase estándar de Objective-C, pero no indica ninguna herencia de una subclase. En cambio, solo agrega paréntesis, como se muestra a continuación:
@interface ClassName ()
@end
Características de las extensiones
No se puede declarar una extensión para ninguna clase, solo para las clases que tenemos la implementación original del código fuente.
Una extensión es agregar métodos privados y variables privadas que solo son específicas de la clase.
Cualquier método o variable declarada dentro de las extensiones no es accesible ni siquiera para las clases heredadas.
Ejemplo de extensiones
Creemos una clase SampleClass que tenga una extensión. En la extensión, tengamos una variable privada internalID.
Entonces, tengamos un método getExternalID que devuelva el externalID después de procesar el internalID.
El ejemplo se muestra a continuación y esto no funcionará en el compilador en línea.
#import <Foundation/Foundation.h>
@interface SampleClass : NSObject {
NSString *name;
}
- (void)setInternalID;
- (NSString *)getExternalID;
@end
@interface SampleClass() {
NSString *internalID;
}
@end
@implementation SampleClass
- (void)setInternalID {
internalID = [NSString stringWithFormat:
@"UNIQUEINTERNALKEY%dUNIQUEINTERNALKEY",arc4random()%100];
}
- (NSString *)getExternalID {
return [internalID stringByReplacingOccurrencesOfString:
@"UNIQUEINTERNALKEY" withString:@""];
}
@end
int main(int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass setInternalID];
NSLog(@"ExternalID: %@",[sampleClass getExternalID]);
[pool drain];
return 0;
}
Ahora, cuando compilemos y ejecutemos el programa, obtendremos el siguiente resultado.
2013-09-22 21:18:31.754 Extensions[331:303] ExternalID: 51
En el ejemplo anterior, podemos ver que el ID interno no se devuelve directamente. Aquí eliminamos UNIQUEINTERNALKEY y solo hacemos que el valor restante esté disponible para el método getExternalID.
El ejemplo anterior solo usa una operación de cadena, pero puede tener muchas características como cifrado / descifrado, etc.
Objective-C le permite definir protocolos, que declaran los métodos que se espera usar para una situación particular. Los protocolos se implementan en las clases que se ajustan al protocolo.
Un ejemplo simple sería una clase de manejo de URL de red, tendrá un protocolo con métodos como el método delegado processCompleted que indica la clase de llamada una vez que finaliza la operación de obtención de URL de red.
A continuación se muestra una sintaxis de protocolo.
@protocol ProtocolName
@required
// list of required methods
@optional
// list of optional methods
@end
Los métodos bajo palabra clave @required deben implementarse en las clases que se ajustan al protocolo y los métodos bajo @optional la palabra clave es opcional para implementar.
Aquí está la sintaxis de la clase conforme al protocolo
@interface MyClass : NSObject <MyProtocol>
...
@end
Esto significa que cualquier instancia de MyClass responderá no solo a los métodos declarados específicamente en la interfaz, sino que MyClass también proporciona implementaciones para los métodos requeridos en MyProtocol. No es necesario volver a declarar los métodos de protocolo en la interfaz de clase: la adopción del protocolo es suficiente.
Si necesita una clase para adoptar varios protocolos, puede especificarlos como una lista separada por comas. Tenemos un objeto delegado que contiene la referencia del objeto de llamada que implementa el protocolo.
A continuación se muestra un ejemplo.
#import <Foundation/Foundation.h>
@protocol PrintProtocolDelegate
- (void)processCompleted;
@end
@interface PrintClass :NSObject {
id delegate;
}
- (void) printDetails;
- (void) setDelegate:(id)newDelegate;
@end
@implementation PrintClass
- (void)printDetails {
NSLog(@"Printing Details");
[delegate processCompleted];
}
- (void) setDelegate:(id)newDelegate {
delegate = newDelegate;
}
@end
@interface SampleClass:NSObject<PrintProtocolDelegate>
- (void)startAction;
@end
@implementation SampleClass
- (void)startAction {
PrintClass *printClass = [[PrintClass alloc]init];
[printClass setDelegate:self];
[printClass printDetails];
}
-(void)processCompleted {
NSLog(@"Printing Process Completed");
}
@end
int main(int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass startAction];
[pool drain];
return 0;
}
Ahora, cuando compilemos y ejecutemos el programa, obtendremos el siguiente resultado.
2013-09-22 21:15:50.362 Protocols[275:303] Printing Details
2013-09-22 21:15:50.364 Protocols[275:303] Printing Process Completed
En el ejemplo anterior, hemos visto cómo se llaman y ejecutan los métodos delgate. Comienza con startAction, una vez que se completa el proceso, se llama al método delegado processCompleted para indicar que se completa la operación.
En cualquier aplicación de iOS o Mac, nunca tendremos un programa implementado sin un delegado. Entonces es importante que entendamos el uso de delegados. Los objetos delegados deben usar el tipo de propiedad unsafe_unretained para evitar pérdidas de memoria.
El enlace dinámico determina el método a invocar en tiempo de ejecución en lugar de en tiempo de compilación. El enlace dinámico también se conoce como enlace tardío.
En Objective-C, todos los métodos se resuelven dinámicamente en tiempo de ejecución. El código exacto ejecutado está determinado por el nombre del método (el selector) y el objeto receptor.
La unión dinámica permite el polimorfismo. Por ejemplo, considere una colección de objetos que incluyen Rectangle y Square. Cada objeto tiene su propia implementación de un método printArea.
En el siguiente fragmento de código, el código real que debe ejecutar la expresión [anObject printArea] se determina en tiempo de ejecución. El sistema de tiempo de ejecución usa el selector para la ejecución del método para identificar el método apropiado en cualquier clase de un objeto que resulte ser.
Veamos un código simple que explicaría el enlace dinámico.
#import <Foundation/Foundation.h>
@interface Square:NSObject {
float area;
}
- (void)calculateAreaOfSide:(CGFloat)side;
- (void)printArea;
@end
@implementation Square
- (void)calculateAreaOfSide:(CGFloat)side {
area = side * side;
}
- (void)printArea {
NSLog(@"The area of square is %f",area);
}
@end
@interface Rectangle:NSObject {
float area;
}
- (void)calculateAreaOfLength:(CGFloat)length andBreadth:(CGFloat)breadth;
- (void)printArea;
@end
@implementation Rectangle
- (void)calculateAreaOfLength:(CGFloat)length andBreadth:(CGFloat)breadth {
area = length * breadth;
}
- (void)printArea {
NSLog(@"The area of Rectangle is %f",area);
}
@end
int main() {
Square *square = [[Square alloc]init];
[square calculateAreaOfSide:10.0];
Rectangle *rectangle = [[Rectangle alloc]init];
[rectangle calculateAreaOfLength:10.0 andBreadth:5.0];
NSArray *shapes = [[NSArray alloc]initWithObjects: square, rectangle,nil];
id object1 = [shapes objectAtIndex:0];
[object1 printArea];
id object2 = [shapes objectAtIndex:1];
[object2 printArea];
return 0;
}
Ahora, cuando compilemos y ejecutemos el programa, obtendremos el siguiente resultado.
2013-09-28 07:42:29.821 demo[4916] The area of square is 100.000000
2013-09-28 07:42:29.821 demo[4916] The area of Rectangle is 50.000000
Como puede ver en el ejemplo anterior, el método printArea se selecciona dinámicamente en tiempo de ejecución. Es un ejemplo de enlace dinámico y es bastante útil en muchas situaciones cuando se trata de objetos similares.
Podemos crear una subclase dentro de un clúster de clases que define una clase que incrusta dentro de ella un objeto. Estos objetos de clase son objetos compuestos.
Así que quizás se pregunte qué es un grupo de clases. Entonces, primero veremos qué es un clúster de clases.
Clústeres de clases
Los clústeres de clases son un patrón de diseño que el marco Foundation hace un uso extensivo. Los clústeres de clases agrupan varias subclases concretas privadas bajo una superclase abstracta pública. La agrupación de clases de esta manera simplifica la arquitectura públicamente visible de un marco orientado a objetos sin reducir su riqueza funcional. Los grupos de clases se basan en el patrón de diseño Abstract Factory.
Para hacerlo simple, en lugar de crear múltiples clases para funciones similares, creamos una sola clase que se encargará de su manejo en función del valor de entrada.
Por ejemplo, en NSNumber tenemos muchos grupos de clases como char, int, bool, etc. Los agrupamos a todos en una sola clase que se encarga de manejar las operaciones similares en una sola clase. NSNumber en realidad envuelve el valor de estos tipos primitivos en objetos.
Entonces, ¿qué es exactamente un objeto compuesto?
Al incrustar un objeto de clúster privado en un objeto de nuestro propio diseño, creamos un objeto compuesto. Este objeto compuesto puede confiar en el objeto de clúster para su funcionalidad básica, solo interceptando mensajes que el objeto compuesto quiere manejar de alguna manera particular. Esta arquitectura reduce la cantidad de código que debemos escribir y le permite aprovechar el código probado proporcionado por Foundation Framework.
Esto se explica en la siguiente figura.
El objeto compuesto debe declararse a sí mismo como una subclase de la superclase abstracta del clúster. Como subclase, debe anular los métodos primitivos de la superclase. También puede anular los métodos derivados, pero esto no es necesario porque los métodos derivados funcionan a través de los primitivos.
El método de conteo de la clase NSArray es un ejemplo; La implementación del objeto interviniente de un método que anula puede ser tan simple como:
- (unsigned)count {
return [embeddedObject count];
}
En el ejemplo anterior, el objeto incrustado es en realidad de tipo NSArray.
Un ejemplo de objeto compuesto
Ahora, para ver un ejemplo completo, veamos el ejemplo de la documentación de Apple que se muestra a continuación.
#import <Foundation/Foundation.h>
@interface ValidatingArray : NSMutableArray {
NSMutableArray *embeddedArray;
}
+ validatingArray;
- init;
- (unsigned)count;
- objectAtIndex:(unsigned)index;
- (void)addObject:object;
- (void)replaceObjectAtIndex:(unsigned)index withObject:object;
- (void)removeLastObject;
- (void)insertObject:object atIndex:(unsigned)index;
- (void)removeObjectAtIndex:(unsigned)index;
@end
@implementation ValidatingArray
- init {
self = [super init];
if (self) {
embeddedArray = [[NSMutableArray allocWithZone:[self zone]] init];
}
return self;
}
+ validatingArray {
return [[self alloc] init] ;
}
- (unsigned)count {
return [embeddedArray count];
}
- objectAtIndex:(unsigned)index {
return [embeddedArray objectAtIndex:index];
}
- (void)addObject:(id)object {
if (object != nil) {
[embeddedArray addObject:object];
}
}
- (void)replaceObjectAtIndex:(unsigned)index withObject:(id)object; {
if (index <[embeddedArray count] && object != nil) {
[embeddedArray replaceObjectAtIndex:index withObject:object];
}
}
- (void)removeLastObject; {
if ([embeddedArray count] > 0) {
[embeddedArray removeLastObject];
}
}
- (void)insertObject:(id)object atIndex:(unsigned)index; {
if (object != nil) {
[embeddedArray insertObject:object atIndex:index];
}
}
- (void)removeObjectAtIndex:(unsigned)index; {
if (index <[embeddedArray count]) {
[embeddedArray removeObjectAtIndex:index];
}
}
@end
int main() {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
ValidatingArray *validatingArray = [ValidatingArray validatingArray];
[validatingArray addObject:@"Object1"];
[validatingArray addObject:@"Object2"];
[validatingArray addObject:[NSNull null]];
[validatingArray removeObjectAtIndex:2];
NSString *aString = [validatingArray objectAtIndex:1];
NSLog(@"The value at Index 1 is %@",aString);
[pool drain];
return 0;
}
Ahora, cuando compilemos y ejecutemos el programa, obtendremos el siguiente resultado.
2013-09-28 22:03:54.294 demo[6247] The value at Index 1 is Object2
En el ejemplo anterior, podemos ver que validar la función única de la matriz no permitiría agregar objetos nulos que provocarían fallas en el escenario normal. Pero nuestra matriz de validación se encarga de ello. De manera similar, cada uno de los métodos en la matriz de validación agrega procesos de validación además de la secuencia normal de operaciones.
Si consulta la documentación de Apple, puede ver los detalles del marco Foundation como se indica a continuación.
El marco Foundation define una capa base de clases Objective-C. Además de proporcionar un conjunto de clases de objetos primitivos útiles, presenta varios paradigmas que definen la funcionalidad que no cubre el lenguaje Objective-C. El marco de la Fundación está diseñado con estos objetivos en mente:
Proporcione un pequeño conjunto de clases de servicios básicos.
Facilite el desarrollo de software mediante la introducción de convenciones coherentes para cosas como la desasignación.
Admite cadenas Unicode, persistencia de objetos y distribución de objetos.
Proporcione un nivel de independencia del sistema operativo para mejorar la portabilidad.
El marco fue desarrollado por NeXTStep, que fue adquirido por Apple y estas clases básicas se convirtieron en parte de Mac OS X e iOS.
Dado que fue desarrollado por NeXTStep, tiene el prefijo de clase "NS".
Hemos utilizado Foundation Framework en todos nuestros programas de muestra. Es casi imprescindible utilizar Foundation Framework.
Generalmente, usamos algo como #import <Foundation/NSString.h> para importar una clase Objective-C, pero para evitar importar demasiadas clases, todo se importa en #import <Foundation/Foundation.h>.
NSObject es la clase base de todos los objetos, incluidas las clases del kit básico. Proporciona los métodos para la gestión de la memoria. También proporciona una interfaz básica para el sistema de ejecución y la capacidad de comportarse como objetos Objective-C. No tiene ninguna clase base y es la raíz de todas las clases.
Clases básicas basadas en la funcionalidad
No Señor. | Tipo de bucle y descripción |
---|---|
1 | Almacenamiento de datos NSArray, NSDictionary y NSSet proporcionan almacenamiento para objetos Objective-C de cualquier clase. |
2 | Texto y cadenas NSCharacterSet representa varias agrupaciones de caracteres que utilizan las clases NSString y NSScanner. Las clases NSString representan cadenas de texto y proporcionan métodos para buscar, combinar y comparar cadenas. Un objeto NSScanner se utiliza para escanear números y palabras de un objeto NSString. |
3 | Fechas y horas Las clases NSDate, NSTimeZone y NSCalendar almacenan horas y fechas y representan información de calendario. Ofrecen métodos para calcular las diferencias de fecha y hora. Junto con NSLocale, proporcionan métodos para mostrar fechas y horas en muchos formatos y para ajustar horas y fechas según la ubicación en el mundo. |
4 | Manejo de excepciones El manejo de excepciones se usa para manejar situaciones inesperadas y se ofrece en Objective-C con NSException. |
5 | Manejo de archivos El manejo de archivos se realiza con la ayuda de la clase NSFileManager. |
6 | Sistema de carga de URL Un conjunto de clases y protocolos que brindan acceso a protocolos comunes de Internet. |
La enumeración rápida es una característica de Objective-C que ayuda a enumerar a través de una colección. Por lo tanto, para conocer la enumeración rápida, primero necesitamos conocer la recopilación, que se explicará en la siguiente sección.
Colecciones en Objective-C
Las colecciones son construcciones fundamentales. Se utiliza para sujetar y gestionar otros objetos. El propósito de una colección es que proporcione una forma común de almacenar y recuperar objetos de manera eficiente.
Hay varios tipos diferentes de colecciones. Si bien todos cumplen el mismo propósito de poder sostener otros objetos, difieren principalmente en la forma en que se recuperan los objetos. Las colecciones más comunes utilizadas en Objective-C son:
- NSSet
- NSArray
- NSDictionary
- NSMutableSet
- NSMutableArray
- NSMutableDictionary
Si desea obtener más información sobre estas estructuras, consulte el almacenamiento de datos en Foundation Framework .
Sintaxis de enumeración rápida
for (classType variable in collectionObject ) {
statements
}
Aquí hay un ejemplo de enumeración rápida.
#import <Foundation/Foundation.h>
int main() {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSArray *array = [[NSArray alloc]
initWithObjects:@"string1", @"string2",@"string3",nil];
for(NSString *aString in array) {
NSLog(@"Value: %@",aString);
}
[pool drain];
return 0;
}
Ahora, cuando compilemos y ejecutemos el programa, obtendremos el siguiente resultado.
2013-09-28 06:26:22.835 demo[7426] Value: string1
2013-09-28 06:26:22.836 demo[7426] Value: string2
2013-09-28 06:26:22.836 demo[7426] Value: string3
Como puede ver en la salida, cada uno de los objetos de la matriz se imprime en un orden.
Enumeración rápida hacia atrás
for (classType variable in [collectionObject reverseObjectEnumerator] ) {
statements
}
A continuación se muestra un ejemplo de reverseObjectEnumerator en enumeración rápida.
#import <Foundation/Foundation.h>
int main() {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSArray *array = [[NSArray alloc]
initWithObjects:@"string1", @"string2",@"string3",nil];
for(NSString *aString in [array reverseObjectEnumerator]) {
NSLog(@"Value: %@",aString);
}
[pool drain];
return 0;
}
Ahora, cuando compilemos y ejecutemos el programa, obtendremos el siguiente resultado.
2013-09-28 06:27:51.025 demo[12742] Value: string3
2013-09-28 06:27:51.025 demo[12742] Value: string2
2013-09-28 06:27:51.025 demo[12742] Value: string1
Como puede ver en la salida, cada uno de los objetos de la matriz se imprime pero en orden inverso en comparación con la enumeración rápida normal.
La gestión de la memoria es uno de los procesos más importantes en cualquier lenguaje de programación. Es el proceso mediante el cual la memoria de los objetos se asigna cuando se necesitan y se desasigna cuando ya no se necesitan.
La gestión de la memoria de objetos es una cuestión de rendimiento; si una aplicación no libera objetos innecesarios, su huella de memoria aumenta y el rendimiento se ve afectado.
Las técnicas de gestión de memoria de Objective-C se pueden clasificar en dos tipos.
- "Retención-liberación manual" o MRR
- "Recuento automático de referencias" o ARC
"Retención-liberación manual" o MRR
En MRR, gestionamos explícitamente la memoria realizando un seguimiento de los objetos por nuestra cuenta. Esto se implementa mediante un modelo, conocido como recuento de referencias, que la clase Foundation NSObject proporciona junto con el entorno de ejecución.
La única diferencia entre MRR y ARC es que la retención y liberación es manejada por nosotros manualmente en el primero, mientras que se realiza automáticamente en el segundo.
La siguiente figura representa un ejemplo de cómo funciona la administración de memoria en Objective-C.
El ciclo de vida de la memoria del objeto Clase A se muestra en la figura anterior. Como puede ver, el recuento de retención se muestra debajo del objeto, cuando el recuento de retención de un objeto se vuelve 0, el objeto se libera por completo y su memoria se desasigna para que otros objetos la usen.
El objeto de clase A se crea primero utilizando el método alloc / init disponible en NSObject. Ahora, el recuento de retención se convierte en 1.
Ahora, la clase B retiene el objeto de la clase A y el recuento de retención del objeto de la clase A se convierte en 2.
Luego, la Clase C hace una copia del objeto. Ahora, se crea como otra instancia de Clase A con los mismos valores para las variables de instancia. Aquí, el recuento de retención es 1 y no el recuento de retención del objeto original. Esto está representado por la línea de puntos en la figura.
La clase C libera el objeto copiado utilizando el método de liberación y el recuento de retención se convierte en 0 y, por lo tanto, el objeto se destruye.
En el caso del Objeto de Clase A inicial, el recuento de retención es 2 y debe liberarse dos veces para que sea destruido. Esto se hace mediante declaraciones de liberación de Clase A y Clase B que reducen el recuento de retención a 1 y 0, respectivamente. Finalmente, el objeto se destruye.
Reglas básicas de MRR
Somos dueños de cualquier objeto que creamos: Creamos un objeto usando un método cuyo nombre comienza con "alloc", "new", "copy" o "mutableCopy"
Podemos tomar posesión de un objeto usando retener: normalmente se garantiza que un objeto recibido seguirá siendo válido dentro del método en el que se recibió, y ese método también puede devolver el objeto de forma segura a su invocador. Usamos retener en dos situaciones:
En la implementación de un método de acceso o un método de inicio, para tomar posesión de un objeto que queremos almacenar como valor de propiedad.
Para evitar que un objeto se invalide como efecto secundario de alguna otra operación.
Cuando ya no lo necesitamos, debemos renunciar a la propiedad de un objeto que poseemos: renunciamos a la propiedad de un objeto enviándole un mensaje de liberación o un mensaje de liberación automática. En la terminología de Cocoa, renunciar a la propiedad de un objeto se denomina, por lo tanto, "liberar" un objeto.
No debe renunciar a la propiedad de un objeto que no es de su propiedad: esto es solo un corolario de las reglas de política anteriores establecidas explícitamente.
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
- (void)sampleMethod;
@end
@implementation SampleClass
- (void)sampleMethod {
NSLog(@"Hello, World! \n");
}
- (void)dealloc {
NSLog(@"Object deallocated");
[super dealloc];
}
@end
int main() {
/* my first program in Objective-C */
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass sampleMethod];
NSLog(@"Retain Count after initial allocation: %d",
[sampleClass retainCount]);
[sampleClass retain];
NSLog(@"Retain Count after retain: %d", [sampleClass retainCount]);
[sampleClass release];
NSLog(@"Retain Count after release: %d", [sampleClass retainCount]);
[sampleClass release];
NSLog(@"SampleClass dealloc will be called before this");
// Should set the object to nil
sampleClass = nil;
return 0;
}
Cuando compilemos el programa anterior, obtendremos el siguiente resultado.
2013-09-28 04:39:52.310 demo[8385] Hello, World!
2013-09-28 04:39:52.311 demo[8385] Retain Count after initial allocation: 1
2013-09-28 04:39:52.311 demo[8385] Retain Count after retain: 2
2013-09-28 04:39:52.311 demo[8385] Retain Count after release: 1
2013-09-28 04:39:52.311 demo[8385] Object deallocated
2013-09-28 04:39:52.311 demo[8385] SampleClass dealloc will be called before this
"Recuento automático de referencias" o ARC
En el conteo automático de referencias o ARC, el sistema usa el mismo sistema de conteo de referencias que MRR, pero inserta las llamadas al método de administración de memoria apropiado para nosotros en tiempo de compilación. Se nos anima encarecidamente a utilizar ARC para nuevos proyectos. Si usamos ARC, normalmente no es necesario comprender la implementación subyacente descrita en este documento, aunque en algunas situaciones puede resultar útil. Para obtener más información sobre ARC, consulte las notas de la versión de transición a ARC.
Como se mencionó anteriormente, en ARC, no es necesario agregar métodos de liberación y retención, ya que el compilador se encargará de eso. En realidad, el proceso subyacente de Objective-C sigue siendo el mismo. Utiliza las operaciones de retención y liberación internamente, lo que facilita al desarrollador la codificación sin preocuparse por estas operaciones, lo que reducirá tanto la cantidad de código escrito como la posibilidad de pérdidas de memoria.
Había otro principio llamado recolección de basura, que se usa en Mac OS-X junto con MRR, pero desde su desaprobación en OS-X Mountain Lion, no se ha discutido junto con MRR. Además, los objetos de iOS nunca tuvieron la función de recolección de basura. Y con ARC, tampoco se usa la recolección de basura en OS-X.
Aquí hay un ejemplo simple de ARC. Tenga en cuenta que esto no funcionará en el compilador en línea ya que no es compatible con ARC.
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
- (void)sampleMethod;
@end
@implementation SampleClass
- (void)sampleMethod {
NSLog(@"Hello, World! \n");
}
- (void)dealloc {
NSLog(@"Object deallocated");
}
@end
int main() {
/* my first program in Objective-C */
@autoreleasepool {
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass sampleMethod];
sampleClass = nil;
}
return 0;
}
Cuando compilemos el programa anterior, obtendremos el siguiente resultado.
2013-09-28 04:45:47.310 demo[8385] Hello, World!
2013-09-28 04:45:47.311 demo[8385] Object deallocated