Entradas

Mostrando las entradas con la etiqueta objective-c

Disparo de eventos desde un User Control GeneXus en iOS

Imagen
Los User Controls en GeneXus permiten extender la funcionalidad provista por los generadores, para resolver escenarios de User Interface que no están resueltos en los controles estandar. Hay varios controles interesantes en el Marketplace , principalmente para Web pero también para Smart Devices . Si bien estos User Controls se utilizan mayormente para cambiar el aspecto visual de las aplicaciones, puede haber casos donde sea necesario ejecutar código del usuario. En iOS esto es muy fácil de hacer, si la implementación del control hereda de la clase GXControlBase o alguna de sus clases derivadas. Hay dos forma de hacerlo: disparando una acción del panel o disparando un evento del control. Disparar una acción del panel Para disparar una acción definida en el panel donde se encuentra el User Control, alcanza con incluir el siguiente código: [self fireActionWithName:actionName userInterfaceContext:nil withEntityData:nil]; donde self es la implementación del user control ...

Operador condicional ternario en Objective-C

Imagen
En la muchos lenguajes de programación (en los que provienen de C al menos...) existe un operador condicional ternario de la forma condición ? expresión1 : expresión2 que evalúa la condición , y el resultado de la expresión completa será expresión1 o expresión2 según el la condición evalúe a true o false respectivamente. En Objecive-C, la condición debe ser evaluable como una expresión booleana, por lo que se puede usar un objeto, y en ese caso el significado es el mismo que preguntar si el objeto es distinto de nil . Por otro lado, Objective-C adopta una convención del compilador GCC (según esta respuesta en StackOverflow), donde la expresión1 es opciona, pudiendo escribir condición ? : expresión2 y en ese caso, si la condición es verdadera, será además el resultado de la expresión completa. ¿Para qué sirve todo esto? Sirve por ejemplo para escribir una asignación cuando el valor asignado puede ser nil y en ese caso queremos asignar un valor por defecto. Al...

async/await en C# 5.0

Imagen
Personalmente no he hecho nada demasiado serio con C# (sí programo, pero no es ni cerca mi lenguaje principal), pero es un lenguaje que me resulta sumamente interesante. Ya había hablado en este blog sobre las mejoras que trajeron las versiones 3.0 y 4.0 . En la última versión de C#, la 5.0 que salió con VisualStudio 2012, se agregaron dos nuevos comandos: async y await . De hecho, es de las pocas cosas nuevas que vinieron con esta versión. Debo reconocer que al principio no le di mucha importancia, hasta que leí este artículo de Miguel de Icaza que me dejó pensando en el tema:  Callbacks as our Generations' Go To Statement ¿Cómo funcionan los comandos async/await? (1) Cuando se declara un método como async , lo que le estamos diciendo al compilador es que el método puede detener su ejecución en cualquier momento mediante el uso de un comando await . A su vez, un método declarado como async tiene que devolver un objeto de tipo Task o Task<T> según su valor de ...

Cosas que me gustaría tener en Objective-C

Imagen
En los últimos tiempos, el lenguaje Objective-C ha mejorado bastante, como ya hemos comentado en el blog (por ejemplo acá ). Pero (siempre hay un "pero"), igual hay algunas cosas que todavía se podrían mejorar o agregar al lenguaje. Implementación default para métodos de protocolos Supongamos que tenemos un @protocol MyProtocol , que define una @property NSArray *someArray . Cuando uso una variable que está basada en este protocolo ( id<MyProtocol> myVar ), puedo ver cuantos elementos tiene el array escribiendo [[myVar someArray] count] Pero supongamos que esto lo hago muy seguido, entonces quiero cambiar esto, para que el protocolo ya defina la propiedad elementCount para poder usarla como [myVar elementCount] ¿Cuál es el problema con esto? Que si agrego la propiedad elementCount al protocolo, tengo que implementarla en todas las clases que implementan el protocolo. Una alternativa sería tener algo así como "method templates", donde se ...

Optimizaciones del compilador en Objective-C

Imagen
Cuando se tiene un objeto que es inmutable, por ejemplo un string, es bastante útil contar con optimizaciones del compilador, para que no cree varias instancias idénticas. Por ejemplo, en Objective-C si hacemos NSString *a = @"hola"; NSString *b = @"hola"; el compilador se da cuenta que son referencias a la misma instancia, y crea el string @"hola" una sola vez en memoria, por lo que a y b quedan apuntando al mismo objeto. Lo mismo pasa si se usan objetos de tipo NSNumber. Si tengo por ejemplo NSNumber *c = @1; NSNumber *d = @1; el objeto @1 queda una sola vez en memoria y las variables c y d referencian la misma instancia. Hasta acá no hay mucha sorpresa. Son objetos inmutables, por lo que no importa mucho que sean la misma instancia... salvo en lo que se puede ahorrar de memoria. Una curiosidad si se quiere, es que los constructores no siempre pueden ser optimizados. Por ejemplo NSString *e = [@"h" stringByAppendingSt...

Objective-C: ejecución sincrónica mediante semáforos

Imagen
En Objective-C, o para ser más precisos en iOS, la norma es que cuando una tarea lleva tiempo, la misma se ejecuta de forma asincrónica mediante el uso de delegates y call-backs . Por ejemplo, si queremos obtener el contenido de una página web, usamos  NSURLConnection . El método start de dicha clase, inicia la operación y termina inmediatamente, antes de comenzar a recibir datos. Los datos llegan a través de los métodos del protocolo  NSURLConnectionDelegate , como por ejemplo,  connection:didReceiveData: . Esto presenta un problema para la implementación de las clases estándar de GeneXus, ya que por ejemplo cuando hacemos &httpClient.execute('GET', 'http://www.google.com') &status = &httpClient.statusCode esperamos que al volver de la llamada la variable &status tenga la información correspondiente. La solución que encontramos para que la ejecución se realice de forma sincrónica, es mediante el uso de semáforos. Los semáforos son pa...

Objective-C se moderniza: subscripting

Imagen
Objective-C es un lenguaje bastante distinto en su sintaxis a otros lenguajes de programación como ser C#, Java o Ruby. Como tal, es un lenguaje que a primer golpe de vista parece dificil de entender. Además, es un lenguaje que por sus características, es más "verbose" que los demás, y esto a su vez puede hacer que parezca que hay que escribir mucho código. Esta última característica no es siempre mala. Por ejemplo, en Java (o cualquier otro lenguaje que no incluya los nombres de los parámetros en el nombre del método), si uno no conoce la API en detalle, y ve este código: String result = "some sample string".replace( 'a', 's' ); puede no quedarle claro si se va a remplazar la 'a' por la 's' o la 's' por la 'a'. En Objective-C, esto se escribe así: NSString *result = [@"some sample string" stringByReplacingOccurrencesOfString:@"a" withString:@"s"]; Es verdad que es mucho más c...

Automatic Reference Counting en Objective-C

Imagen
Cuando uno empieza a programar en Objective-C, una de las mayores dificultades que se encuentra es con el manejo de memoria. Objective-C utiliza una técnica que se llama "reference counting", que resuelve el manejo de memoria en tiempo de compilación (a diferencia de "garbage collection"), pero que hasta la aparición de iOS 5 y OS X 10.7, lo dejaba en manos del programador. Cómo funciona el "reference counting" Básicamente, la técnica de "reference counting" funciona así: cuando quiero quedarme con una referencia a un objeto tengo que mandarle un retain , esto incrementa el retainCount en uno cuando ya no lo necesito más le mando un release , esto  decremente el retainCount también en uno si no quiero quedarme con una referencia pero tampoco quiero que el objeto se libere inmediatamente, puedo mandarle un autorelease que hace un release pero en el futuro (1) cuando el objeto queda con retainCount en cero, el mismo objeto se enca...

Detectar problemas de memoria con Instruments

Imagen
En Objective-C, cuando se maneja la memoria "a mano" con retain/release/autorelease, es bastante común que aparezcan problemas de memoria. Estos problemas no deberían aparecer si se usa ARC (Automatic Reference Counting) en el proyecto, ya que todo el manejo lo hace automáticamente el compilador. Los problemas que pueden aparecer son de dos clases: Leaks: un objeto se retiene más veces que las que se libera, por lo que queda memoria en uso, a la que no se puede acceder. Zombies: un objeto que se libera más veces de las que se retiene, por lo que la aplicación da un error cuando se le intenta mandar un mensaje. Los Zombies en general son más fáciles de detectar ejecutando la aplicación, porque la aplicación termina con un error. De todas formas, a partir del error, no siempre es fácil detectar donde se produce o por que. Para ambos casos, Xcode viene con una aplicación llamada Instruments, que permite detectarlos. Para poder ejecutar Instruments, se debe ej...

Implementar un User Control para el generador iOS

Imagen
En los generadores para Smart Devices en GeneXus X Evolution 2, tenemos la posibilidad de crear user controls, para extender el comportamiento del generador. La idea de esta nota es contar como desarrollar un nuevo user control para el generador iOS. Nota : crear un nuevo user control involucra varios pasos: implementación en la plataforma, definición del control, implementar resolvers para las propiedades, distribución, etc. Ahora me voy a concentrar solo en la parte de implementación. Como ejemplo, voy a mostrar como implementar el SD ImageMap. Básicamente lo que hace es mostrar una imagen de fondo con un conjunto de imágenes en posiciones determinadas, que cuando se seleccionan tiene la posibilidad de disparar una acción. El código completo del control (al día de hoy) lo pueden ver en  https://gist.github.com/1600064 Clase base Como decía, el control muestra una lista de imágenes con una imagen grande de fondo. Esa lista puede venir de una tabla en la base de datos...

Objective-C: implementar método de forma opcional en runtime

Imagen
Una de las ventajas que tiene Objective-C, es que es un lenguaje dinámico. Eso permite tener protocolos (interfaces en otros lenguajes...) con métodos declarados como opcionales, y preguntar en tiempo de ejecución si la clase que voy a usar implementa el método. Esta característica está buena, pero ahora necesito ir un paso más lejos. Quiero que una clase implemente o no un método, pero según alguna condición que solo conozco en tiempo de ejecución. El caso de uso es el siguiente. Cuando se tiene una tabla (UITableView) se pueden mostrar los registros agrupados en secciones, y en esos casos se puede cambiar la apariencia de lo títulos de las secciones. En GeneXus tenemos la posibilidad de cambiar estos títulos usando la clase del tema GroupSeparator (es nueva, la estamos implementando...) El problema es que esa propiedad puede estar vacía, y en ese caso lo que quiero es que la tabla muestre el separador por defecto, que tiene un fondo con gradiente, letra con sombra, etc. ...

Métodos privados y "protected" en Objective-C

Imagen
El lenguaje Objective-C tiene algunas cosas a las que todavía no me termino de acostumbrar, después de más de un año de estar trabajando con él. Una de estas cosas es la visibilidad de los métodos. Me explico: en los lenguajes orientados a objetos, se suele tener por lo menos tres tipos de métodos: públicos, que son accesibles por todos; privados, que son solo accesibles dentro de la clase que los define; y "protected" que son visibles para la clase que los define y para sus clases derivadas. Métodos públicos En Objective-C todos los métodos son públicos, en el sentido que siempre se pueden ejecutar aunque no estén declarados como tal. Para declarar un método como público y que quede visible para el resto del mundo, simplemente se declara en la definición de la clase en el .h Métodos privados Si bien cualquier método se puede invocar, los que no están declarados en el .h son considerados privados. Al no declararlos en el .h, no es fácil conocer la firma de e...

Text macros en XCode

Imagen
Acabo de "descubrir" una funcionalidad de XCode que no sabía que existía: text macros. En realidad es algo que sí sabía que estaba, porque muchas veces cuando uno empieza a escribir algo, le aparece código automáticamente para completar. Por ejemplo, si uno escribe "if", aparece if (<#condition#>) {     <#statements#> } y apretando Enter o Space se agrega el código permitiendo completar las cosas que faltan. Lo que no sabía, es que podía definir mis propios macros y como usarlos... Hay una explicación muy completa de como hacerlo en esta nota , pero a mi me gusta más editarlo en modo texto que usando el editor de propiedades, así que acá va como lo hice yo... En una ventana del Terminal.app: cd /Developer/Applications/Xcode.app/Contents cd PlugIns/TextMacros.xctxtmacro/Contents/Resources edit ObjectiveC.xctxtmacro donde "edit" se puede cambiar por cualquier editor de texto de su agrado (en mi caso en particular abre TextWrangler...

Blocks en Objective-C (iOS 4)

Imagen
Me acabo de enterar, que a partir de iOS 4, el lenguaje Objective-C soporta blocks . ¡Espectacular! Les recomiendo que lean: The Pragmatic Studio: Using Blocks in iOS 4: The Basics The Pragmatic Studio: Using Blocks in iOS 4: Designing with Blocks  (ver también al final del artículo que tiene otros links interesantes) Programming with C Blocks (On Apple Devices) iOS Reference Library: A Short Practical Guide to Blocks La sintaxis para declarar un block , es un tanto extraña... Por ejemplo, si queremos declarar un block que recibe un número entero y devuelve otro número entero, por ejemplo multiplicando el parámetro por 3, se declara así: ^ (int num) {     return num * 3; } Este block se puede asignar a una variable, por ejemplo con (int)(^por3)(int) = ^ (int num) {return num * 3;}; y luego invocarlo con: int result = por3(7);  // result = 21 o se puede pasar como parámetro a algún método que reciba un block con el tipo dado: [some...

Manejo de fechas en Objective-C

Imagen
El lenguaje Objective-C tiene una carencia importante según yo lo veo, que es que hay cosas que deberían ser simples y llevan una cantidad importante de trabajo. Un ejemplo es concatenar dos strings. En cualquier otro lenguaje, sería algo como: result = s1 + s2; En Objective-C, hacer lo mismo lleva mucho más código: result = [NSString stringWithFormat:@"%@%@", s1, s2]; En particular, una de las cosas que me parecen de las más complicadas en Objective-C (desde el punto de la sintaxis), es el manejo de fechas. Por ejemplo, para crear una fecha, el código es el siguiente: NSDateComponents *comps = [[NSDateComponents alloc] init]; [comps setYear:2010]; [comps setMonth:12]; [comps setDay:6]; NSDate *date = [[NSCalendar currentCalendar] dateFromComponents:comps]; [comps release]; También si quiero obtener el día, mes y año de una fecha dada, es complicado: NSDate *tmpDate = [NSDate date]; // today NSDateComponents *comp = [[NSCalendar currentCalendar] components:(N...

Invocación dinámica de funciones en Objective-C

Imagen
Tengo el siguiente problema: tengo un objeto que tiene tres propiedades (o métodos, en Objective-C se pueden invocar como métodos), que tienen nombres "sourceUrl1", "sourceUrl2" y "sourceUrl3". En una determinada función, recibo por parámetro el número de la propiedad que quiero usar. El código "tradicional" para hacer esto, sería con un switch, discriminando por el valor del parámetro. Algo así: NSString *strUrl; switch (indexPath.row) {   case 0:     strUrl = question.sourceUrl1;     break;   case 1:     strUrl = question.sourceUrl2;     break;   case 2:     strUrl = question.sourceUrl3;     break; } Pero Objective-C tiene la ventaja de ser dinámico. De esa forma, puedo construir el nombre de la propiedad usando un string, e invocarlo a partir de ese nombre. El código usando esta propiedad del lenguaje es: NSString *s...

Animar la interfaz de usuario en iOS

Imagen
Una de las cosas que tienen mucho las aplicaciones para el iPhone, son animaciones en la interfaz de usuario, por ejemplo en las transiciones entre pantallas. Esta animación, la que se da al pasar de una pantalla a otra, es bien simple. Lo único que se precisa es pasar un parámetro a la función que muestra la siguiente vista. Algo así: [navigationController pushViewController:newViewController animated:YES ]; Pero además, también es muy sencillo crear animaciones más complejas, de forma totalmente trivial. Alcanza con encerrar el código que modifica la interfaz de usuario en un bloque de animación. [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:duration]; //código del cambio que queremos hacer en la UI [UIView commitAnimations]; La duración de la animación está expresada en segundos. Por ejemplo, supongamos que tenemos una toolbar en la parte inferior de la pantalla, y queremos que desaparezca deslizándose hacia abajo cuando presionamos un botón. El ...

Propiedades en Objective-C y el manejo de memoria

Imagen
Hace unos días comentaba sobre el manejo de memoria en Objective-C . Hoy quería hablar en particular sobre las propiedades. Cuando un declara un propiedad en una clase,  con la directiva @property, el  setter  de dicha propiedad puede tener una de las siguiente semánticas: assign: se usa una asignación simple, es el valor por defecto retain: se le envía un mensaje de "retain" al valor que se va a asignar a la propiedad copy: se le envía un mensaje de "copy" (se crea una copia) al valor que se va a asignar. Cuando se va a implementar el método setter (si no se usa la directiva @synthesize para que lo cree por defecto) se debe tener en cuenta la semántica que se le quiere dar a dicha propiedad. Assign Supongamos que tenemos una propiedad definida como  @property (nonatomic, assign) NSObject *myProperty; El método setter de dicha propiedad deberá ser de la siguiente forma: - (void) setMyProperty:(NSObject *)valor {     myProperty = valor; ...

Manejo de memoria en Objective-C

Imagen
Una de las cosas que más me ha dado más trabajo por el momento en Objective-C es el manejo de memoria (la otra cosa es el diseño de la interfez de usuario con Interface Builder, pero ese es otro tema). Desde hace muchos años, trabajo con lenguajes donde no había que preocuparse por el manejo de memoria, o bien porque el lenguaje tenía garbage collector (C#, Java) o bien porque la herramienta ocultaba el problema (GeneXus, por ejemplo con el generador C/SQL). La última vez que me había tenido que preocupar por el manejo de memoria había sido en la facultad (hace más de 10 años), cuando en algún curso usamos C y C++... En Objective-C creo que no es tan complicado como en C, pero igual suele dar bastantes dolores de cabeza. Un buen recurso para empezar a ver el tema, es la documentación de Apple al respecto . Los problemas de memoria suelen ser difíciles de diagnosticar, y hay de dos clases: Cuando se libera la memoria antes de tiempo (los más complicados), el programa...

XCode vs. Visual Studio

Imagen
Hace unos días empecé mis primeras pruebas para desarrollar aplicaciones para el iPhone, con lo cual tuve que estudiar un poco de Objective-C (el lenguaje de programación) y XCode (el ambiente de desarrollo). No puedo evitar la comparación con C#/Visual Studio, que es el otro lenguaje de propósito general que manejo... Si bien tal vez la comparación no sea del todo justa, ya que en Visual Studio nunca desarrollé aplicaciones móviles, creo que como ambientes de desarrollo deberían ser bastante comparables. Intellitips Se extrañan... En Visual Studio cuando escribo "variable." muestra una lista de todas las propiedades, métodos y eventos que están disponibles para esa variable. Esto es muy útil cuando uno no se acuerda exáctamente el nombre de una función. En XCode no encontré que tuviera intellitips, lo más parecido que tiene es una especie de "autocomplete", que muestra el primér método que coincide con lo que voy escribiendo. Por lo tanto, si quiero busc...