<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Sumolari.com &#187; Tutoriales</title>
	<atom:link href="http://sumolari.com/category/tutoriales/feed/" rel="self" type="application/rss+xml" />
	<link>http://sumolari.com</link>
	<description>Proyectos de un amante de la informática</description>
	<lastBuildDate>Thu, 09 Feb 2012 20:06:17 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Guardar objetos en archivos con Objective-C</title>
		<link>http://sumolari.com/guardar-objetos-en-archivos-con-objective-c/</link>
		<comments>http://sumolari.com/guardar-objetos-en-archivos-con-objective-c/#comments</comments>
		<pubDate>Wed, 07 Sep 2011 06:50:02 +0000</pubDate>
		<dc:creator>Sumolari</dc:creator>
				<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Introducción a Objective-C]]></category>
		<category><![CDATA[xcode]]></category>

		<guid isPermaLink="false">http://sumolari.com/?p=5633</guid>
		<description><![CDATA[Ayer Carmen Parra preguntaba en un comentario cómo se pueden guardar los datos introducidos por el usuario en un archivo. Como el proceso es demasiado largo como para publicarlo en un comentario, he decidido escribir este pequeño tutorial. NSArray, NSDictionary, NSString, NSNumber, NSData y otros Hay dos métodos sencillos para almacenar un objeto en un [...]]]></description>
			<content:encoded><![CDATA[<p>Ayer <a href="http://sumolari.com/introduccion-a-objective-c-el-paradigma-de-la-poo/comment-page-1/#comment-42784">Carmen Parra</a> preguntaba en un comentario cómo se pueden guardar los datos introducidos por el usuario en un archivo. Como el proceso es demasiado largo como para publicarlo en un comentario, he decidido escribir este pequeño tutorial.</p>
<h3>NSArray, NSDictionary, NSString, NSNumber, NSData y otros</h3>
<p><a href="http://sumolari.com/wp-content/uploads/2011/09/Captura-de-pantalla-2011-09-07-a-las-07.21.15.png" rel="lightbox-5633"><img class="alignright size-medium wp-image-5634 rightimage" title="Resultado del código de ejemplo" src="http://sumolari.com/wp-content/uploads/2011/09/Captura-de-pantalla-2011-09-07-a-las-07.21.15-300x115.png" alt="Resultado del código de ejemplo" width="300" height="115" /></a>Hay dos métodos sencillos para almacenar un objeto en un archivo y poder recuperarlo cuando nos convenga. El primero no se puede aplicar a cualquier objeto, sino a objetos de algunas clases de <a href="http://sumolari.com/category/objective-c/">Objective-C </a>que responden a dos métodos llamados <em>writeToFile:atomically:</em> y <em>writeToURL:atomically:</em>. El uso de estos métodos es muy sencillo, basta con llamarlos en el momento en el que queramos que el objeto se guarde en un archivo.</p>
<p>A continuación teneís un ejemplo comentado. Básicamente creamos una matriz, le añadimos algo de contenido, la imprimimos, la guardamos en un archivo y nos deshacemos de ella. A continuación creamos otra matriz que lea el contenido del archivo y comprobamos que tiene el mismo contenido que la anterior. El resultado que obtendréis será similar al de la imagen de la derecha.</p>
<pre class="brush: objc; title: ; notranslate">
NSMutableArray *array = [[NSMutableArray alloc] init]; // Creamos una matriz
	[array addObject:@&quot;¡Hola&quot;]; // Añadimos un objeto
	[array addObject:@&quot;mundo!&quot;]; // Añadimos otro objeto
	NSLog(@&quot;Matriz original: %@&quot;, array); // Imprimimos la matriz original
	[array writeToFile:@&quot;filename&quot; atomically:YES]; // Escribimos en el archivo filename el contenido de la matriz
	[array release]; // Liberamos memoria

	NSMutableArray *arrayFromFile = [[NSMutableArray alloc] initWithContentsOfFile:@&quot;filename&quot;]; // Esta matriz tiene el mismo contenido que tenía la matriz anterior
	NSLog(@&quot;%@&quot;, arrayFromFile); // Imprimimos la matriz recuperada del archivo
	[arrayFromFile release]; // Liberamos memoria
</pre>
<p>Del mismo modo que se puede guardar en un archivo un objeto de la clase <em>NSArray</em>, también se puede usar con objetos <em>NSDictionary</em>, <em>NSString</em>, <em>NSData</em> y <em>NSNumber</em>, entre otros. Sin embargo no se puede usar con objetos de una clase creada por nosotros (en la mayoría de los casos).</p>
<h3>Clases creadas por nosotros</h3>
<p>Para guardar en un archivo un objeto de una clase creada por nosotros, tendremos que hacer que el objeto sigua el protocolo <em>NSCoding</em>. Tras esto, mediante las clases <em>NSKeyedArchiver</em> y <em>NSKeyedUnarchiver</em> podremos guardar en un archivo y leer de un archivo nuestro objeto. Este protocolo tiene dos métodos necesarios: <em>initWithCoder:</em> y <em>encodeWithCoder:</em>.</p>
<p>Vamos a suponer que hemos creado la clase <em>Empleado</em>, que tiene la siguiente interfaz:</p>
<pre class="brush: objc; title: ; notranslate">
@interface Empleado : NSObject

@property (nonatomic, retain)	NSString	*nombre, *apellidos;
@property						NSUInteger	edad;
@property						BOOL		esEmpleadoDelMes;

@end
</pre>
<p>Para poder almacenar este objeto en un archivo tendremos primero que hacer que siga el protocolo <em>NSCoding</em>. Modficaremos la interfaz y la dejaremos así:</p>
<pre class="brush: objc; title: ; notranslate">
#define kNombre				@&quot;Nombre&quot;
#define kApellidos			@&quot;Apellidos&quot;
#define kEdad				@&quot;Edad&quot;
#define kEsEmpleadoDelMes	@&quot;esEmpleadoDelMes&quot;

@interface Empleado : NSObject

@property (nonatomic, retain)	NSString	*nombre, *apellidos;
@property						NSUInteger	edad;
@property						BOOL		esEmpleadoDelMes;

@end
</pre>
<p>Básicamente hay dos cambios: hemos indicado que la clase sigue el protocolo <em>NSCoding</em> y hemos definido una serie de constantes que usaremos más adelante y que entenderéis en seguida su utilidad.</p>
<p>Ahora pasamos a la implementación. Esta es la implementación original de la clase <em>Empleado</em>, antes de seguir el protocolo <em>NSCoding</em>:</p>
<pre class="brush: objc; title: ; notranslate">
@implementation Empleado

@synthesize nombre, apellidos;
@synthesize edad;
@synthesize esEmpleadoDelMes;

- (void)dealloc
{
	[nombre release];
	[apellidos release];

	[super dealloc];
}

@end
</pre>
<p>Ahora vamos a añadir los dos métodos que necesitamos para seguir el protocolo <em>NSCoding</em>. Estos métodos nos permiten archivar nuestro objeto. El método <em>encodeWithCoder:</em> tiene por parámetro un objeto de la clase <em>NSCoder</em>. En este objeto archivaremos las propiedades del nuestro, asignándole a una serie de claves las propiedades del objeto.</p>
<p>Por ejemplo, si queremos hacer que la propiedad <em>nombre</em> se archive en la clave <em>clave</em>, el método tendría el siguiente aspecto:</p>
<pre class="brush: objc; title: ; notranslate">
- (void)encodeWithCoder:(NSCoder *)coder {

    [coder encodeObject:self.nombre forKey:@&quot;clave&quot;];

}
</pre>
<p>No todas las propiedades se archivan de la misma forma. Los objeto se archivan a través del método <em>encodeObject:forKey:</em>, los números enteros se archivan con <em>encodeInteger:forKey:</em> y los valores booleanos con <em>encodeBool:forKey:</em>. Las claves son muy importantes, ya que el método <em>initWithCoder:</em> va a desarchivar el objeto usando las mismas claves para acceder a las propiedades, por eso hemos definido una serie de constantes que serán las claves que usaremos para archivar y desarchivar las propiedades.</p>
<p><strong>Nota:</strong> Tenéis una lista de todos los métodos para archivar objetos, así como una explicación del proceso de archivar y desarchivar objetos en <a href="http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Archiving/Articles/codingobjects.html#//apple_ref/doc/uid/20000948-BCIHBJDE">la documentación de Apple</a> (en inglés).</p>
<p>Nuestro método <em>encodeWithCoder:</em> quedará así:</p>
<pre class="brush: objc; title: ; notranslate">
- (void)encodeWithCoder:(NSCoder *)coder {

    [coder encodeObject:self.nombre forKey:kNombre];
	[coder encodeObject:self.apellidos forKey:kApellidos];
	[coder encodeInteger:self.edad forKey:kEdad];
	[coder encodeBool:self.esEmpleadoDelMes forKey:kEsEmpleadoDelMes];

}
</pre>
<p>El método <em>initWithCoder:</em> es muy similar al anterior, sólo que su funcionamiento es el contrario: a partir de un objeto archivado se obtienen las propiedades y se crea un objeto de la clase <em>Empleado</em> (en este caso) con las propiedades que tenía el objeto al archivarse. En este caso enviaremos el mensaje <em>decodeObjectForKey:@&#8221;clave&#8221;</em> a <em>coder</em> y asignaremos el valor devuelto a la propiedad de nuestro objeto. De nuevo, se usan métodos diferentes para decodificar número enteros, valores booleanos y otros tipos de variables. Nuestro método <em>initWithCoder: </em>quedará así:</p>
<pre class="brush: objc; title: ; notranslate">
- (id)initWithCoder:(NSCoder *)coder {

    if ((self = [super init])) {

		self.nombre = [coder decodeObjectForKey:kNombre];
		self.apellidos = [coder decodeObjectForKey:kApellidos];
		self.edad = [coder decodeIntForKey:kEdad];
		self.esEmpleadoDelMes = [coder decodeBoolForKey:kEsEmpleadoDelMes];

	}

    return self;
}
</pre>
<p><a href="http://sumolari.com/wp-content/uploads/2011/09/Captura-de-pantalla-2011-09-07-a-las-08.43.05.png" rel="lightbox-5633"><img class="alignleft size-medium wp-image-5641 leftimage" title="Resultado del ejemplo" src="http://sumolari.com/wp-content/uploads/2011/09/Captura-de-pantalla-2011-09-07-a-las-08.43.05-300x19.png" alt="Resultado del ejemplo" width="300" height="19" /></a>Ahora pasemos a crear un objeto <em>Empleado</em>, a guardarlo en un archivo y a comprobar que funciona correctamente. Primero incluímos la interfaz de la clase <em>Empleado </em>en el archivo en el que vamos a crear el objeto, en mi caso, y al tratarse de una &#8220;<em>Command Line Tool</em>&#8220;, lo incluiré en el archivo <em>main.m</em>. El siguiente código comentado crea un objeto de la clase <em>Empleado</em>, le asigna algunos valores sus propiedades, lo archiva y después crea un nuevo objeto con el contenido del archivo en el que se ha guardado antes el objeto:</p>
<pre class="brush: objc; title: ; notranslate">
Empleado *trabajador = [[Empleado alloc] init]; // Creamos el objeto
	trabajador.nombre = @&quot;Juan&quot;; // Le damos un nombre
	trabajador.apellidos = @&quot;García López&quot;; // Unos apellidos
	trabajador.edad = 26; // Una edad
	trabajador.esEmpleadoDelMes = YES; // Y lo hacemos empleado del mes

	NSLog(@&quot;%@ %@ tiene %lu años&quot;, trabajador.nombre, trabajador.apellidos, trabajador.edad); // Imprimimos sus datos

	[NSKeyedArchiver archiveRootObject:trabajador toFile:@&quot;empleado&quot;]; // Lo guardamos en el archivo empleado

	[trabajador release]; // Liberamos memoria

	Empleado *trabajadorRecuperado = [NSKeyedUnarchiver unarchiveObjectWithFile:@&quot;empleado&quot;]; // Creamos un objeto a partir del archivo empleado

	NSLog(@&quot;%@ %@ tiene %lu años&quot;, trabajadorRecuperado.nombre, trabajadorRecuperado.apellidos, trabajadorRecuperado.edad); // Imprimimos sus datos
</pre>
<p>Así se puede guardar un objeto de cualquier clase en un archivo, de forma que puede ser recuperado en cualquier momento. Los objetos más complejos pueden necesitar métodos más complejos a la hora de archivarlos. Del mismo modo no se tienen por qué archivar todas las propiedades si no se quiere.</p>
<p>Por último <a href="http://cl.ly/140k2I3L2b1U1N0E0Z1H">dejo a vuestra disposición los archivos del proyecto que he creado mientras escribía el tutorial</a>, por si os atascáis y necesitáis un empujoncito.</p>
]]></content:encoded>
			<wfw:commentRss>http://sumolari.com/guardar-objetos-en-archivos-con-objective-c/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Borra archivos de un pendrive en Mac OS X sin vaciar la papelara</title>
		<link>http://sumolari.com/borra-archivos-de-un-pendrive-en-mac-os-x-sin-vaciar-la-papelara/</link>
		<comments>http://sumolari.com/borra-archivos-de-un-pendrive-en-mac-os-x-sin-vaciar-la-papelara/#comments</comments>
		<pubDate>Sat, 20 Aug 2011 10:26:09 +0000</pubDate>
		<dc:creator>Sumolari</dc:creator>
				<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[automator]]></category>
		<category><![CDATA[trucos]]></category>

		<guid isPermaLink="false">http://sumolari.com/?p=5423</guid>
		<description><![CDATA[Editado: En la primera versión de esta pequeña aplicación había un error que provocaba que en unidades con nombres que incluyesen espacios o caracteres especiales no se borrasen los archivos de forma definitiva. Se ha resuelto y he actualizado el artículo añadiendo el enlace para descargar la última versión en lugar de la que tenía [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Editado:</strong> En la primera versión de esta pequeña aplicación había un error que provocaba que en unidades con nombres que incluyesen espacios o caracteres especiales no se borrasen los archivos de forma definitiva. Se ha resuelto y he actualizado el artículo añadiendo el enlace para descargar la última versión en lugar de la que tenía el error. ¡Gracias a Jorosa por el aviso!</p>
<div id="attachment_5430" class="wp-caption alignleft" style="width: 240px"><a href="http://sumolari.com/wp-content/uploads/2011/08/Captura-de-pantalla-2011-08-20-a-las-12.00.20.png" rel="lightbox-5423"><img class="size-thumbnail wp-image-5430 " title="Archivos &quot;borrados&quot; del pendrive" src="http://sumolari.com/wp-content/uploads/2011/08/Captura-de-pantalla-2011-08-20-a-las-12.00.20-230x130.png" alt="Archivos &quot;borrados&quot; del pendrive" width="230" height="130" /></a><p class="wp-caption-text">Hay cerca de 800MB de archivos &quot;borrados&quot; en este pendrive</p></div>
<p>Hay veces que uno se sorprende al ver ciertos comportamientos de <a href="http://sumolari.com/category/mac-os-x/">Mac OS X</a>. Uno de los que menos me gustan es la forma de borrar archivos de un dispositivo extraíble (por ejemplo, un pendrive). En lugar de borrar el archivo, como sería de esperar, o moverlo a la papelera del Mac, lo almacena en una carpeta oculta dentro del propio pendrive que usa a modo de papelera. Si nos fijamos en la papelera de nuestro Mac, veremos que los archivos que hemos borrado del pendrive aparecen en ella, aunque no estén almacenados en el Mac.</p>
<p>El problema radica en que además de no borrar realmente los archivos y dejarlos en el pendrive (ocupando parte de su preciada capacidad), no hay forma de borrar los archivos individualmente de la papelera. Si usamos la combinación <em>Función</em> + <em>Retroceso</em> lo que hacemos es devolver el archivo eliminado a su carpeta de origen en lugar de borrarlo. Estamos pues obligados a vaciar la papelera y borrar definitivamente otros archivos que tal vez no queramos perder todavía.</p>
<p>Así que, algo mosqueado porque esto no haya cambiado ni en Snow Leopard ni en Lion (ni tiene pinta de que vaya a cambiar), he creado una simple aplicación en Automator para &#8220;<em>limpiar</em>&#8221; los pendrives de archivos supuestamente eliminados.</p>
<h3>Cómo funciona</h3>
<div id="attachment_5433" class="wp-caption alignright" style="width: 240px"><a href="http://sumolari.com/wp-content/uploads/2011/08/Captura-de-pantalla-2011-08-20-a-las-12.08.27.png" rel="lightbox-5423"><img class="size-thumbnail wp-image-5433" title="La carpeta .Trashes al descubierto" src="http://sumolari.com/wp-content/uploads/2011/08/Captura-de-pantalla-2011-08-20-a-las-12.08.27-230x130.png" alt="La carpeta .Trashes al descubierto" width="230" height="130" /></a><p class="wp-caption-text">Esto lo aclara todo</p></div>
<p>Antes de dar los enlaces para descargar la aplicación, veamos cómo funciona. Como ya he dicho, Mac OS X mueve los archivos &#8220;<em>borrados</em>&#8221; a una carpeta oculta que funciona a modo de papelera. Esta carpeta se llama <em>.Trashes</em> (como de costumbre en OS X, al llevar un punto al principio del nombre, la carpeta es oculta). Si borramos la carpeta<em> .Trashes</em>, borramos todos los archivos que queríamos eliminar pero, ¿cómo la borramos sin pasar por la papelera de nuevo?</p>
<p>Aquí es donde entra en juego el potencial de un sistema basado en Unix. Gracias al comando <strong>rm</strong> (<strong>r</strong>emo<strong>v</strong>e) podemos eliminar archivos o carpetas sin necesidad de pasar por la papelera. Combinando esto con un par de parámetros, concretamente <strong>-R</strong> (borrar de forma recursiva) <strong>-f</strong> (sin pedir confirmación) y <strong>-d</strong> (directorios y archivos) conseguimos vaciar el pendrive de archivos que queríamos borrar.</p>
<p>Obviamente tener que escribir todo esto en la terminal cada vez que queremos limpiar un pendrive de archivos &#8220;<em>borrados</em>&#8221; no es muy cómodo. Para hacer más cómoda la tarea recurriremos a <em>Automator</em>, ese pobre incomprendido que si bien es capaz de hacer maravillas, la mayoría de los usuarios desconoce incluso su existencia.</p>
<p><a href="http://sumolari.com/wp-content/uploads/2011/08/Captura-de-pantalla-2011-08-20-a-las-11.43.22.png" rel="lightbox-5423"><img class="size-thumbnail wp-image-5435 alignleft leftimage" style="border: none;" title="Creamos una nueva aplicación en Automator" src="http://sumolari.com/wp-content/uploads/2011/08/Captura-de-pantalla-2011-08-20-a-las-11.43.22-230x130.png" alt="Creamos una nueva aplicación en Automator" width="230" height="130" /></a><a href="http://sumolari.com/wp-content/uploads/2011/08/Captura-de-pantalla-2011-08-20-a-las-11.53.38.png" rel="lightbox-5423"><img class="alignright size-medium wp-image-5436" title="El flujo resultante" src="http://sumolari.com/wp-content/uploads/2011/08/Captura-de-pantalla-2011-08-20-a-las-11.53.38-300x176.png" alt="El flujo resultante" width="300" height="176" /></a>Para crear la aplicación abrimos <em>Automator </em>y elegimos crear una aplicación. A continuación arrastramos las acciones para formar el flujo que podéis ver en la imagen de la derecha. Básicamente el flujo es el siguiente:</p>
<ol>
<li>Solicitamos una carpeta. El usuario deberá seleccionar un dispositivo extraíble.</li>
<li>Establecemos el valor de una variable con la ruta de la carpeta seleccionada.</li>
<li>Leemos el valor de esta variable y se lo pasamos a un script Shell como parámetro (este paso y el anterior supongo que se pueden omitir y usar el resultado del paso 1 como argumentos para el paso 4, pero por pereza no lo he comprobado &#8211; si alguien se anima que lo comente en los comentarios).</li>
<li>En el script <em>Shell</em> usamos el comando <strong>cd</strong> (<strong>c</strong>hange <strong>d</strong>ir) para ir a la ruta del pendrive.</li>
<li>A continuación, en el mismo <em>Shell</em> y cambiada la ruta a la que nos interesa, borramos la carpeta <em>.Trashes</em> con los parámetros que he expuesto antes.</li>
</ol>
<h3>Descarga</h3>
<p>Seguidos los pasos y entendido el funcionamiento, <a href="http://sumolari.com/?dl_id=7">aquí tenéis a vuestra disposición la aplicación</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://sumolari.com/borra-archivos-de-un-pendrive-en-mac-os-x-sin-vaciar-la-papelara/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mejora el aspecto de Google Reader con Stylish</title>
		<link>http://sumolari.com/dale-un-aspecto-mas-atractivo-a-google-reader-con-stylish/</link>
		<comments>http://sumolari.com/dale-un-aspecto-mas-atractivo-a-google-reader-con-stylish/#comments</comments>
		<pubDate>Wed, 13 Jul 2011 12:03:46 +0000</pubDate>
		<dc:creator>Sumolari</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[Navegadores]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[chrome]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[Google Reader]]></category>
		<category><![CDATA[opera]]></category>
		<category><![CDATA[safari]]></category>
		<category><![CDATA[Stylish]]></category>

		<guid isPermaLink="false">http://sumolari.com/?p=5235</guid>
		<description><![CDATA[Google Reader no destaca precisamente por tener el diseño más bonito del mundo. De hecho no ha recibido ningún rediseño desde hace bastante tiempo, a diferencia de otros servicios de como Calendar o Gmail. Si sois de los que utilizáis Google Reader directamente desde su web, sin recurrir a ninguna aplicación que se sincronice con [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://sumolari.com/wp-content/uploads/2011/07/Captura-de-pantalla-2011-07-13-a-las-09.59.17.png" rel="lightbox-5235"><img class="aligncenter size-large wp-image-5236" title="Google Reader después de aplicar algo de CSS con Stylish" src="http://sumolari.com/wp-content/uploads/2011/07/Captura-de-pantalla-2011-07-13-a-las-09.59.17-848x377.png" alt="Google Reader después de aplicar algo de CSS con Stylish" width="848" height="377" /></a></p>
<div id="attachment_5239" class="wp-caption alignleft" style="width: 240px"><a href="http://sumolari.com/wp-content/uploads/2011/07/Captura-de-pantalla-2011-07-13-a-las-10.00.02.png" rel="lightbox-5235"><img class="size-thumbnail wp-image-5239 leftimage" title="Google Reader antes de activar el nuevo estilo" src="http://sumolari.com/wp-content/uploads/2011/07/Captura-de-pantalla-2011-07-13-a-las-10.00.02-230x130.png" alt="Google Reader antes de activar el nuevo estilo" width="230" height="130" /></a><p class="wp-caption-text">Google Reader antes de activar el nuevo estilo</p></div>
<p><a href="http://google.com/reader">Google Reader</a> no destaca precisamente por tener el diseño más bonito del mundo. De hecho no ha recibido ningún rediseño desde hace bastante tiempo, <a href="http://es.engadget.com/2011/07/01/google-vuelve-a-lo-basico-con-un-rediseno-de-gmail-y-google-cale/">a diferencia de otros servicios de como Calendar o Gmail</a>. Si sois de los que utilizáis <a href="http://google.com/reader">Google Reader</a> directamente desde su web, sin recurrir a ninguna aplicación que se sincronice con él, agradeceréis este artículo.</p>
<p>Lo que veis en la imagen de arriba es <a href="http://google.com/reader">Google Reader</a> tras activar algo de CSS a través de Stylish. Si no tenéis instalado Stylish, podéis hacerlo en <a href="https://addons.mozilla.org/es-es/firefox/addon/stylish/">Firefox</a> o <a href="https://chrome.google.com/webstore/detail/fjnbnpbmkenffdnngjfgmeleoegfcffe">Google Chrome</a> (en otros navegadores, como <a href="http://my.opera.com/espanol/forums/topic.dml?id=956352">Opera</a> o <a href="http://www.nystic.com/blog/?p=303">Safari</a>, hay formas diferentes de aplicar los estilos CSS).</p>
<p>Si ya tenéis instalado Stylish, ahora tendréis que instalar los estilos. Al ser un archivo demasiado grande, el autor (<a href="http://userstyles.org/users/24486" rel="nofollow">Mestiso</a>) no ha podido insertarlo directamente en <a href="http://userstyles.org/styles/50474/google-reader-3-column-reader">userstyles.org</a>, pero comparte el código <a href="http://kamilb.info/s/googlereader-3cr.css">en su página web</a>. Para instalarlo (a través de Stylish) primero accederemos a <a href="http://userstyles.org/styles/50474/google-reader-3-column-reader">userstyles.org</a> y haremos clic en el botón<em> Install with Stylish</em>, a continuación editaremos el estilo y reemplazaremos todo el código por el que nos ofrece su autor <a href="http://kamilb.info/s/googlereader-3cr.css">en su página web</a>. Para ello, en Firefox, mostraremos el panel lateral de Stylish (Ver » Panel lateral » Stylish) y haremos doble clic sobre el estilo <em>Google Reader &#8211; 3 Column Reader</em>. Una vez reemplazado el código haremos clic en <em>Guardar</em> y cuando accedamos de nuevo a <a href="http://google.com/reader">Google Reader</a>, veremos un diseño mucho más limpio y elegante.</p>
<p>El único inconveniente es que algunas características dejan de ser accesibles, como los patrones. Sin embargo esta función sigue estando activa. Para poder acceder a ella simplemente desactivaremos temporalmente el nuevo estilo (siguiendo los mismos pasos que antes, sólo que en lugar de hacer doble clic en <em>Google Reader &#8211; 3 Column Reader</em> lo haremos sobre el icono con una S que aparece a la izquierda del nombre, que tras el doble clic perderá el color, indicando que el estilo está desactivado).</p>
<p><strong>Estilo:</strong> <a href="http://userstyles.org/styles/50474/google-reader-3-column-reader">userstyles.org</a><br />
<strong>Estilo:</strong> <a href="http://kamilb.info/s/googlereader-3cr.css">kamilb.info</a><br />
<strong>Stylish:</strong> <a href="https://addons.mozilla.org/es-es/firefox/addon/stylish/">Firefox</a> | <a href="https://chrome.google.com/webstore/detail/fjnbnpbmkenffdnngjfgmeleoegfcffe">Google Chrome</a></p>
]]></content:encoded>
			<wfw:commentRss>http://sumolari.com/dale-un-aspecto-mas-atractivo-a-google-reader-con-stylish/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Añade más páginas al Widget «bbPress View List»</title>
		<link>http://sumolari.com/anade-mas-paginas-al-widget-%c2%abbbpress-view-list%c2%bb/</link>
		<comments>http://sumolari.com/anade-mas-paginas-al-widget-%c2%abbbpress-view-list%c2%bb/#comments</comments>
		<pubDate>Sat, 18 Jun 2011 08:36:23 +0000</pubDate>
		<dc:creator>Sumolari</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[bbPress]]></category>

		<guid isPermaLink="false">http://sumolari.com/?p=5012</guid>
		<description><![CDATA[El Widget de bbPress «View List» que viene por defecto en bbPress 2.0 no tiene demasiada utilidad, al menos aparentemente. Sin embargo ofrece una característica la mar de interesante: podemos añadir cualquier página a ese Widget. ¿Cómo? Ahora lo veremos. En primero lugar hay que entender cómo funciona el Widget. Toma del objeto $bbp la [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://sumolari.com/wp-content/uploads/2011/06/Captura-de-pantalla-2011-06-18-a-las-10.27.54.png" rel="lightbox-5012"><img class="alignright size-thumbnail wp-image-5013 rightimage" title="Ahora hay dos vistas en la lista de views de bbPress 2.0" src="http://sumolari.com/wp-content/uploads/2011/06/Captura-de-pantalla-2011-06-18-a-las-10.27.54-230x130.png" alt="Ahora hay dos vistas en la lista de views de bbPress 2.0" width="230" height="130" /></a>El Widget de <em>bbPress «View List»</em> que viene por defecto en <a href="http://sumolari.com/tag/bbpress/">bbPress</a> 2.0 no tiene demasiada utilidad, al menos aparentemente. Sin embargo ofrece una característica la mar de interesante: podemos añadir cualquier página a ese Widget. ¿Cómo? Ahora lo veremos.</p>
<p>En primero lugar hay que entender cómo funciona el Widget. Toma del objeto <em>$bbp</em> la matriz <em>views</em>, la recorre y genera una lista de vistas disponibles. Por defecto esta matriz sólo tiene una vista: la lista de temas sin respuesta, pero podemos añadir todas las que queramos. La estructura de la matriz <em>views</em> es la siguiente:</p>
<pre class="brush: plain; title: ; notranslate">
Array
(
    [no-replies] =&gt; Array
        (
            [title] =&gt; Topics with no replies
            [query] =&gt; Array
                (
                    [meta_key] =&gt; _bbp_reply_count
                    [meta_value] =&gt; 1
                    [meta_compare] =&gt; &lt;
                    [orderby] =&gt;
                    [show_stickies] =&gt;
                )

            [feed] =&gt; 1
        )

    [IDENTIFICADOR] =&gt; Array
        (
            [title] =&gt;Título
            [query] =&gt; Array
                ( /* Matriz con los parámetros de la consulta a realizar en dicha vista, equivale a query_vars en WP_Query */
                )

            [feed] =&gt; 1 /* Supongo que será si se quiere mostrar o no esta vista en el RSS Feed, pero no lo he comprobado, así que no sé realmente qué es lo que hace */
        )

)
</pre>
<p>Interesante, ¿verdad? Pues bien, jugando un poco con esta matriz no sólo podemos crear enlaces que lleven a páginas que muestren sólo determinados temas, sino que podemos hacer que redirijan a cualquier lugar.</p>
<pre class="brush: php; title: ; notranslate">
function bbpress_add_rss_to_view_list()
	{
		global $bbp;

		$nombre_de_la_vista = 'sumolari_bbpress_rss_feed'; // Utilizo este nombre por si en un futuro añaden a bbPress una vista llamada rss_feed o algo similar

		$bbp-&gt;views[$nombre_de_la_vista] = array(
			'title' =&gt; __('RSS Feed', 'bbpress'),
			'query' =&gt; array(),
			'feed' =&gt; 1
		);

		if (bbp_get_view_id() == $nombre_de_la_vista)
		{
			header('Location: '.home_url().'/feed/?post_type='.$bbp-&gt;topic_post_type);
			exit;
		}

	}

	add_action('get_header', 'bbpress_add_rss_to_view_list');
</pre>
<p>¿Qué hace este código? En primer lugar obtiene el objeto <em>$bbp</em>. A continuación definimos un identificador para nuestra nueva vista. Después añadimos a la matriz <em>views </em>un nuevo índice con nuestro identificador y como valor una matriz que tiene por valor del <em>title, &#8220;RSS Feed</em>&#8220;, por valor del índice <em>query</em> una matriz vacía y por valor del índice <em>feed</em> el número 1. Tras esto verificamos que no nos encontramos en nuestra vista, ya que si así fuera, tendríamos que redirigir la página hacia el RSS Feed de los temas del foro. Por último añadimos esta nueva función a las acciones que se ejecutarán al obtener la cabecera del theme.</p>
<p>¿Cómo generamos el RSS Feed? <a href="../category/wordpress/">WordPress</a> lo hace de forma automática, y al ser los foros de <a href="../tag/bbpress/">bbPress</a> 2.0 artículos de <a href="../category/wordpress/">WordPress</a> con <em>post_type</em> personalizados, basta con cargar el RSS Feed indicando el tipo de artículos que queremos ver, a través del parámetro de URL <em>post_type</em>.</p>
<p>Obviamente esta es sólo una de las cosas que se pueden hacer modificando la lista de vistas. El único límite es nuestra imaginación.</p>
]]></content:encoded>
			<wfw:commentRss>http://sumolari.com/anade-mas-paginas-al-widget-%c2%abbbpress-view-list%c2%bb/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Muestra un widget con tags de bbPress en WordPress</title>
		<link>http://sumolari.com/muestra-un-widget-con-tags-de-bbpress-en-wordpress/</link>
		<comments>http://sumolari.com/muestra-un-widget-con-tags-de-bbpress-en-wordpress/#comments</comments>
		<pubDate>Fri, 17 Jun 2011 20:24:50 +0000</pubDate>
		<dc:creator>Sumolari</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[bbPress]]></category>

		<guid isPermaLink="false">http://sumolari.com/?p=4993</guid>
		<description><![CDATA[Una de las características que sorprendentemente no incluye bbPress 2.0 es un Widget para WordPress que muestre las etiquetas de los temas del foro. Es curioso que incluya un Widget que sólo muestre un enlace a la lista de mensajes sin responder y por contra no incluya un índice de etiquetas. Esta tarde me he [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://sumolari.com/wp-content/uploads/2011/06/Captura-de-pantalla-2011-06-17-a-las-22.21.06.png" rel="lightbox-4993"><img class="alignleft size-thumbnail wp-image-5007 leftimage" title="Lista de temas de un foro bbPress como Widget de WordPress" src="http://sumolari.com/wp-content/uploads/2011/06/Captura-de-pantalla-2011-06-17-a-las-22.21.06-230x130.png" alt="Lista de temas de un foro bbPress como Widget de WordPress" width="230" height="130" /></a>Una de las características que sorprendentemente no incluye <a href="http://sumolari.com/tag/bbpress/">bbPress</a> 2.0 es un Widget para <a href="http://sumolari.com/category/wordpress/">WordPress</a> que muestre las etiquetas de los temas del foro. Es curioso que incluya un Widget que sólo muestre un enlace a la lista de mensajes sin responder y por contra no incluya un índice de etiquetas.</p>
<p>Esta tarde me he tomado la molestia de crear yo uno y quiero compartirlo con todo aquel al que le parezca interesante. Básicamente se copia el siguiente código en el archivo <em>functions.php</em> de nuestro theme de <a href="../category/wordpress/">WordPress</a> o en un archivo <em>.php</em> en la carpeta de plugins de <a href="../category/wordpress/">WordPress</a>.</p>
<pre class="brush: php; title: ; notranslate">
class bbPress_Widget_Tag_Cloud extends WP_Widget {

		function bbPress_Widget_Tag_Cloud() {
			$widget_ops = array( 'description' =&gt; __( &quot;Your most used tags in cloud format&quot;) );
			$this-&gt;WP_Widget('bbpress_tag_cloud', __('bbPress Tag Cloud'), $widget_ops);
		}

		function widget( $args, $instance ) {
			extract($args);
			$current_taxonomy = $this-&gt;_get_current_taxonomy($instance);
			if ( !empty($instance['title']) ) {
				$title = $instance['title'];
			} else {
				if ( 'post_tag' == $current_taxonomy ) {
					$title = __('Tags');
				} else {
					$tax = get_taxonomy($current_taxonomy);
					$title = $tax-&gt;labels-&gt;name;
				}
			}
			$title = apply_filters('widget_title', $title, $instance, $this-&gt;id_base);

			echo $before_widget;
			if ( $title )
				echo $before_title . $title . $after_title;
			echo '
&lt;div class=&quot;tagcloud&quot;&gt;';
			wp_tag_cloud( apply_filters('widget_tag_cloud_args', array('taxonomy' =&gt; $current_taxonomy) ) );
			echo &quot;&lt;/div&gt;
\n&quot;;
			echo $after_widget;
		}

		function update( $new_instance, $old_instance ) {
			$instance['title'] = strip_tags(stripslashes($new_instance['title']));
			$instance['taxonomy'] = stripslashes($new_instance['taxonomy']);
			return $instance;
		}

		function form( $instance ) {

			global $bbp;

			$current_taxonomy = $this-&gt;_get_current_taxonomy($instance);
	?&gt;

&lt;label for=&quot;&lt;?php echo $this-&gt;get_field_id('title'); ?&gt;&quot;&gt;&lt;!--?php _e('Title:') ?--&gt;&lt;/label&gt;
		&lt;input id=&quot;&lt;?php echo $this-&gt;get_field_id('title'); ?&gt;&quot; class=&quot;widefat&quot; name=&quot;&lt;?php echo $this-&gt;get_field_name('title'); ?&gt;&quot; type=&quot;text&quot; value=&quot;&lt;?php if (isset ( $instance['title'])) {echo esc_attr( $instance['title'] );} ?&gt;&quot; /&gt;

&lt;label for=&quot;&lt;?php echo $this-&gt;get_field_id('taxonomy'); ?&gt;&quot;&gt;&lt;!--?php _e('Taxonomy:') ?--&gt;&lt;/label&gt;
&lt;select id=&quot;&lt;?php echo $this-&gt;get_field_id('taxonomy'); ?&gt;&quot; class=&quot;widefat&quot; name=&quot;&lt;?php echo $this-&gt;get_field_name('taxonomy'); ?&gt;&quot;&gt;		&lt;!--?php foreach ( get_object_taxonomies($bbp---&gt;forum_post_type) as $taxonomy ) :					$tax = get_taxonomy($taxonomy);					if ( !$tax-&gt;show_tagcloud || empty($tax-&gt;labels-&gt;name) )						continue;		?&gt;			&lt;option value=&quot;&lt;?php echo esc_attr($taxonomy) ?&gt;&quot;&gt;&gt;&lt;!--?php echo $tax---&gt;labels-&gt;name; ?&gt;&lt;/option&gt;		&lt;!--?php endforeach; ?--&gt;		&lt;!--?php foreach ( get_object_taxonomies($bbp---&gt;topic_post_type) as $taxonomy ) :					$tax = get_taxonomy($taxonomy);					if ( !$tax-&gt;show_tagcloud || empty($tax-&gt;labels-&gt;name) )						continue;		?&gt;			&lt;option value=&quot;&lt;?php echo esc_attr($taxonomy) ?&gt;&quot;&gt;&gt;&lt;!--?php echo $tax---&gt;labels-&gt;name; ?&gt;&lt;/option&gt;		&lt;!--?php endforeach; ?--&gt;		&lt;!--?php foreach ( get_object_taxonomies($bbp---&gt;reply_post_type) as $taxonomy ) :					$tax = get_taxonomy($taxonomy);					if ( !$tax-&gt;show_tagcloud || empty($tax-&gt;labels-&gt;name) )						continue;		?&gt;			&lt;option value=&quot;&lt;?php echo esc_attr($taxonomy) ?&gt;&quot;&gt;&gt;&lt;!--?php echo $tax---&gt;labels-&gt;name; ?&gt;&lt;/option&gt;		&lt;!--?php endforeach; ?--&gt;&lt;/select&gt;
&lt;!--?php&lt;br /--&gt;		}

		function _get_current_taxonomy($instance) {
			if ( !empty($instance['taxonomy']) &amp;&amp; taxonomy_exists($instance['taxonomy']) )
				return $instance['taxonomy'];

			return 'post_tag';
		}
	}

register_widget('bbPress_Widget_Tag_Cloud');
</pre>
<p>¿Cómo funciona? Pues lo que he hecho ha sido copiar el código del Widget de nube de etiquetas que viene por defecto en <a href="../category/wordpress/">WordPress</a> (sobre la línea 986 del archivo<em> wp-includes/default-widgets.php</em>) y modificarlo para que en la lista de posibles taxonomías a mostrar muestre todas las taxonomías que pertenezcan a alguno de los <em>post_type</em> que añade <a href="../tag/bbpress/">bbPress</a> 2.0.</p>
<p>Lamentablemente hay un pequeño problema en esto y es que aparecerán también las etiquetas que se aplican a temas publicados en foros privados, comprometiendo la privacidad de dichos foros. La solución me ha costado bastante más de encontrar, pero la tenéis a continuación. Se trata básicamente de aplicar un filtro al Widget, que añade a la lista de etiquetas a excluir cualquier etiqueta que haya sido asignada a un tema de un foro privado. De nuevo, se puede añadir en el archivo <em>functions.php</em> de nuestro theme o en un archivo aparte en <em>wp-content/plugins</em>.</p>
<pre class="brush: php; title: ; notranslate">
function parchear_bug_tag_cloud($content)
	{

		global $bbp;

		$private_forums = bbp_get_private_forum_ids();

		if (bbp_user_can_view_forum(array('forum_id' =&gt; $private_forums[1])))
		{
			return $content;
		}

		$tags_to_remove = array();
		foreach ($private_forums as $pf_id =&gt; $pf_forum)
		{

			if ($pf_forum == '') { continue; }

			$temp_query = new WP_Query(array('suppress_filters' =&gt; true, 'post_type' =&gt; $bbp-&gt;topic_post_type, 'meta_query' =&gt; array(array('key' =&gt; '_bbp_forum_id', 'value' =&gt; $pf_forum, 'compare' =&gt; '='))));

			while ( $temp_query-&gt;have_posts() ) : $temp_query-&gt;the_post();

				$tags = wp_get_object_terms(get_the_ID(), $bbp-&gt;topic_tag_id);

				foreach ($tags as $t_key =&gt; $t_value)
				{
					$tags_to_remove[] = $t_value-&gt;term_id;
				}

			endwhile;

			wp_reset_postdata();

		}

		$content['exclude'] = $tags_to_remove;

		return $content;
	}

	add_filter('widget_tag_cloud_args', 'parchear_bug_tag_cloud');
</pre>
<p>¿Cómo funciona? Primero se obtienen los foros privados y se comprueba que el usuario no puede verlos. A continuación se recorren todos los temas de todos los foros privados (sí, se que no está demasiado optimizado, pero no he encontrado una forma mejor de hacerlo) y se añaden todas sus etiquetas a la lista de etiquetas a excluir. Por último se devuelven los nuevos parámetros del Widget.</p>
<p>La lástima es que hay un segundo bug, y es que si un usuario accede a la URL de una etiqueta que está asignada a un tema publicado en un foro privado, el usuario puede ver la lista de temas que tienen asignada dicha etiqueta, y entre esos temas, aparecerá también el tema que debería estar oculto al ser publicado en un foro privado.</p>
<p>De nuevo para solucionar esto podemos recurrir a los filtros de <a href="../tag/bbpress/">bbPress</a> y <a href="../category/wordpress/">WordPress</a>, en concreto arreglar el error se logra con el siguiente código:</p>
<pre class="brush: php; title: ; notranslate">
function parchear_bug_foros_privados($content)
	{
		global $bbp;

		$private_forums = bbp_get_private_forum_ids();

		if (bbp_user_can_view_forum(array('forum_id' =&gt; $private_forums[1])))
		{
			return $bbp-&gt;topic_query-&gt;post_count;
		}

		$topics_to_remove = array();
		foreach ($bbp-&gt;topic_query-&gt;posts as $key =&gt; $post)
		{
			if (in_array(get_post_meta($post-&gt;ID, '_bbp_forum_id', true), $private_forums))
			{
				$topics_to_remove[] = $key;
			}
		}

		foreach ($topics_to_remove as $key =&gt; $topic_to_remove)
		{
			unset($bbp-&gt;topic_query-&gt;posts[$topic_to_remove]);
		}

		$bbp-&gt;topic_query-&gt;post_count = count($bbp-&gt;topic_query-&gt;posts);

		$bbp-&gt;topic_query-&gt;post = reset($bbp-&gt;topic_query-&gt;posts);

		return $bbp-&gt;topic_query-&gt;post_count;

	}

	add_filter('bbp_has_topics', 'parchear_bug_foros_privados');
</pre>
<p>Esto tiene un efecto secundario: a partir del momento de aplicar estos dos parches, cualquier tema que tenga asignada una etiqueta que esté a su vez asignada a un tema publicado en un foro privado, será invisible para los usuarios que no tengan permiso para ver dicho foro, es decir, se volverá tan privado como los temas publicados en un foro privado. Este efecto desaparece al eliminar el código de ambos parches, sin embargo si no usamos estas funciones, queda a la vista de cualquier usuario (incluso los no registrados) la lista de temas privados.</p>
<p>Sencillo y limpio, pues si queremos eliminar este parche o el Widget basta con borrar el código anterior. Además, en caso de que este error no se arreglara en futuras versiones, el parche y el Widget seguirán disponibles tras actualizar <a href="../tag/bbpress/">bbPress</a>, manteniendo la sencillez característica de <a href="../category/wordpress/">WordPress</a>.</p>
<p>De todos modos, espero que en la versión final de <a href="../tag/bbpress/">bbPress</a> 2.0 se incluya un Widget que reemplace al mío, y que los fallos sean arreglados.</p>
]]></content:encoded>
			<wfw:commentRss>http://sumolari.com/muestra-un-widget-con-tags-de-bbpress-en-wordpress/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Aplica los filtros de WordPress a bbPress 2.0</title>
		<link>http://sumolari.com/aplica-los-filtros-de-wordpress-a-bbpress-2-0/</link>
		<comments>http://sumolari.com/aplica-los-filtros-de-wordpress-a-bbpress-2-0/#comments</comments>
		<pubDate>Fri, 17 Jun 2011 13:50:03 +0000</pubDate>
		<dc:creator>Sumolari</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[bbPress]]></category>

		<guid isPermaLink="false">http://sumolari.com/?p=4982</guid>
		<description><![CDATA[bbPress no se caracteriza por ser uno de los sistemas de foros más completos, de hecho no es posible utilizar etiquetas tan comunes en otros foros como la de coloreado de código o la posibilidad de añadir un vídeo con tan sólo usar la etiqueta [youtube]. Sin embargo, al ser un plugin de WordPress, podemos [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: center;"><a href="http://sumolari.com/wp-content/uploads/2011/06/Captura-de-pantalla-2011-06-17-a-las-15.42.45.png" rel="lightbox-4982"><img class="size-large wp-image-4985 aligncenter" style="border: 1px solid #CCC;" title="Coloreado de sintaxis en bbPress" src="http://sumolari.com/wp-content/uploads/2011/06/Captura-de-pantalla-2011-06-17-a-las-15.42.45-848x343.png" alt="Coloreado de sintaxis en bbPress" width="848" height="343" /></a></p>
<p><a href="http://sumolari.com/tag/bbpress/">bbPress</a> no se caracteriza por ser uno de los sistemas de foros más completos, de hecho no es posible utilizar etiquetas tan comunes en otros foros como la de coloreado de código o la posibilidad de añadir un vídeo con tan sólo usar la etiqueta [<em></em>youtube]. Sin embargo, al ser un plugin de <a href="http://sumolari.com/category/wordpress/">WordPress</a>, podemos extender las características de <a href="../tag/bbpress/">bbPress</a> aprovechándonos de las de <a href="../category/wordpress/">WordPress</a>. ¿De qué estoy hablando? De aplicar los mismos filtros que aplica <a href="../category/wordpress/">WordPress</a> al contenido de los artículos a los mensajes del foro, haciendo que cada característica que añadamos a <a href="../category/wordpress/">WordPress</a> a través de plugins también esté disponible al instante en el foro.</p>
<p>Aplicar estos cambios es muy sencillo. Podemos crear un nuevo plugin o modificar el archivo <em>functions.php</em> de nuestro theme de <a href="../category/wordpress/">WordPress</a>. En primer lugar definiremos una función que devuelva el contenido que se le pasa como parámetro tras aplicarle los filtros que aplica <a href="../category/wordpress/">WordPress</a>. A continuación añadiremos esta función a los filtros que aplica <a href="../tag/bbpress/">bbPress</a> al contenido de los mensajes. Aquí va el código en cuestión.</p>
<pre class="brush: php; title: ; notranslate">
function aplicar_filtros($content)
{

	global $bbp;

	$author_id = $bbp-&gt;reply_query-&gt;posts[$bbp-&gt;reply_query-&gt;current_post]-&gt;post_author;
	$author_info = get_userdata($author_id);

	if ($author_info-&gt;wp_capabilities['administrator'] == 1)
	{
		return apply_filters('the_content', $content);
	}

	return apply_filters('comment_text', $content);
}

add_filter('bbp_get_reply_content', 'aplicar_filtros');
</pre>
<p>¿Cómo funciona esta función? En primer lugar obtenemos la variable <em>$bbp</em>, que contiene, entre otras cosas, la información relativa al mensaje que estamos mostrando. A continuación obtenemos la ID del usuario que ha publicado el mensaje, y con ésta, la información del usuario. Tras esto comprobamos que el autor del artículo tiene permisos de administrador. Si es así, el usuario puede utilizar cualquier filtro aplicado a los artículos del blog (es decir, cualquier filtro añadido a <em>the_content</em>); si por el contrario el autor no es un administrador, le dejaremos usar cualquier filtro que se pueda usar en los comentarios (es decir, que se añade a <em>comment_text</em>).</p>
<p>Por último añadimos la nueva función al filtro <em>bbp_get_reply_content</em> y ¡voilà! Ya tenemos nuevas características soportadas en nuestro foro. Ahora si queremos, por ejemplo, permitir el coloreado de código, basta con instalar un plugin como <a href="http://wordpress.org/extend/plugins/syntaxhighlighter/">SyntaxHighlighter Evolved</a> y activarlo desde el Panel de Administración de WordPress. También podremos usar otras características de WordPress, como embeber vídeos usando los shortcodes [<em></em>video] o [<em></em>youtube].</p>
<p>Del mismo modo, por ejemplo, se podrían añadir carruseles creados con <em>WP Carousel 1.0</em> con utilizar el shortcode [<em></em>wp_carousel].</p>
<p>Por medidas de seguridad, tan sólo los administradores gozarán de todos los filtros, ya que es posible que algún plugin añada un filtro a <em>the_content</em> que no queremos que los demás usuarios puedan usar públicamente, como por ejemplo añadir formularios de contacto o mostrar carruseles.</p>
]]></content:encoded>
			<wfw:commentRss>http://sumolari.com/aplica-los-filtros-de-wordpress-a-bbpress-2-0/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Introducción a Objective-C: El paradigma de la POO</title>
		<link>http://sumolari.com/introduccion-a-objective-c-el-paradigma-de-la-poo/</link>
		<comments>http://sumolari.com/introduccion-a-objective-c-el-paradigma-de-la-poo/#comments</comments>
		<pubDate>Fri, 07 Jan 2011 08:02:24 +0000</pubDate>
		<dc:creator>Sumolari</dc:creator>
				<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Introducción a Objective-C]]></category>
		<category><![CDATA[iPad]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[iPod Touch]]></category>
		<category><![CDATA[POO]]></category>
		<category><![CDATA[xcode]]></category>

		<guid isPermaLink="false">http://sumolari.com/?p=4655</guid>
		<description><![CDATA[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 [...]]]></description>
			<content:encoded><![CDATA[<p>Siguiendo con los tutoriales de <a href="../category/objective-c/">Objective-C</a>, voy a explicar el paradigma de la <a href="http://sumolari.com/tag/poo/">Programación Orientada a Objetos</a>. En la POO de <a href="../category/objective-c/">Objective-C</a> hay 5 conceptos clave:</p>
<ul>
<li><strong>Objeto:</strong> 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.</li>
<li><strong>Clases: </strong>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 <a href="../category/objective-c/">Objective-C</a> 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 <em>NSObject</em>, al menos a nuestro nivel), cuando esto sucede, la nueva clase responde a todos los métodos a los que respondía la clase &#8220;padre&#8221; y los objetos de esta clase también tienen las variables de instancia de la clase &#8220;padre&#8221;.</li>
<li><strong>Variables de instancia:</strong> 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 <em>rueda</em> y accedemos a la variable <em>presiónDeLaRueda</em>, cada uno devolverá un valor diferente de presión.</li>
<li><strong>Métodos de instancia:</strong> 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 <em>encenderMotor</em>, al que se accedería desde un objeto determinado.</li>
<li><strong>Métodos de clase:</strong> 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 <em>alloc</em>, al que sólo se puede acceder desde una case, nunca desde un objeto.</li>
</ul>
<p>Puede que no os hayan quedado claros del todo los conceptos con esta introducción, los explicaré mejor un poco más adelante.</p>
<div id="attachment_4666" class="wp-caption alignleft" style="width: 240px"><a href="http://sumolari.com/wp-content/uploads/2011/01/NuevaClase.png" rel="lightbox-4655"><img class="size-thumbnail wp-image-4666" title="Creando una nueva clase" src="http://sumolari.com/wp-content/uploads/2011/01/NuevaClase-230x130.png" alt="Creando una nueva clase" width="230" height="130" /></a><p class="wp-caption-text">Creando una nueva clase</p></div>
<div id="attachment_4667" class="wp-caption alignright" style="width: 240px"><a href="http://sumolari.com/wp-content/uploads/2011/01/NuevaClasePaso2.png" rel="lightbox-4655"><img class="size-thumbnail wp-image-4667" title="Creando una nueva clase - Paso 2" src="http://sumolari.com/wp-content/uploads/2011/01/NuevaClasePaso2-230x130.png" alt="Creando una nueva clase - Paso 2" width="230" height="130" /></a><p class="wp-caption-text">Creando una nueva clase - Paso 2</p></div>
<p>En <a href="../category/objective-c/">Objective-C</a> las clases se definen mediante dos archivos: <em>NOMBRECLASE.h</em> y <em>NOMBRECLASE.m</em>. 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.</p>
<p>Para añadir un nuevo archivo a nuestro proyecto basta con ir al menú <em>File » New file&#8230;</em> o pulsar <em>Comando</em> + <em>N</em>. En la ventana que nos aparecerá seleccionaremos <em>Mac OS X » Cocoa Class » Objective-C Class (Subclass of NSObject)</em>. En  <em>File Name</em> introduciremos el nombre de nuestra nueva clase, en este caso <em>Coche</em>, acabado en .m. También marcaremos la casilla <em>Also create &#8220;Coche.h&#8221;</em>, para mantener más limpio el código.</p>
<p>En el archivo <em>Coche.h</em> encontraremos el siguiente código:</p>
<pre class="brush: objc; title: ; notranslate">

#import &lt;Cocoa/Cocoa.h&gt;

@interface Coche : NSObject {

}

@end
</pre>
<p>La primera línea ya la vimos en <a href="http://sumolari.com/?p=4633">la primera parte de los tutoriales</a>, e importa el Framework <a href="http://sumolari.com/tag/cocoa/">Cocoa</a>. En la siguiente línea comienza la interfaz de la clase. Veamos su sintaxis:</p>
<ul>
<li><strong>@interface</strong>: Inicia la interfaz</li>
<li><strong>Coche</strong>: El nombre de la clase que estamos definiendo</li>
<li><strong>: </strong>: Separado entre el nombre de la clase y la clase de la que hereda.</li>
<li><strong>NSObject</strong>: La clase de la que hereda nuestra clase.</li>
<li><strong>{</strong> : Abre el bloque donde se definen las variables de instancia.</li>
<li><strong>}</strong> : Cierra este bloque.</li>
<li><strong>@end</strong>: Indica el fin de la implementación.</li>
</ul>
<p>Como podéis ver, las clases pueden ser &#8220;hijas&#8221; de otras clases, y es algo realmente común. De hecho es muy conveniente que nuestras clases sean hijas de al menos <em>NSObject</em>. La clase <em>NSObject</em> es la clase básica e incluye las funciones esenciales de gestión de memoria (la veremos más tarde), entre otras cosas.</p>
<p>Si nuestra clase es hija de una clase que es hija de <em>NSObject</em>, esta nueva clase también tendrá acceso a los métodos de la clase <em>NSObject</em>.</p>
<p>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: <em>color</em> y <em>numPuertas</em>. La primera, color, será un objeto de clase <em>NSString</em> (cadena de texto). La segunda, <em>numPuertas</em>, será una variable de tipo <em>NSUInteger</em> (a nuestro nivel, equivalente a un <em>unsigned</em> <em>int</em> de C, o en palabras llanas, un número entero sin signo).</p>
<pre class="brush: objc; title: ; notranslate">
#import &lt;Cocoa/Cocoa.h&gt;

@interface Coche : NSObject {
 NSString    *color;
 NSUInteger    numPuertas;
}

@end
</pre>
<p>Fijáos en la sintaxis para definir varibles de instancia:</p>
<pre class="brush: objc; title: ; notranslate">

NOMBRE_DE_LA_CLASE_DEL_OBJETO *NOMBRE_DEL_OBJETO;
NOMBRE_DEL_TIPO_DE_VARIABLE NOMBRE_DE_LA_VARIABLE;
</pre>
<p>Al defnir un objeto <strong>siempre</strong> antepondremos un asterisco (&#8220;*&#8221;) al nombre del objeto.</p>
<p>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 (&#8220;}&#8221;) y el <em>@end</em>. Creemos dos métodos de instancia: <em>getColor</em> y <em>getNumPuertas</em>. Creemos otro más llamado <em>imprimirDetalles</em> que muestre en la consola los valores devueltos por <em>getColor</em> y <em>getNumPuertas</em>.</p>
<pre class="brush: objc; title: ; notranslate">

#import &lt;Cocoa/Cocoa.h&gt;

@interface Coche : NSObject {
 NSString    *color;
 NSUInteger    numPuertas;
}

- (NSString *)getColor;
- (NSUInteger)getNumPuertas;
- (void)imprimirDetalles;

@end
</pre>
<p>Fijáos de nuevo en la sintaxis:</p>
<pre class="brush: objc; title: ; notranslate">

- (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;
</pre>
<p>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 <em>void</em> para indicárselo al compilador.</p>
<p>El guión (&#8220;-&#8221;) 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 +.</p>
<p>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 <em>setColor</em> y <em>setNumPuertas</em> que acepten un parámetro que será el nuevo valor.</p>
<pre class="brush: objc; title: ; notranslate">
#import &lt;Cocoa/Cocoa.h&gt;

@interface Coche : NSObject {
 NSString    *color;
 NSUInteger    numPuertas;
}

- (NSString *)getColor;
- (NSUInteger)getNumPuertas;
- (void)imprimirDetalles;

- (void)setColor: (NSString *)nuevoColor;
- (void)setNumPuertas: (NSUInteger)nuevoNumPuertas;

@end
</pre>
<p>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 <em>void</em>. Los nombres están claros, pero al final de estos hay dos puntos (&#8220;:&#8221;). 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.</p>
<pre class="brush: objc; title: ; notranslate">

- (void)miFuncion;
- (void)miFuncionConUnParametro: (NSUInteger)miParametro;
- (NSString *)miFuncionConUnParametro: (NSUInteger)miParametro queAdemasDevuelveUnaCadenaDeTextoYRequiereOtroParametro: (NSUInteger)elSegundo;
</pre>
<p>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í:</p>
<pre class="brush: objc; title: ; notranslate">

miFuncion
miFuncionConUnParametro:
miFuncionConUnParametro:queAdemasDevuelveUnaCadenaDeTextoYRequiereOtroParametro:
</pre>
<p>De este modo no son iguales los nombres a pesar de ser bastante parecidos (al menos en principio).</p>
<p>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 <em>Coche.m</em> y comencemos a implementarlas. En el archivo .m veremos el siguiente código:</p>
<pre class="brush: objc; title: ; notranslate">

#import &quot;Coche.h&quot;

@implementation Coche

@end
</pre>
<p>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 <em>@implementation Coche</em> y <em>@end</em> es donde escribiremos nuestras funciones.</p>
<p>Antes de implementar nuestras funciones, añadid el siguiente código después de <em>@implementation Coche</em>. 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.</p>
<pre class="brush: objc; title: ; notranslate">

- (void)dealloc
{
 [color release];

 [super dealloc];
}
</pre>
<p>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:</p>
<pre class="brush: objc; title: ; notranslate">

- (TIPO_DE_VALOR_QUE_SE_DEVUELVE)NOMBRE_DE_LA_FUNCION
{

// Código de la función

}
</pre>
<p>¿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<em> [super NOMBRE_DE_LA_FUNCION]; </em>en el lugar en el que queramos que se ejecute.</p>
<pre class="brush: objc; title: ; notranslate">

- (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];

}
</pre>
<p>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:</p>
<pre class="brush: objc; title: ; notranslate">

#import &quot;Coche.h&quot;

@implementation Coche

- (void)dealloc
{
 [color release];

 [super dealloc];
}

- (NSString *)getColor
{
}

- (NSUInteger)getNumPuertas
{
}

- (void)imprimirDetalles
{
}

- (void)setColor: (NSString *)colorNuevo
{
}

- (void)setNumPuertas: (NSUInteger)nuevoNumeroDePuertas
{
}

@end
</pre>
<p>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.</p>
<p>La función <em>getColor</em> y <em>getNumPuertas </em>tan sólo devuelven el valor de las variables correspondientes, así que añadiremos <em>return VARIABLE; </em>para que el método devuelva el valor de la variable. <em>return </em>no requiere asterisco si se devuelven objetos, se usa exactamente igual con objetos que con variables sencillas.</p>
<p>En la función <em>imprimirDetalles</em> utilizaremos la función <em>NSLog</em> para imprimir en la consola los valores de las variables. La función <em>NSLog</em> admite varios parámetros. El primero siempre es una cadena de texto (<em>@&#8221;"</em>), pero esta cadena admite combinaciones de caracteres específicas que indican que se deben reemplazar por otro valor. Así un <em>%d </em>se reemplazará por un número entero, un <em>%f</em> por un número decimal y un <em>%@</em> 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 (&#8220;,&#8221;) debemos introducir las variables o los objetos que reemplazarán las combinaciones. A continuación tenéis las tres funciones que hemos explicado:</p>
<pre class="brush: objc; title: ; notranslate">

- (NSString *)getColor
{
 return color;
}

- (NSUInteger)getNumPuertas
{
 return numPuertas;
}

- (void)imprimirDetalles
{
 NSLog(@&quot;Este coche es de color %@ y tiene %d puertas&quot;, [self getColor], [self getNumPuertas]);
}
</pre>
<p>Fijáos en la última función, concretamente en <em>[self getColor]</em> y <em>[self getNumPuertas]</em>. 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 <em>[self funcion]</em> le pedimos al objeto <em>self</em> que ejecute el método <em>funcion</em>. El objeto <em>self</em> 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 <em>Coche</em> que ejecuta el método <em>imprimirDetalles</em> que ejecute el método <em>getColor </em>y <em>getNumPuertas</em>.</p>
<p>Las funciones <em>setColor</em> y <em>setNumPuertas</em> son bastante sencillas. Simplemente asignaremos (mediante &#8220;=&#8221;) el valor que se pasa como parámetro (o argumento) a la variable correspondiente. Aquí los tenéis completos:</p>
<pre class="brush: objc; title: ; notranslate">

- (void)setColor: (NSString *)colorNuevo
{
 color = colorNuevo;
}

- (void)setNumPuertas: (NSUInteger)nuevoNumeroDePuertas
{
 numPuertas = nuevoNumeroDePuertas;
}
</pre>
<p>Y este es el aspecto final de la implementación de nuestra clase <em>Coche</em>:</p>
<pre class="brush: objc; title: ; notranslate">

#import &quot;Coche.h&quot;

@implementation Coche

- (void)dealloc
{
 [color release];

 [super dealloc];
}

- (NSString *)getColor
{
 return color;
}

- (NSUInteger)getNumPuertas
{
 return numPuertas;
}

- (void)imprimirDetalles
{
 NSLog(@&quot;Este coche es de color %@ y tiene %d puertas&quot;, [self getColor], [self getNumPuertas]);
}

- (void)setColor: (NSString *)colorNuevo
{
 color = colorNuevo;
}

- (void)setNumPuertas: (NSUInteger)nuevoNumeroDePuertas
{
 numPuertas = nuevoNumeroDePuertas;
}

@end
</pre>
<p>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.</p>
<p>Vamos al archivo <em>NOMBREPROYECTO.m</em>, que debería tener el siguiente código:</p>
<pre class="brush: objc; title: ; notranslate">

#import &lt;Foundation/Foundation.h&gt;

int main (int argc, const char * argv[]) {
 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

 // insert code here...
 NSLog(@&quot;Hello, World!&quot;);
 [pool drain];
 return 0;
}
</pre>
<p>E importamos el archivo <em>Coche.h</em> justo después de importarse Foundation:</p>
<pre class="brush: objc; title: ; notranslate">#import &quot;Coche.h&quot;</pre>
<p>A continuación añadimos, entre <em>NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; </em>y <em>[pool drain];</em>:</p>
<pre class="brush: objc; title: ; notranslate">

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

 [miCoche setColor:@&quot;Azul&quot;];
 [miCoche setNumPuertas:5];

 [miCoche imprimirDetalles];

 [miCoche release];
</pre>
<p>Vayamos línea a línea:</p>
<pre class="brush: objc; title: ; notranslate">Coche *miCoche = [[Coche alloc] init];</pre>
<p>En esta línea creamos el objeto <em>miCoche</em>, de clase <em>Coche</em>. Fijáos como se le envía a  la clase <em>Coche</em> el mensaje <em>alloc</em> y al objeto resultante de ese mensaje se le envía el mensaje <em>init</em>. 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.</p>
<pre class="brush: objc; title: ; notranslate">
[miCoche setColor:@&quot;Azul&quot;];
[miCoche setNumPuertas:5];
</pre>
<p>En estas dos líneas se envía el método <em>setColor:</em> y <em>setNumPuertas:</em> al objeto <em>miCoche</em>, con el parámetro <em>@&#8221;Azul&#8221;</em> como nuevo color y <em>5</em> como número de puertas.</p>
<pre class="brush: objc; title: ; notranslate">
[miCoche imprimirDetalles];
</pre>
<p>En esta línea se le manda al objeto el mensaje <em>imprimirDetalles</em>, lo que hará que muestre por terminal los valores de las variables.</p>
<pre class="brush: objc; title: ; notranslate">
 [miCoche release];
</pre>
<p>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.</p>
<p>El código resultante de<em> MIPROYECTO.m</em> será:</p>
<pre class="brush: objc; title: ; notranslate">

#import &lt;Foundation/Foundation.h&gt;
#import &quot;Coche.h&quot;

int main (int argc, const char * argv[]) {
 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

 // insert code here...
 NSLog(@&quot;Hello, World!&quot;);

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

 [miCoche setColor:@&quot;Azul&quot;];
 [miCoche setNumPuertas:5];

 [miCoche imprimirDetalles];

 [miCoche release];

 [pool drain];
 return 0;
}
</pre>
<p>Y si compilamos y ejecutamos la aplicación veremos el siguiente resultado:</p>
<p><a href="http://sumolari.com/wp-content/uploads/2011/01/Resultado.png" rel="lightbox-4655"><img class="aligncenter size-full wp-image-4668" title="Resultado de la segunda aplicación" src="http://sumolari.com/wp-content/uploads/2011/01/Resultado.png" alt="Resultado de la segunda aplicación" width="797" height="483" /></a></p>
<p>Esto no está mal, pero, ¿para qué llamar a dos métodos para establecer las variables y otro más para iniciar el objeto (<em>init</em>)? ¿No podríamos juntar esos tres métodos en uno? Sí, podemos. Vayamos al archivo <em>Coche.h</em> y añadamos el siguiente método:</p>
<pre class="brush: objc; title: ; notranslate">- (Coche *)initWithColor: (NSString *)nuevoColor andNumPuertas: (NSUInteger)nuevoNumPuertas;</pre>
<p>Quedando así la interfaz:</p>
<pre class="brush: objc; title: ; notranslate">

#import &lt;Cocoa/Cocoa.h&gt;

@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
</pre>
<p>En la implementación añadiremos lo siguiente:</p>
<pre class="brush: objc; title: ; notranslate">

- (Coche *)initWithColor: (NSString *)nuevoColor andNumPuertas: (NSUInteger)nuevoNumPuertas
{
 if (self = [super init])
 {
 [self setColor:nuevoColor];
 [self setNumPuertas:nuevoNumPuertas];
 }
 return self;
}
</pre>
<p>Analicemos este código. La primera línea de la función, <em>if (self = [super init])</em> 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 <em>self</em>. Como podéis ver, esta función devuelve un objeto de clase <em>Coche</em>.</p>
<p>El código final de nuestra implementación será:</p>
<pre class="brush: objc; title: ; notranslate">

#import &quot;Coche.h&quot;

@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(@&quot;Este coche es de color %@ y tiene %d puertas&quot;, [self getColor], [self getNumPuertas]);
}

- (void)setColor: (NSString *)colorNuevo
{
 color = colorNuevo;
}

- (void)setNumPuertas: (NSUInteger)nuevoNumeroDePuertas
{
 numPuertas = nuevoNumeroDePuertas;
}

@end
</pre>
<p>¿Cómo aplicamos estos cambios a nuestra aplicación? Vayamos al archivo <em>NOMBREPROYECTO.m</em> y reemplacemos el siguiente código:</p>
<pre class="brush: objc; title: ; notranslate">

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

 [miCoche setColor:@&quot;Azul&quot;];
 [miCoche setNumPuertas:5];
</pre>
<p>Por este otro:</p>
<pre class="brush: objc; title: ; notranslate">Coche *miCoche = [[Coche alloc] initWithColor:@&quot;Azul&quot; andNumPuertas:5];</pre>
<p>Como veis, hemos convertido tres líneas de código en sólo una, y el resultado es idéntico.</p>
<p>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 <a href="../category/objective-c/">Objective-C</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://sumolari.com/introduccion-a-objective-c-el-paradigma-de-la-poo/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Introducción a Objective-C: Nuestra primera aplicación</title>
		<link>http://sumolari.com/introduccion-a-objective-c-nuestra-primera-aplicacion/</link>
		<comments>http://sumolari.com/introduccion-a-objective-c-nuestra-primera-aplicacion/#comments</comments>
		<pubDate>Sat, 01 Jan 2011 18:46:06 +0000</pubDate>
		<dc:creator>Sumolari</dc:creator>
				<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Introducción a Objective-C]]></category>
		<category><![CDATA[iPad]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[iPod Touch]]></category>
		<category><![CDATA[POO]]></category>
		<category><![CDATA[xcode]]></category>

		<guid isPermaLink="false">http://sumolari.com/?p=4633</guid>
		<description><![CDATA[¿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, [...]]]></description>
			<content:encoded><![CDATA[<p>¿Qué es <a href="http://sumolari.com/category/objective-c/">Objective-C</a>? ¿Qué es <a href="http://sumolari.com/tag/cocoa/">Cocoa</a>? ¿Qué es la <a href="http://sumolari.com/tag/poo">Programacion Orientada a Objetos</a> (POO)? ¿Y la arquitectura de Modelo Vista Controlador (MVC)? Dar los primeros pasos en la programación para <a href="http://sumolari.com/category/mac-os-x/">Mac OS X</a>, <a href="http://sumolari.com/tag/iphone/">iPhone</a> y <a href="http://sumolari.com/tag/ipad">iPad</a> 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 <a href="../tag/iphone/">iPhone</a> (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 <a href="../tag/iphone/">iPhone</a> (extensible a <a href="../category/mac-os-x/">Mac OS X</a> y <a href="../tag/ipad">iPad</a>). Tampoco esperéis ser unos maestros de <a href="../category/objective-c/">Objective-C</a> 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.<span id="more-4633"></span></p>
<p>En este serie de tutoriales voy a suponer que se tienen unos conocimientos básicos de programación, que se entiende el significado de términos como &#8220;código fuente&#8221;, &#8220;función&#8221; o &#8220;variable&#8221;. Cualquiera que haya programado antes en cualquier lenguaje de programación conocerá su significado. El único término nuevo que puede que no conozcan aquellos que sólo han programado en lenguajes interpretados (como <a href="http://sumolari.com/category/php">PHP</a>) es el de &#8220;compilar&#8221;. Para simplificar, podríamos decir que compilar un programa es traducir el código que nosotros escribimos en un código que la máquina pueda entender.</p>
<p>Ahora bien, queda diferenciar cuatro conceptos:</p>
<ul>
<li><strong>Objective-C: </strong>Es el lenguaje de programación que se suele usar en <a href="../category/mac-os-x/">Mac OS X</a>. Digo se suele usar porque también se pueden programar aplicaciones en C, C++, Objective-C++, etc.</li>
<li><strong>Cocoa:</strong> Es un Framework, un conjunto de funciones que facilitan la tarea al programador. Tareas como modificar una cadena de caracteres, descargar archivos de Internet, gestionar matrices o la memoria se hacen mucho más sencillas con este Framework. De hecho programar en <a href="../category/objective-c/">Objective-C</a> sin usar <a href="../tag/cocoa/">Cocoa</a> es algo poco usual y no lo veremos en este tutorial (yo, por ejemplo, no he programado nada en <a href="../category/objective-c/">Objective-C</a> sin tener vinculado <a href="../tag/cocoa/">Cocoa</a>). Cocoa Touch es la versión de <a href="../tag/cocoa/">Cocoa</a> para <a href="../tag/iphone/">iPhone</a>, <a href="http://sumolari.com/tag/ipod-touch/">iPod Touch</a> y <a href="../tag/ipad">iPad</a>.</li>
<li><strong>Programación Orientada a Objetos: </strong>Es un paradigma de programación del que hablaremos más adelante. <a href="../category/objective-c/">Objective-C</a> es un lenguaje de Programación Orientada a Objetos. En <a href="../category/objective-c/">Objective-C</a> prácticamente todo es un objeto, cosa que veremos más adelante.</li>
<li><strong>Modelo Vista y Controlador:</strong> Es una arquitectura en la que se separa la parte lógica de la aplicación de la interfaz y de los datos que se gestionan. Realmente no es imprescindible hacer uso de esta arquitectura, pero hacerlo es una buena idea, simplifica la tarea y hace las aplicación más fáciles de extender. En nuestros primeros pasos no haremos uso de esta arquitectura, pero a medida que vayamos avanzando iremos viendo en qué consiste y qué beneficios aporta.</li>
</ul>
<p><a href="http://sumolari.com/wp-content/uploads/2010/12/Captura-de-pantalla-2010-12-31-a-las-23.07.24.png" rel="lightbox-4633"><img class="alignnone size-large wp-image-4637" title="Menú de la aplicación de Xcode" src="http://sumolari.com/wp-content/uploads/2010/12/Captura-de-pantalla-2010-12-31-a-las-23.07.24-848x14.png" alt="Menú de la aplicación de Xcode" width="848" height="14" /></a></p>
<div id="attachment_4636" class="wp-caption alignright" style="width: 240px"><a href="http://sumolari.com/wp-content/uploads/2010/12/Captura-de-pantalla-2010-12-31-a-las-23.07.17.png" rel="lightbox-4633"><img class="size-thumbnail wp-image-4636" title="Menú Archivo" src="http://sumolari.com/wp-content/uploads/2010/12/Captura-de-pantalla-2010-12-31-a-las-23.07.17-230x130.png" alt="Menú Archivo" width="230" height="130" /></a><p class="wp-caption-text">Menú Archivo</p></div>
<div id="attachment_4634" class="wp-caption alignleft" style="width: 240px"><a href="http://sumolari.com/wp-content/uploads/2010/12/Captura-de-pantalla-2010-12-31-a-las-22.59.54.png" rel="lightbox-4633"><img class="size-thumbnail wp-image-4634" title="Plantillas del proyecto de Xcode" src="http://sumolari.com/wp-content/uploads/2010/12/Captura-de-pantalla-2010-12-31-a-las-22.59.54-230x130.png" alt="Plantillas del proyecto de Xcode" width="230" height="130" /></a><p class="wp-caption-text">Plantillas del proyecto de Xcode</p></div>
<p>Dicho esto, pasemos a presentar a los sospechosos habituales. Cuando programemos en <a href="../category/mac-os-x/">Mac OS X</a> trabajeros con <a href="../tag/xcode/">Xcode</a>, el Entorno de Desarrollo Integrado de Apple. <a href="http://sumolari.com/tag/xcode/">Xcode</a> viene en los discos de instalación de <a href="../category/mac-os-x/">Mac OS X</a>, y se puede descargar de forma gratuita (previo registro) <a href="http://developer.apple.com/technologies/xcode.html">desde la web de Apple</a>. Durante estos tutoriales usaremos como plantilla del proyecto la plantilla de aplicación para la línea de comandos, ya que así evitamos tener que preocuparnos de elementos más complejos como la interfaz gráfica de la aplicación. Crear un nuevo proyecto es sencillo: Basta con ir al menú <em>File » New project&#8230;</em> . Aparecerá una ventana en la que podremos seleccionar la plantilla para el proyecto que vamos a crear. En estos tutoriales elegiremos la plantilla <em>Mac OS X » Application » Command Line Tool</em>.</p>
<p><a href="http://sumolari.com/wp-content/uploads/2010/12/Captura-de-pantalla-2010-12-31-a-las-23.00.20.png" rel="lightbox-4633"><img class="size-thumbnail wp-image-4635 alignleft leftimage" title="Nuestro primer proyecto" src="http://sumolari.com/wp-content/uploads/2010/12/Captura-de-pantalla-2010-12-31-a-las-23.00.20-230x130.png" alt="Nuestro primer proyecto" width="121" height="68" /></a> Veremos una ventana como la que tenéis en la izquierda. En la parte izquierda de la ventana tenemos acceso a los archivos del proyecto. De los archivos que se pueden ver en la imagen, el que nos interesa ahora es NOMBREPROYECTO.m. Veréis un código como el siguiente:</p>
<pre class="brush: objc; title: ; notranslate">

#import &lt;Foundation/Foundation.h&gt;

int main (int argc, const char * argv[]) {
 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

 // insert code here...
 NSLog(@&quot;Hello, World!&quot;);
 [pool drain];
 return 0;
}
</pre>
<p>Vayamos línea a línea. La primera línea importa el Framework <em>Foundation</em> en nuestra aplicación. El Framework <a href="../tag/cocoa/">Cocoa</a> está compuesto por dos Frameworks diferentes: <em>Foundation</em> y <em>Application Kit</em>. <em>Foundation</em> incluye las funciones que trabajan en la trastienda sin que el usuario lo vea, pero que al desarrollador le vienen fenomenal. Por su parte, <em>Application Kit</em> se encarga de la parte visual de la aplicación (como comprenderéis, esto es una versión resumida de lo que realmente hacen, así que tampoco lo toméis al pie de la letra). Si os fijáis en la sintaxis, podéis ver tres partes: La almohadilla (#), los signos menor y mayor que (<>) y el nombre del Framework.</p>
<p>La almohadilla introduce instrucciones para el preprocesador. Las que más comúnmente se usan con <em>#import</em> y <em>#define</em>. <em>#import</em> incluye otros archivos y Frameworks en el archivo actual. <em>#define </em>permite declarar constantes. Las constantes sirven para definir un valor que es fijo en toda la aplicación, pero que si nos interesa cambiar, podemos hacerlo modificando una sóla línea. Imaginad, por ejemplo, que queremos definir nuestra edad. Si sólo la ponemos en una línea no hay ningún problema, pero ¿y si la incluímos en 5, 10, 200 ó 5000 líneas? Es una faena tener que ir buscando cada lugar en el que hemos puesto ese valor. Con las constantes basta con poner la constante en lugar de nuestra edad, y definir el valor de la constante con el valor de nuestra edad. Cuando queramos modificar el valor de nuestra edad, sólo lo cambiaremos una vez, en lugar de tantas veces como uso se haga de ella.</p>
<p>A la hora de importar archivos, hay dos tipos de archivos que podemos importar: Frameworks del sistema y otros archivos de nuestro proyecto. Cuando importamos Frameworks del sistema, usamos los signos mayor e igual que (<>). Si importamos archivos de nuestro proyecto, usamos comillas (&#8220;).</p>
<p>La siguiente línea define la función main. La función main es la función principal de la aplicación, la única función que <strong>siempre</strong> se ejecuta. La estructura de la función es la misma estructura que C, sin embargo en <a href="../category/objective-c/">Objective-C</a> la mayoría de las funciones (métodos) se definen con una sintaxis diferente, así que no me voy a parar a explicarla.</p>
<p>Centrémonos en el siguiente bloque:</p>
<pre class="brush: objc; title: ; notranslate">
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

 // insert code here...
 NSLog(@&quot;Hello, World!&quot;);
 [pool drain];
 return 0;
</pre>
<p>En este bloque vemos unas cuantas líneas curiosas. Vayamos a la primera:</p>
<pre class="brush: objc; title: ; notranslate">
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
</pre>
<p>Esta es la sintaxis para crear un objeto en <a href="../category/objective-c/">Objective-C</a>. El primer <em>NSAutoreleasePool</em> es la clase del objeto que vamos a crear. El asterisco (&#8220;*&#8221;) indica que a continuación se presenta un objeto (lo veremos más adelante). <em>pool</em> es el nombre de la variable (objeto) que estamos creando. La segunda parte del código: <em>[[NSAutoreselasePool alloc] init]</em>, se trata de un mensaje enviado a una clase, que es a su vez el valor del objeto que estamos creando. Los mensajes se pueden enviar tanto a clases como a objetos, lo veremos más adelante, no os preocupéis.</p>
<p>A continuación vemos una línea que comienza con dos barras (//). Cuando una línea va introducida por dos barras, se trata de un comentario. Los comentarios se eliminan de la aplicación al compilarla: son sólo una ayuda al programador durante la programación, para saber qué hace cada cosa o para qué se usa una variable. Los comentarios también se pueden introducir con /* Comentario */.</p>
<pre class="brush: cpp; title: ; notranslate">

// Con dos barras el comentario ocupa toda la línea

/* Con barra y asterisco es necesario terminar el comentario con asterisco barra, así que el comentario

aún no ha acabado en esta línea,

sino que acaba en esta otra */
</pre>
<p>La siguiente línea es la llamada a una función.</p>
<pre class="brush: objc; title: ; notranslate">
NSLog(@&quot;Hello, World!&quot;);
</pre>
<p><a href="../category/objective-c/">Objective-C</a> es un superconjunto de C, con lo cual comparte algunas características con el anterior. Esta forma de llamar a la función es típica de C. Las funciones tienen dos partes: La primera (<em>NSLog</em> en este caso) es el nombre de la función. La segunda, que se encuentra entre paréntesis (&#8220;()&#8221;), son los argumentos de la función. En este caso, el argumento es: <em>@&#8221;Hello, World!&#8221;</em>. Cuando unas comillas están precedidas por un arroba (@), sabemos que se trata de una cadena de texto, un objeto de clase <em>NSString</em> (lo trataremos más adelante). Tras los paréntesis encontramos un punto y coma (;). Esto indica el final de una instrucción (todas las instrucciones en C y <a href="../category/objective-c/">Objective-C</a> van sucedidas por un punto y coma (;), a excepción de aquellas instrucciones que son argumentos de funciones (como el <em>@&#8221;Hello, World!&#8221;</em>)  o de mensajes (lo veremos más adelante).</p>
<p>La función <em>NSLog() </em>muestra el texto que se le envía como argumento en la terminal. Durante el desarrollo de la aplicaciones es una función muy útil, como veréis a medida que avancemos en los tutoriales, para saber el valor de una variable en cada momento o para recibir un aviso cuando se ejecuta un método.</p>
<pre class="brush: objc; title: ; notranslate">
[pool drain];
</pre>
<p>Esta línea le envía el mensaje <em>drain</em> al objeto <em>pool</em>, creado anteriormente. Veremos más adelante todo esto, en otro tutorial de esta serie. A continuación vemos:</p>
<pre class="brush: objc; title: ; notranslate">
return 0;
</pre>
<p>Esta línea le devuelve el valor 0 al Sistema Operativo. La función <em>main</em> tiene que devolver un valor que indica si la aplicación se ha ejecutado correctamente o si ha encontrado errores durante su ejecución. El valor 0 indica que todo ha ido bien.</p>
<div id="attachment_4643" class="wp-caption alignleft" style="width: 240px"><a href="http://sumolari.com/wp-content/uploads/2011/01/Captura-de-pantalla-2011-01-01-a-las-00.04.38.png" rel="lightbox-4633"><img class="size-thumbnail wp-image-4643" title="Nuestra primera aplicación ejecutándose" src="http://sumolari.com/wp-content/uploads/2011/01/Captura-de-pantalla-2011-01-01-a-las-00.04.38-230x130.png" alt="Nuestra primera aplicación ejecutándose" width="230" height="130" /></a><p class="wp-caption-text">Nuestra primera aplicación ejecutándose</p></div>
<p>Para probar la aplicación hay que pulsar el botón <em>Build and Run</em>, o pulsar <em>Comando</em> + <em>Enter</em>. La aplicación se compilará y se ejecutará. Como la aplicación no tiene interfaz, se ejecutará sin ver nosotros nada. Para poder ver el texto enviado por nuestra aplicación (<em>Hello, World!</em>), tenemos que mostrar la consola (Menú <em>Run » Console</em> o <em>Comando</em> + <em>Mayus</em> + <em>R</em>). Veremos algo como la imagen de la izquierda.</p>
<p>Y esto es todo por este primer tutorial. En los próximos comenzaré a tratar la Programación Orientada a Objetos en <a href="../category/objective-c/">Objective-C</a> e introduciré los conceptos de clase, objeto y método.</p>
]]></content:encoded>
			<wfw:commentRss>http://sumolari.com/introduccion-a-objective-c-nuestra-primera-aplicacion/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Comparte en Tuenti tus artículos de WordPress</title>
		<link>http://sumolari.com/comparte-en-tuenti-tus-articulos-de-wordpress/</link>
		<comments>http://sumolari.com/comparte-en-tuenti-tus-articulos-de-wordpress/#comments</comments>
		<pubDate>Tue, 24 Aug 2010 08:17:25 +0000</pubDate>
		<dc:creator>Sumolari</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[tuenti]]></category>

		<guid isPermaLink="false">http://sumolari.com/?p=4434</guid>
		<description><![CDATA[Hace algunos días Tuenti anunció un botón para compartir páginas web en la red social. La pega es que este botón no es tan automático como el de Twitter, y requiere algo más de esfuerzo añadirlo en nuestras páginas web, aunque no es para nada complicado. El botón es básicamente un enlace que contiene una [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://sumolari.com/wp-content/uploads/2010/08/botones_tuenti.png" rel="lightbox-4434"><img class="alignleft size-medium wp-image-4435 leftimage" title="Botones para compartir en Tuenti" src="http://sumolari.com/wp-content/uploads/2010/08/botones_tuenti-300x82.png" alt="Botones para compartir en Tuenti" width="300" height="82" /></a>Hace algunos días <a href="http://tuenti.com">Tuenti</a> anunció <a href="http://www.tuenti.com/#m=Developercorporatepages&amp;func=index">un botón para compartir páginas web en la red social</a>. La pega es que este botón no es tan automático como <a href="http://sumolari.com/ya-podemos-anadir-el-boton-oficial-de-twitter/">el de Twitter</a>, y requiere algo más de esfuerzo añadirlo en nuestras páginas web, aunque no es para nada complicado. El botón es básicamente un enlace que contiene una imagen, creado con el siguiente código <a href="http://sumolari.com/tag/html/">HTML</a>:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;a href=&quot;http://www.tuenti.com/share?url=[URL_DE_NUESTRO_ARTICULO]&quot; target=&quot;_blank&quot;&gt;
&lt;img src=&quot;[IMAGEN_DEL_BOTON]&quot; /&gt;
&lt;/a&gt;
</pre>
<p>La URL del enlace apunta a la página de compartir de Tuenti, donde <em>[URL_DE_NUESTRO_ARTICULO]</em> debe ser reemplazado por la URL de nuestro artículo codificada, o bien mediante la función <a href="http://sumolari.com/category/javascript/">Javascript</a> <em>encodeURIComponent()</em> o bien mediante la función <a href="http://sumolari.com/category/php/">PHP</a> <em>urlencode()</em>.</p>
<p>La imagen del botón podemos elegirla nosotros, lo recomendable es usar algunas de <a href="http://estaticos.tuenti.com/corporate/tuenti_share_kit.1.zip">las que ofrece Tuenti</a> para no confundir a los usuarios, aunque también podemos crear las nuestras. Por último, los desarrolladores de Tuenti recomiendan que el enlace se abra en una nueva ventana, aunque quizás sería mejor abrir la ventana dentro de una ventana modal en nuestro propio blog, para así evitar tener que abrir una nueva pestaña.</p>
<p>Para añadir el botón de compartir a todos nuestros artículos basta con editar el archivo single.php de nuestro theme de <a href="http://sumolari.com/category/wordpress/">WordPress</a> y añadir en el lugar que queramos mostrar el enlace:</p>
<pre class="brush: php; title: ; notranslate">
&lt;a href=&quot;http://www.tuenti.com/share?url=&lt;?php echo urlencode(get_permalink()); ?&gt;&quot; target=&quot;_blank&quot;&gt;
 &lt;img src=&quot;http://estaticosak1.tuenti.com/layout/web2-Zero/images/corporate/3_share_es_dark.59917.png&quot; /&gt;
 &lt;/a&gt;
</pre>
<p>El código simplemente muestra el enlace con el permalink del artículo cofidicado. La URL de la imagen que aparece en el código anterior es la misma que aparece en la página de desarrolladores de Tuenti, así que podéis usar esa o cambiarla por otra. No os recomiendo usar la que hay en el código de ejemplo porque tal vez la ruta a esa imagen cambien en algún tiempo y entonces os dejen de funcionar los botones de compartir.</p>
<p>También podéis añadir el botón a vuestras páginas, no sólo a los artículos, mediante el mismo código.</p>
]]></content:encoded>
			<wfw:commentRss>http://sumolari.com/comparte-en-tuenti-tus-articulos-de-wordpress/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Convierte tus PDF en ePub</title>
		<link>http://sumolari.com/convierte-tus-pdf-en-epub/</link>
		<comments>http://sumolari.com/convierte-tus-pdf-en-epub/#comments</comments>
		<pubDate>Fri, 06 Aug 2010 15:33:12 +0000</pubDate>
		<dc:creator>Sumolari</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[iPad]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[iPod Touch]]></category>
		<category><![CDATA[libros]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://sumolari.com/?p=4358</guid>
		<description><![CDATA[Parece que Apple está interesada en que sus dispositivos con iOS (iPhone, iPod y iPad) tengan acceso a iBooks, una aplicación que nos permite gestionar y leer libros. Desde la versión 1.1 podemos leer PDF desde la misma aplicación, sin embargo hay ciertas opciones que no podemos configurar al leer PDF y sí al leer [...]]]></description>
			<content:encoded><![CDATA[<p>Parece que <a href="http://sumolari.com/tag/apple/">Apple</a> está interesada en que sus dispositivos con <a href="http://sumolari.com/tag/iphone-os/">iOS</a> (<a href="http://apple.com/es/iphone/">iPhone</a>, <a href="http://www.apple.com/es/ipodtouch/">iPod</a> y <a href="http://apple.com/es/ipad/">iPad</a>) tengan acceso a <a href="http://itunes.apple.com/es/app/ibooks/id364709193?mt=8">iBooks</a>, una aplicación que nos permite gestionar y leer libros. Desde la versión 1.1 podemos leer PDF desde la misma aplicación, sin embargo hay ciertas opciones que no podemos configurar al leer PDF y sí al leer ePub, como el tamaño de la letra, lo que hace que leer, por ejemplo, el manual de usuario de iOS 4 sea realmente incómodo al tener que hacer zoom cada dos por tres.</p>
<p>Afortunadamente tenemos una alternativa: podemos convertir nuestros PDF en ePub. Hay muchas aplicaciones para hacer esto, tanto online como offline, pero en este artículo sólo me centraré en una aplicación. <a href="http://calibre-ebook.com/">Calibre</a> (así es como se llama la utilidad que nos permitirá convertir nuestros PDF en ePub) es totalmente gratutia y está disponible tanto para <a href="http://calibre-ebook.com/download_windows">Windows</a> como para <a href="http://calibre-ebook.com/download_linux">Linux</a> y <a href="http://calibre-ebook.com/download_osx">Mac OS X</a>.<span id="more-4358"></span></p>
<p><a href="http://sumolari.com/wp-content/uploads/2010/08/instalacion_paso1.png" rel="lightbox-4358"><img class="alignleft size-medium wp-image-4359" title="Instalación de Calibre - Paso 1" src="http://sumolari.com/wp-content/uploads/2010/08/instalacion_paso1-300x178.png" alt="Instalación de Calibre - Paso 1" width="300" height="178" /></a><a href="http://sumolari.com/wp-content/uploads/2010/08/instalacion_paso2.png" rel="lightbox-4358"><img class="alignright size-medium wp-image-4360" title="Instalación de Calibre - Paso 2" src="http://sumolari.com/wp-content/uploads/2010/08/instalacion_paso2-300x178.png" alt="Instalación de Calibre - Paso 2" width="300" height="178" /></a>Instalar <a href="http://calibre-ebook.com/">Calibre</a> es realmente fácil. El primer paso (imagen de la izquierda) nos dejará seleccionar el idioma de la aplicación y la carpeta en la que almacenaremos la colección de libros (no lo he comentado antes, pero <a href="http://calibre-ebook.com/">Calibre</a> permite gestionar toda nuestra biblioteca digital además de convertir nuestros archivos PDF en ePub &#8211; entre otros formatos). El siguiente paso (imagen de la derecha) consiste en seleccionar el lector de libros que usaremos, este tutorial está orientado al <a href="http://apple.com/es/iphone/">iPhone</a>, <a href="http://www.apple.com/es/ipodtouch/">iPod</a> y <a href="http://apple.com/es/ipad/">iPad</a>, así que seleccionaremos de la primera lista &#8220;<em>Apple</em>&#8221; y de la segunda &#8220;<em>iPad or iPhone/iTouch + Stanza</em>&#8220;.</p>
<p><a href="http://sumolari.com/wp-content/uploads/2010/08/instalacion_paso3.png" rel="lightbox-4358"><img class="alignleft size-medium wp-image-4361" title="Instalación de Calibre - Paso 3" src="http://sumolari.com/wp-content/uploads/2010/08/instalacion_paso3-300x178.png" alt="Instalación de Calibre - Paso 3" width="300" height="178" /></a><a href="http://sumolari.com/wp-content/uploads/2010/08/instalacion_paso4.png" rel="lightbox-4358"><img class="alignright size-medium wp-image-4362" title="Instalación de Calibre - Paso 4" src="http://sumolari.com/wp-content/uploads/2010/08/instalacion_paso4-300x178.png" alt="Instalación de Calibre - Paso 4" width="300" height="178" /></a>El tercer paso es opcional (imagen de la izquierda) y permite crear un servidor para almacenar información acerca de nuestra lectura si usamos la aplicación <a href="http://www.lexcycle.com/">Stanza</a>, pero el objectivo del tutorial es leer los libros con <a href="http://itunes.apple.com/es/app/ibooks/id364709193?mt=8">iBooks</a>, así que podemos dejar desmarcada esta opción. Con esto habremos terminado de configurar <a href="http://calibre-ebook.com/">Calibre</a> (imagen de la derecha).</p>
<p><a href="http://sumolari.com/wp-content/uploads/2010/08/esquema.png" rel="lightbox-4358"><img class="alignleft size-medium wp-image-4364" title="Convertir libros con Calibre" src="http://sumolari.com/wp-content/uploads/2010/08/esquema-300x215.png" alt="Convertir libros con Calibre" width="300" height="215" /></a><a href="http://sumolari.com/wp-content/uploads/2010/08/convertir_paso2.png" rel="lightbox-4358"><img class="alignright size-medium wp-image-4365" title="Convertir libros con Calibre - Paso 2" src="http://sumolari.com/wp-content/uploads/2010/08/convertir_paso2-300x211.png" alt="Convertir libros con Calibre - Paso 2" width="300" height="211" /></a>Convertir un documento PDF a ePub no es tampoco nada complicado. Lo primero que tenemos que hacer es añadir el documento en cuestión a <a href="http://calibre-ebook.com/">Calibre</a>, en Mac OS X basta con arrastrar el archivo a su icono en el dock, aunque también podemos añadirlo haciendo clic en la imagen del libro rojo (la primera imagen del menú superior). Cuando tengamos añadido el libro veremos algo similar a la imagen de la izquierda. A continuación tenemos que seleccionar el libro que queramos convertir y hacer clic en la imagen del libro marrón (la tercera del menú superior, en la imagen de la izquierda está indicada). Nos aparecerá una ventana con opciones para configurar el nuevo documento (imagen de la derecha), como seleccionar la portada, la tabla de contenidos, metadatos, formato del nuevo documento, etc. Las opciones que vienen por defecto nos valen (a no ser que queramos personalizar más el documento), así que le damos a &#8220;<em>Aceptar</em>&#8221; y continuamos.</p>
<p><a href="http://sumolari.com/wp-content/uploads/2010/08/convertir_paso3.png" rel="lightbox-4358"><img class="alignleft size-medium wp-image-4366" title="Esperando a que Calibre acabe la exportación" src="http://sumolari.com/wp-content/uploads/2010/08/convertir_paso3-300x270.png" alt="Esperando a que Calibre acabe la exportación" width="300" height="270" /></a><a href="http://sumolari.com/wp-content/uploads/2010/08/convertir_paso4.png" rel="lightbox-4358"><img class="alignright size-medium wp-image-4367" title="Resultado de la conversión con Calibre" src="http://sumolari.com/wp-content/uploads/2010/08/convertir_paso4-300x274.png" alt="Resultado de la conversión con Calibre" width="300" height="274" /></a>Ahora tendremos que esperar unos minutos (dependiendo del tamaño del archivo) hasta que esté listo el documento convertido (veréis una ventana como la de la imagen de la izquierda). Cuando acabe la exportación, veremos que en nuestra biblioteca de <a href="http://calibre-ebook.com/">Calibre</a> ahora hay dos archivos más: la portada del libro exportado y el libro en formato ePub. Ahora ya sólo nos queda importar el libro en iTunes (de nuevo en Mac OS X basta con arrastrar el archivo al icono de iTunes en el dock) y sincronizar nuestro <a href="http://apple.com/es/iphone/">iPhone</a>/<a href="http://www.apple.com/es/ipodtouch/">iPod</a>/<a href="http://apple.com/es/ipad/">iPad</a>.</p>
<p>Lamentablemente, el archivo que obtendremos no será idéntico al PDF, y puede que haya variaciones en el color y en la estructura en general. De hecho el documento que he convertido yo en el tutorial perdía los colores y la estructura del documento variaba ligeramente. A cambio ganaremos la posiblidad de poder aumentar el tamaño de la letra.</p>
]]></content:encoded>
			<wfw:commentRss>http://sumolari.com/convierte-tus-pdf-en-epub/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

