Currently browsing: January 2011

Presentando… Music Maniac

This post was published 8 years ago. It may be exremely outdated.

Vale, pensaba que no tendría tiempo y que tendría que retrasar la aplicación hasta verano, pero no, al final con un esfuerzo extra y un par de días de completa dedicación al proyecto, he podido acabar la aplicación hace apenas un semana (el resto del tiempo ha estado en revisión). Así que hoy toca presentación de la aplicación.

¿Qué es Music Maniac?

Icono de Music Maniac¿Recordáis el juego del concurso musical de los antiguos iPod Video? Para los que no os suene, se trataba de un juego muy sencillo en el que  sonaba durante unos segundos una canción y se te ofrecían una serie de títulos entre los que elegir. Si acertabas el título conseguías puntos y si fallabas, no. Además, cuánto más rápido acertases más puntos ganabas, así que la velocidad era importante.

Music Maniac es mi idea de cómo debería haber sido ese juego llevada a iOS. ¿Y qué tiene de nuevo Music Maniac? Para empezar, más flexibilidad: se puede jugar con sólo los títulos de las canciones, con los nombres de los álbumes, con los nombres de los artistas, con las carátulas de los álbumes o con combinaciones de los anteriores. También se puede personalizar la duración de las canciones o el número de rondas.

Se puede jugar tanto con canciones de nuestra biblioteca de iTunes (a las que será necesario añadirle los datos del título, artista, álbum y carátula, ya que de algún sitio tiene que sacar la información sobre la canción Music Maniac) como con las canciones más populares de la iTunes Store. Sin embargo los modos de juego son diferentes: en el modo offline podemos jugar las rondas que queramos, hasta cansarnos o hasta fallar por primera vez, mientras que en el modo online sólo podemos jugar 10 rondas (esto es porque deben descargarse las canciones y el proceso requiere tanto tiempo para descargarlas como memoria libre para almacenarlas).

Como aliciente al modo offline, se puede jugar con amigos con un sólo dispositivo, pasándolo al terminar cada ronda y viendo después quién ha conseguido más puntos. Pero la competición no acaba en el modo offline, ya que Music Maniac tiene clasificaciones y logros de Game Center, con lo cual podrás ver quién conoce mejor su música y quién los éxitos de la iTunes Store. También podrás desbloquear logros acertando rondas en pocos segundos o acumulando cierta cantidad de puntos.

Music Maniac estará disponible en unas horas de forma gratuita en una versión Lite, en la que sólo se puede jugar en el modo offline, sin personalizar las rondas y sin enviar las puntuaciones a Game Center y en versión completa por 0.99$ (0.79€).

La aplicación es universal: está adaptada tanto a iPod Touch y iPhone (también a la Retina Display del iPhone 4) como a iPad. Además está traducida al inglés, catalán y español (lo siento, no hablo más idiomas, así que lo dejo en esos tres).

Próximas actualizaciones

Seguramente habréis visto por la App Store muchas aplicaciones que comienzan con una versión 1.0 y al cabo de un tiempo lanzan la versión 2.0 como aplicación independiente de la anterior. Esto no va a pasar con Music Maniac. Music Maniac sólo habrá una, se actualizará (sí, habrá versión 2.0, me gustaría desarrollarla en verano) y sus actualizaciones serán gratuitas para todo aquel que comprase la versión anterior y tendrá el mismo precio que la aplicación original para aquellos que no la comprasen.

También aviso que no habrá cambios de precio, ni subidas ni bajadas. La aplicación costará siempre 0.99$ (a no ser que Apple me impida ponerle ese precio), así que no os precupéis por posibles subidas de precio futuras: no las habrá.

Introducción a Objective-C: El paradigma de la POO

This post was published 8 years ago. It may be exremely outdated.

Siguiendo con los tutoriales de Objective-C, voy a explicar el paradigma de la Programación Orientada a Objetos. En la POO de Objective-C hay 5 conceptos clave:

  • Objeto: Los objetos son el pilar fundamental en la POO. Los objetos contienen variables, responden a métodos, tienen una dirección de memoria en la que están almacenados, pertenecen a una clase y pueden implementar protocolos.
  • Clases: Un objeto pertecen a una clase, y sólo a una. Por el contrario varios objetos pueden pertenecer a la misma clase. En otros lenguajes de programación los objetos pueden heredar de varias clases, pero en Objective-C no. Cuando un objeto pertecene a una clase, el objeto contiene todas las variables de la clase, y responde a todos los métodos de instancia a los que responde la clase (veremos qué es esto más adelante). A su vez, una clase puede heredar de otra clase (de hecho lo más común es que las clases que creemos hereden de NSObject, al menos a nuestro nivel), cuando esto sucede, la nueva clase responde a todos los métodos a los que respondía la clase “padre” y los objetos de esta clase también tienen las variables de instancia de la clase “padre”.
  • Variables de instancia: Los objetos, a pesar de ser por sí mismos variables, pueden contener a otras variables, que pueden ser variables simples como las de C (por ejemplo, números enteros o de coma flotantes) u objetos de cualquier clase. Las variables de instancia son diferentes en cada objeto, por lo que si tenemos dos objetos de la clase rueda y accedemos a la variable presiónDeLaRueda, cada uno devolverá un valor diferente de presión.
  • Métodos de instancia: Los métodos de instancia son las funciones que puede ejecutar el objeto de una clase determinada. Cada clase define unos métodos de instancia diferente. Por ejemplo, la clase coche podría tener un método que fuese encenderMotor, al que se accedería desde un objeto determinado.
  • Métodos de clase: Los métodos de clase son funciones a las que sólo se puede acceder desde la propia clase. Un método de clase típico es alloc, al que sólo se puede acceder desde una case, nunca desde un objeto.

Puede que no os hayan quedado claros del todo los conceptos con esta introducción, los explicaré mejor un poco más adelante.

Creando una nueva clase

Creando una nueva clase

Creando una nueva clase - Paso 2

Creando una nueva clase - Paso 2

En Objective-C las clases se definen mediante dos archivos: NOMBRECLASE.h y NOMBRECLASE.m. Los archivos .h contienen la interfaz de la clase y los archivos .m su implementación. La interfaz de la clase es una especie de índice: indica todas las varibles de instancia de la clase y todos los métodos a los que responde. La implementación es donde se desarrolla el código de las funciones. No es necesario dividir las clases en dos archivos, pero es altamente recomendable para hacer más claro el código.

Para añadir un nuevo archivo a nuestro proyecto basta con ir al menú File » New file… o pulsar Comando + N. En la ventana que nos aparecerá seleccionaremos Mac OS X » Cocoa Class » Objective-C Class (Subclass of NSObject). En  File Name introduciremos el nombre de nuestra nueva clase, en este caso Coche, acabado en .m. También marcaremos la casilla Also create “Coche.h”, para mantener más limpio el código.

En el archivo Coche.h encontraremos el siguiente código:

#import <Cocoa/Cocoa.h>
@interface Coche : NSObject {
}
@end

La primera línea ya la vimos en la primera parte de los tutoriales, e importa el Framework Cocoa. En la siguiente línea comienza la interfaz de la clase. Veamos su sintaxis:

  • @interface: Inicia la interfaz
  • Coche: El nombre de la clase que estamos definiendo
  • : : Separado entre el nombre de la clase y la clase de la que hereda.
  • NSObject: La clase de la que hereda nuestra clase.
  • { : Abre el bloque donde se definen las variables de instancia.
  • } : Cierra este bloque.
  • @end: Indica el fin de la implementación.

Como podéis ver, las clases pueden ser “hijas” de otras clases, y es algo realmente común. De hecho es muy conveniente que nuestras clases sean hijas de al menos NSObject. La clase NSObject es la clase básica e incluye las funciones esenciales de gestión de memoria (la veremos más tarde), entre otras cosas.

Si nuestra clase es hija de una clase que es hija de NSObject, esta nueva clase también tendrá acceso a los métodos de la clase NSObject.

Ahora bien, imaginemos que queremos que queremos que nuestra clase tenga alguna variable de instancia, como por ejemplo, el color del vehículo y el número de puertas. Definiremos dos variables: color y numPuertas. La primera, color, será un objeto de clase NSString (cadena de texto). La segunda, numPuertas, será una variable de tipo NSUInteger (a nuestro nivel, equivalente a un unsigned int de C, o en palabras llanas, un número entero sin signo).

#import <Cocoa/Cocoa.h>
@interface Coche : NSObject {
 NSString    *color;
 NSUInteger    numPuertas;
}
@end

Fijáos en la sintaxis para definir varibles de instancia:

NOMBRE_DE_LA_CLASE_DEL_OBJETO *NOMBRE_DEL_OBJETO;
NOMBRE_DEL_TIPO_DE_VARIABLE NOMBRE_DE_LA_VARIABLE;

Al defnir un objeto siempre antepondremos un asterisco (“*”) al nombre del objeto.

Y ahora, ¿cómo obtenemos el valor de estas variables? Pues bien, tendremos que crear un método de instancia para asignar este valor. Los métodos se definen entre el corchete de cierre (“}”) y el @end. Creemos dos métodos de instancia: getColor y getNumPuertas. Creemos otro más llamado imprimirDetalles que muestre en la consola los valores devueltos por getColor y getNumPuertas.

#import <Cocoa/Cocoa.h>
@interface Coche : NSObject {
 NSString    *color;
 NSUInteger    numPuertas;
}
- (NSString *)getColor;
- (NSUInteger)getNumPuertas;
- (void)imprimirDetalles;
@end

Fijáos de nuevo en la sintaxis:

- (CLASE_DEL_OBJETO_QUE_VAMOS_A_DEVOLVER *)NOMBRE_DE_LA_FUNCION;
- (TIPO_DE_LA_VARIABLE_QUE_SE_DEVOLVERA)NOMBRE_DE_LA_FUNCION;
- (VOID)NOMBRE_DE_LA_FUNCION_QUE_NO_DEVUELVE_NADA;

Como antes, cuando un método devuelve un objeto, se añade un asterisco al nombre de la clase del objeto que se devolverá. Cuando no es un objeto, no es necesario añadir el asterisco. Cuando una función no devuelve nada, se utiliza el valor void para indicárselo al compilador.

El guión (“-“) que precede a los métodos sirve para indicar que se trata de métodos de instancia. Si se tratase de métodos de clase (que veremos más adelante), estarían precedidos por un sigo +.

Pero aún nos faltan dos métodos para establecer el valor de las dos variables de instancias. Para ello definiremos dos métodos llamados setColor y setNumPuertas que acepten un parámetro que será el nuevo valor.

#import <Cocoa/Cocoa.h>
@interface Coche : NSObject {
 NSString    *color;
 NSUInteger    numPuertas;
}
- (NSString *)getColor;
- (NSUInteger)getNumPuertas;
- (void)imprimirDetalles;
- (void)setColor: (NSString *)nuevoColor;
- (void)setNumPuertas: (NSUInteger)nuevoNumPuertas;
@end

Analicemos la sintaxis de estas funciones. Como podéis ver, ninguna de las dos devuelve ningún valor, luego en el primer paréntesis escribiremos void. Los nombres están claros, pero al final de estos hay dos puntos (“:”). Esto indica que a continuación se encuentra un parámetro. Los parámetros tienen dos partes: la clase del objeto que es el parámetro o el tipo de la variable que es el parámetro y el nombre del mismo. La sintaxis es igual que la del tipo de valor que devuelve la función: El tipo de variable o la clase de objeto entre paréntesis (si es un objeto el parámetro se añade un asterisco) y a continuación el nombre del mismo. Las funciones pueden admitir varios parámetros, y pueden haber funciones con el mismo nombre pero diferentes parámetros. A continuación tenéis un ejemplo.

- (void)miFuncion;
- (void)miFuncionConUnParametro: (NSUInteger)miParametro;
- (NSString *)miFuncionConUnParametro: (NSUInteger)miParametro queAdemasDevuelveUnaCadenaDeTextoYRequiereOtroParametro: (NSUInteger)elSegundo;

Esto presenta un problema: ¿Cómo se llaman las funciones, si puede haber dos iguales hasta el primer parámetro? Pues bien, las funciones anteriores se llamarían así:

miFuncion
miFuncionConUnParametro:
miFuncionConUnParametro:queAdemasDevuelveUnaCadenaDeTextoYRequiereOtroParametro:

De este modo no son iguales los nombres a pesar de ser bastante parecidos (al menos en principio).

Con esto hemos creado la interfaz de nuestra clase: el índice de variables y métodos a los que responde. Sin embargo aún tenemos que escribir el código de estas funciones, así que vayamos al archivo Coche.m y comencemos a implementarlas. En el archivo .m veremos el siguiente código:

#import "Coche.h"
@implementation Coche
@end

Os suena, ¿verdad? Como en el caso anterior, vemos como se importa un archivo, en este caso la interfaz de nuestra clase. También vemos como se inicia la implementación con un código similar a la interfaz. Como podéis suponer, entre @implementation Coche y @end es donde escribiremos nuestras funciones.

Antes de implementar nuestras funciones, añadid el siguiente código después de @implementation Coche. Se trata de un método para la gestión de memoria que veremos en otro tutorial. Así de forma rápida, el método dealloc se llama cuando un objeto va a ser eliminado de la memoria. Los objetos tienen un contador interno que se aumenta con el método retain y se disminuye con el método release. Cuando el contador llega a 0, se llama automáticamente al método dealloc y se elimina el objeto de la memoria. De momento basta con que lo copiéis sin preguntar, ya lo explicaré más adelante.

- (void)dealloc
{
 [color release];
 [super dealloc];
}

Aprovechando este código os explicaré cómo se sobreescriben funciones ya existentes en la clase padre. Como he comentado, una clase que hereda de otra recibe las funciones de la clase padre, pero ¿qué sucede si queremos que en la clase hija la función heredada sea diferente? Pues nada, escribimos la nueva función como cualquier otra. La sintaxis es sencilla:

- (TIPO_DE_VALOR_QUE_SE_DEVUELVE)NOMBRE_DE_LA_FUNCION
{
// Código de la función
}

¿Qué ocurre si queremos que además de ejecutarse nuestro código se ejecute también el método (por si no os habéis dado cuenta, utilizo método y función para referirme a lo mismo, tal vez no es lo más correcto, pero estoy más acostumbrado a hablar de función y no de método, así que me sale sin pensar) de la clase padre que estamos sobreescribiendo? Pues añadimos [super NOMBRE_DE_LA_FUNCION]; en el lugar en el que queramos que se ejecute.

- (TIPO_DE_VALOR_QUE_SE_DEVUELVE)NOMBRE_DE_LA_FUNCION
 {
// Podemos ejecutar el método de la clase padre antes que nuestro código
[super NOMBRE_DE_LA_FUNCION];
// Código de la función
// O después
[super NOMBRE_DE_LA_FUNCION];
}

Veamos ahora cómo quedaría la implementación de nuestra clase tras añadir todos los métodos que hemos definido en la interfaz:

#import "Coche.h"
@implementation Coche
- (void)dealloc
{
 [color release];
 [super dealloc];
}
- (NSString *)getColor
{
}
- (NSUInteger)getNumPuertas
{
}
- (void)imprimirDetalles
{
}
- (void)setColor: (NSString *)colorNuevo
{
}
- (void)setNumPuertas: (NSUInteger)nuevoNumeroDePuertas
{
}
@end

Fijáos en que he cambiado el nombre de las variables de los argumentos de las dos últimas funciones. Las variables de los argumentos no tienen por qué tener el mismo nombre en la interfaz y en la implementación, pero tampoco pasa nada porque tengan el mismo nombre.

La función getColor y getNumPuertas tan sólo devuelven el valor de las variables correspondientes, así que añadiremos return VARIABLE; para que el método devuelva el valor de la variable. return no requiere asterisco si se devuelven objetos, se usa exactamente igual con objetos que con variables sencillas.

En la función imprimirDetalles utilizaremos la función NSLog para imprimir en la consola los valores de las variables. La función NSLog admite varios parámetros. El primero siempre es una cadena de texto (@””), pero esta cadena admite combinaciones de caracteres específicas que indican que se deben reemplazar por otro valor. Así un %d se reemplazará por un número entero, un %f por un número decimal y un %@ por otra cadena de texto (se puede usar tranquilamente un objeto también, lo veremos más adelante). Si usamos estas combinaciones, tras la cadena de caracteres, y separadas por comas (“,”) debemos introducir las variables o los objetos que reemplazarán las combinaciones. A continuación tenéis las tres funciones que hemos explicado:

- (NSString *)getColor
{
 return color;
}
- (NSUInteger)getNumPuertas
{
 return numPuertas;
}
- (void)imprimirDetalles
{
 NSLog(@"Este coche es de color %@ y tiene %d puertas", [self getColor], [self getNumPuertas]);
}

Fijáos en la última función, concretamente en [self getColor] y [self getNumPuertas]. Esta es la sintaxis para enviar mensajes a los objetos. Enviar un mensaje a un objeto es, básicamente, pedirle a un objeto que ejecute el método con ese nombre. Así, cuando escribimos [self funcion] le pedimos al objeto self que ejecute el método funcion. El objeto self es un objeto especial y hace referencia al objeto actual, de modo que lo que hacemos en esta última función es pedirle al objeto de clase Coche que ejecuta el método imprimirDetalles que ejecute el método getColor y getNumPuertas.

Las funciones setColor y setNumPuertas son bastante sencillas. Simplemente asignaremos (mediante “=”) el valor que se pasa como parámetro (o argumento) a la variable correspondiente. Aquí los tenéis completos:

- (void)setColor: (NSString *)colorNuevo
{
 color = colorNuevo;
}
- (void)setNumPuertas: (NSUInteger)nuevoNumeroDePuertas
{
 numPuertas = nuevoNumeroDePuertas;
}

Y este es el aspecto final de la implementación de nuestra clase Coche:

#import "Coche.h"
@implementation Coche
- (void)dealloc
{
 [color release];
 [super dealloc];
}
- (NSString *)getColor
{
 return color;
}
- (NSUInteger)getNumPuertas
{
 return numPuertas;
}
- (void)imprimirDetalles
{
 NSLog(@"Este coche es de color %@ y tiene %d puertas", [self getColor], [self getNumPuertas]);
}
- (void)setColor: (NSString *)colorNuevo
{
 color = colorNuevo;
}
- (void)setNumPuertas: (NSUInteger)nuevoNumeroDePuertas
{
 numPuertas = nuevoNumeroDePuertas;
}
@end

Ahora modificaremos nuestra aplicación para que cree un objeto de clase coche, establezca su color en azul y su número de puertas en 5 y que a continuación imprima en la consola la información sobre el mismo.

Vamos al archivo NOMBREPROYECTO.m, que debería tener el siguiente código:

#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 // insert code here...
 NSLog(@"Hello, World!");
 [pool drain];
 return 0;
}

E importamos el archivo Coche.h justo después de importarse Foundation:

#import "Coche.h"

A continuación añadimos, entre NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; y [pool drain];:

Coche *miCoche = [[Coche alloc] init];
 [miCoche setColor:@"Azul"];
 [miCoche setNumPuertas:5];
 [miCoche imprimirDetalles];
 [miCoche release];

Vayamos línea a línea:

Coche *miCoche = [[Coche alloc] init];

En esta línea creamos el objeto miCoche, de clase Coche. Fijáos como se le envía a  la clase Coche el mensaje alloc y al objeto resultante de ese mensaje se le envía el mensaje init. Los mensajes se pueden encadenar tanto como se quiera, aunque esto hace más complicado de leer el código, así que no es muy recomendable.

[miCoche setColor:@"Azul"];
[miCoche setNumPuertas:5];

En estas dos líneas se envía el método setColor: y setNumPuertas: al objeto miCoche, con el parámetro @”Azul” como nuevo color y 5 como número de puertas.

[miCoche imprimirDetalles];

En esta línea se le manda al objeto el mensaje imprimirDetalles, lo que hará que muestre por terminal los valores de las variables.

 [miCoche release];

Por último esta línea elimina el objeto. En realidad es algo más complejo, y lo explicaré más adelante en otro tutorial. De momento con saber que se elimina el objeto nos vale.

El código resultante de MIPROYECTO.m será:

#import <Foundation/Foundation.h>
#import "Coche.h"
int main (int argc, const char * argv[]) {
 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 // insert code here...
 NSLog(@"Hello, World!");
 Coche *miCoche = [[Coche alloc] init];
 [miCoche setColor:@"Azul"];
 [miCoche setNumPuertas:5];
 [miCoche imprimirDetalles];
 [miCoche release];
 [pool drain];
 return 0;
}

Y si compilamos y ejecutamos la aplicación veremos el siguiente resultado:

Resultado de la segunda aplicación

Esto no está mal, pero, ¿para qué llamar a dos métodos para establecer las variables y otro más para iniciar el objeto (init)? ¿No podríamos juntar esos tres métodos en uno? Sí, podemos. Vayamos al archivo Coche.h y añadamos el siguiente método:

- (Coche *)initWithColor: (NSString *)nuevoColor andNumPuertas: (NSUInteger)nuevoNumPuertas;

Quedando así la interfaz:

#import <Cocoa/Cocoa.h>
@interface Coche : NSObject {
 NSString    *color;
 NSUInteger    numPuertas;
}
- (Coche *)initWithColor: (NSString *)nuevoColor andNumPuertas: (NSUInteger)nuevoNumPuertas;
- (NSString *)getColor;
- (NSUInteger)getNumPuertas;
- (void)imprimirDetalles;
- (void)setColor: (NSString *)nuevoColor;
- (void)setNumPuertas: (NSUInteger)nuevoNumPuertas;
@end

En la implementación añadiremos lo siguiente:

- (Coche *)initWithColor: (NSString *)nuevoColor andNumPuertas: (NSUInteger)nuevoNumPuertas
{
 if (self = [super init])
 {
 [self setColor:nuevoColor];
 [self setNumPuertas:nuevoNumPuertas];
 }
 return self;
}

Analicemos este código. La primera línea de la función, if (self = [super init]) sirve para comprobar que el objeto se ha creado correctamente. Es posible (aunque raro) que por algún motivo el objeto no pueda crearse correctamente (por ejemplo, por falta de memoria), así que en caso de que no se cree correctamente, no estableceremos el valor de ninguna variable (pues de otra manera haríamos fallar la aplicación). Dentro de la condición se envía los mensajes que ya conocemos al objeto y finalmente se devuelve el objeto self. Como podéis ver, esta función devuelve un objeto de clase Coche.

El código final de nuestra implementación será:

#import "Coche.h"
@implementation Coche
- (Coche *)initWithColor: (NSString *)nuevoColor andNumPuertas: (NSUInteger)nuevoNumPuertas
{
 if (self = [super init])
 {
 [self setColor:nuevoColor];
 [self setNumPuertas:nuevoNumPuertas];
 }
 return self;
}
- (void)dealloc
{
 [color release];
 [super dealloc];
}
- (NSString *)getColor
{
 return color;
}
- (NSUInteger)getNumPuertas
{
 return numPuertas;
}
- (void)imprimirDetalles
{
 NSLog(@"Este coche es de color %@ y tiene %d puertas", [self getColor], [self getNumPuertas]);
}
- (void)setColor: (NSString *)colorNuevo
{
 color = colorNuevo;
}
- (void)setNumPuertas: (NSUInteger)nuevoNumeroDePuertas
{
 numPuertas = nuevoNumeroDePuertas;
}
@end

¿Cómo aplicamos estos cambios a nuestra aplicación? Vayamos al archivo NOMBREPROYECTO.m y reemplacemos el siguiente código:

Coche *miCoche = [[Coche alloc] init];
 [miCoche setColor:@"Azul"];
 [miCoche setNumPuertas:5];

Por este otro:

Coche *miCoche = [[Coche alloc] initWithColor:@"Azul" andNumPuertas:5];

Como veis, hemos convertido tres líneas de código en sólo una, y el resultado es idéntico.

Esto tan sólo es una breve introducción al paradigma de la programación orientada a objetos. Espero que os haya aclarado un poco los conceptos. En los próximos tutoriales iremos viendo más características de la POO en Objective-C.

Introducción a Objective-C: Nuestra primera aplicación

This post was published 8 years ago. It may be exremely outdated.

¿Qué es Objective-C? ¿Qué es Cocoa? ¿Qué es la Programacion Orientada a Objetos (POO)? ¿Y la arquitectura de Modelo Vista Controlador (MVC)? Dar los primeros pasos en la programación para Mac OS X, iPhone y iPad puede ser algo complicado si no sabes dónde buscar la información (y aún más difícil si no sabes inglés, imprescindible en el mundo de la informática). Hace año y medio, cuando yo comencé a aprender a programar para el iPhone (no tengáis prisa, sigo haciéndolo y me queda para mucho rato), el primer problema que tuve fue encontrar fuentes de información para dar los primeros pasos, así que he decido escribir esta serie de tutoriales para facilitar la tarea a aquellos que, como yo, quieran aprender a programar para el iPhone (extensible a Mac OS X y iPad). Tampoco esperéis ser unos maestros de Objective-C después de haber leído esta serie de tutoriales (que iré publicando cuando vaya teniendo tiempo para redactarlos), pues mis conocimientos son fruto del autodidactismo y seguramente no utilice los términos adecuados ni profundice del todo en los conceptos que trate. Sin embargo espero que os sirva para dar el primer paso y poder continuar después con textos mejor redactados, más exactos y más profundos. Read more →

Poniendo a punto el diseño de Sumolari.com

This post was published 8 years ago. It may be exremely outdated.

Carrusel de la página de inicio

Los que hayáis visitado antes Sumolari.com y seáis observadores, habréis notado ciertos cambios en el diseño del blog. Para comenzar, y como ya anuncié a mediados de septiembre del año pasado, y es hoy cuando se hace efectivo el cambio: el blog pasa a ser una parte más de Sumolari.com, y no el eje principal de la web. A partir de ahora se podrá acceder al blog desde el enlace del menú principal, desde http://sumolari.com/blog o desde el subdominio http://blog.sumolari.com. La página principal contendrá un carruseles con los últimos proyectos en los que trabaje y series de tutoriales que vaya publicando en el blog.

Información del artículo

Información del artículo

Información del enlace

Información del enlace

A pesar de no ser el centro de la web, el blog también tiene algunas novedades. He modificado ligeramente las etiquetas que indican la fecha de publicación del artículo, y al pasar el cursor sobre ésta, se despliega información acerca de las categorías en las que se ha publicado el artículo.

Otra de las novedades respecto al blog es que ahora dejar el cursor sobre un enlace que dirija a un artículo de Sumolari.com, se mostrará el título de la página a la que dirige, de modo que es más fácil saber hacia dónde lleva el enlace. He eliminado el icono que indicaba que el enlace dirigía a una página externa a Sumolari.com, y lo he reemplazado por un color negro al pasar el cursor sobre el enlace, por contra, al pasarse el cursor sobre un enlace que dirige a Sumolari.com, éste pasa a tener un color gris.

Buscador instantáneo

Buscador instantáneo

Suscribirse a los comentarios

Suscribirse a los comentarios

En cuanto al buscador de la web, lo he modificado para que busque según que van escribiendo las palabras, aunque se puede forzar una búsqueda pulsando Enter o haciendo clic en el icono de la lupa.

También he estado revisando el tema de las suscripciones a los comentarios. WordPress crea un RSS de los comentarios de cada artículo, pero he puesto ningún enlace a los mismos en los artículos: tan sólo hay un enlace a este RSS en la pestaña de Meta.

Gestionar las suscripciones

Gestionar las suscripciones

Rediseño del formulario de contacto

Rediseño del formulario de contacto

Estuve planteándome qué solución aplicar para poder llevar un seguimiento de los comentarios, y he decidido implementar el plugin Subscribe to Comments, que permite a los lectores recibir un email automáticamente cada vez que se publica un nuevo comentario en un artículo. No obstante, he modificado el plugin para que se adapte mejor a mis intenciones y se puedan gestionar las suscripciones sin salir del artículo que se está leyendo, trabajando en una ventana que se superpone al contenido, como los resultados de la búsqueda o el menú de Proyectos.

El formulario de contacto también ha cambiado ligeramente para diferenciar mejor los campos y utilizar mejor el espacio, aunque el funcionamiento es el mismo de siempre.

Columnas en las pestañas

Columnas en las pestañas

Por último, el pie de página también ha sido ligeramente modificado. He unificado las pestañas Recomendado y Meta, además de que ahora el contenido de las pestañas está dividido en dos columnas para aprovechar mejor el ancho de la página.

Aparte de estas novedades, también he arreglado algunos fallos que había acumulado de versiones anteriores del diseño, nada del otro mundo, pero ahora algunos fallos que había antes, como que al pasar el cursor sobre una imagen semitransparente su fondo cambiaba a un color azul claro, entre otros.

Y éstas son todas las novedades del diseño de Sumolari.com.

Propósitos y proyectos para 2011

This post was published 8 years ago. It may be exremely outdated.

Ayer terminó el año 2010, y fue un buen momento para hacer una revisión completa del mismo y plantearse nuevos retos para el año que hoy comienza. Este último trimestre ha sido un trimestre de poca actividad en Sumolari.com, de hecho no he escrito ningún artículo y me he limitado a responder a los comentarios y a los mensajes del foro.

No obstante, y a pesar del escaso tiempo libre del que gozo este año, he tenido el tiempo suficiente como para darle una puesta a punto al diseño del blog, comenzar a redactar una serie de tutoriales de Objective-C y POO (actualmente tengo escritos sólo 2 artículos de la serie de tutoriales), a continuar el desarrollo de WP Carousel y a trabajar en una nueva aplicación para iOS.

Mis intenciones para este año 2011 son:

  • Redactar artículos de introducción a Objective-C y POO, con la intención de enseñar lo fundamental a aquellos que quieran introducirse en la programació para Mac OS X y iOS.
  • Liberar la próxima versión de WP Carousel, que está rebosante de novedades y de la que pronto espero tener lista una primera versión Alpha.
  • Terminar y publicar en la AppStore mi segunda aplicación para iOS, de la que hablaré cuando sea, con suerte, aprobada (o sin ella, rechazada).
  • Diseñar más themes para WordPress, aplicando lo aprendido durante el desarrollo de WP Carousel y las mejoras en el diseño de Sumolari.com. Así, a partir de ahora mis themes soportarán todas las características de WordPress 3.0 e incluirán un buscador instantáneo de artículos, páginas, etiquetas y categorías, además de soportar de forma nativa WP Carousel.

Sin embargo ninguna de estas cosas tiene fecha fija. Espero poder terminar mi aplicación para iOS antes de acabar la semana próxima, si tengo suerte y la acabo a tiempo, podría estar disponible a principios de febrero (siempre y cuando fuese revisada en dos semanas y aprobada). Sino, me temo que se podría retrasar bastante tiempo.

En cuanto a WP Carousel, muchas de las características de la próxima versión ya están terminadas, sin embargo aún queda una de las más importantes: el soporte de jCarousel y la actualización de los themes para soportar el nuevo motor. De todos modos, me gustaría lanzar una versión Alpha en poco tiempo, aunque esta versión no incluya el soporte de jCarousel. No será lo mismo que la versión final pero servirá para probar algunas de las nuevas características, que seguro que gustarán a muchos.

Por último, me gustaría diseñar más themes para WordPress. De hecho ya tengo dos bocetos de posibles themes, pero no he tenido tiempo para crearlos en HTML y CSS, de modo que no son más que dibujos en un papel que esperan ser convertidos en realidad. Estos themes los comenzaré a diseñar cuando termine con WP Carousel y con mi aplicación para iOS.