<?xml version="1.0" encoding="iso-8859-1"?><feed xmlns="http://www.w3.org/2005/Atom">
    <title>design-nation.blog/es</title>
    <link rel="alternate" type="text/html" href="http://www.design-nation.net/es/" />
    <link rel="self" type="application/atom+xml" href="http://www.design-nation.net/es/atom.php" />
   <id>tag:www.design-nation.net,2008:/es//3</id>
    <link rel="service.post" type="application/atom+xml" href="http://www.design-nation.net/cgi-bin/mt-atom.cgi/weblog/blog_id=3" title="design-nation.blog/es" />
    <updated>2008-08-18T09:20:49Z</updated>
    <subtitle>un blog sobre actionscript, java, cocoa, y lo que se tercie</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 3.2</generator>
 
<entry>
    <title>Keep Your Word 1.0</title>
    <link rel="alternate" type="text/html" href="http://www.design-nation.net/es/archivos/003840.php" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.design-nation.net/cgi-bin/mt-atom.cgi/weblog/blog_id=3/entry_id=3840" title="Keep Your Word 1.0" />
    <id>tag:www.design-nation.net,2008:/es//3.3840</id>
    
    <published>2008-08-18T09:19:58Z</published>
    <updated>2008-08-18T09:20:49Z</updated>
    
    <summary>Esta vez ha sido niña. Tengo el placer de anunciar la disponibilidad inmediata de la segunda aplicación de bambooapps: Keep Your Word. ¿Para qué sirve Keep Your Word? Pues no es más que una herramienta de apoyo para los que...</summary>
    <author>
        <name>Cesar Tardaguila</name>
        <uri>http://www.design-nation.net</uri>
    </author>
            <category term="Cocoa" />
            <category term="Flash-Actionscript" />
            <category term="General" />
            <category term="Java" />
            <category term="Mac" />
    
    <content type="html" xml:lang="es" xml:base="http://www.design-nation.net/es/">
        <![CDATA[<p>Esta vez ha sido niña.</p>

<p>Tengo el placer de anunciar la disponibilidad inmediata de la segunda aplicación de <a href="http://bambooapps.com/">bambooapps</a>: <a href="http://bambooapps.com/kyw/">Keep Your Word</a>.</p>

<p><img src="http://www.design-nation.net/es//kyw_interface_400.jpg" alt="kyw_interface_400.jpg" border="0" width="400" height="404" /></p>

<p>¿Para qué sirve Keep Your Word? Pues no es más que una herramienta de apoyo para los que estudiamos idiomas. Permite crear tus propios diccionarios, con los términos que tú quieras, y organizados como tú quieras. Pero además, facilita el aprendizaje de esas colecciones de palabras gracias a sus diferentes "modos de ejercicio".</p>

<p>Keep Your Word es una aplicación sólo para Mac OS X Leopard, tiene un período de prueba de 30 días, durante los cuales la aplicación es completamente funcional, y un precio de $24.95 USD.</p>

<p>Más información en la <a href="http://bambooapps.com/">web de bambooapps</a>.</p>]]>
        
    </content>
</entry>
<entry>
    <title>FND 1.3</title>
    <link rel="alternate" type="text/html" href="http://www.design-nation.net/es/archivos/003839.php" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.design-nation.net/cgi-bin/mt-atom.cgi/weblog/blog_id=3/entry_id=3839" title="FND 1.3" />
    <id>tag:www.design-nation.net,2008:/es//3.3839</id>
    
    <published>2008-07-17T13:39:28Z</published>
    <updated>2008-07-17T13:48:45Z</updated>
    
    <summary>Se acaba de liberar una nueva versión de FND (film is not dead), la aplicación para Mac OS X que viene en ayuda de aquellos que amamos la fotografía analógica y que disfrutamos revelando película con nuestras propias manos. FND...</summary>
    <author>
        <name>Cesar Tardaguila</name>
        <uri>http://www.design-nation.net</uri>
    </author>
            <category term="Cocoa" />
            <category term="Flash-Actionscript" />
            <category term="General" />
            <category term="Java" />
    
    <content type="html" xml:lang="es" xml:base="http://www.design-nation.net/es/">
        <![CDATA[<p>Se acaba de liberar una nueva versión de <a href="http://bambooapps.com/fnd/">FND (film is not dead)</a>, la aplicación para Mac OS X que viene en ayuda de aquellos que amamos la fotografía analógica y que disfrutamos revelando película con nuestras propias manos.</p>

<p><img src="http://www.design-nation.net/es//fnd_1_4_450.png" alt="fnd_1_4_450.png" border="0" width="450" height="381" /></p>

<p>FND es una tabla de tiempos y reveladores, que permite tener organizada y clasificada tu experiencia con las diferentes combinaciones de película y revelador. Además, FND es un reloj de revelado, que puede funcionar en modo fullscreen, y que es controlable a través del Apple Remote.</p>

<p>La aplicación es sólo para Leopard, tiene un período de prueba de 30 días, y su precio es de 12.95 dólares.</p>

<p>Esta nueva versión permite al usuario asignar los tiempos de agitación, que por defecto se sitúan en 30 segundos tanto en la importación inicial de datos como en la creación de nuevos registros, así como algunos bugfixes.</p>]]>
        
    </content>
</entry>
<entry>
    <title>Nueve meses</title>
    <link rel="alternate" type="text/html" href="http://www.design-nation.net/es/archivos/003838.php" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.design-nation.net/cgi-bin/mt-atom.cgi/weblog/blog_id=3/entry_id=3838" title="Nueve meses" />
    <id>tag:www.design-nation.net,2008:/es//3.3838</id>
    
    <published>2008-06-13T05:05:25Z</published>
    <updated>2008-06-13T05:05:51Z</updated>
    
    <summary>Es el tiempo que ha necesitado flickr para aprobar una solicitud de API comercial. Nota mental número uno: jamás, nunca jamás, vuelvas a depender de un servicio externo para tus desarrollos. Nota mental número dos: el próximo que diga &quot;mashup&quot;...</summary>
    <author>
        <name>Cesar Tardaguila</name>
        <uri>http://www.design-nation.net</uri>
    </author>
            <category term="Cocoa" />
            <category term="Flash-Actionscript" />
            <category term="General" />
            <category term="Java" />
    
    <content type="html" xml:lang="es" xml:base="http://www.design-nation.net/es/">
        <![CDATA[Es el tiempo que ha necesitado flickr para aprobar una solicitud de API comercial.

Nota mental número uno: jamás, nunca jamás, vuelvas a depender de un servicio externo para tus desarrollos.

Nota mental número dos: el próximo que diga "mashup" delante de mí se va a llevar un bofetón. Algo que tampoco debe descartar el próximo que, delante de mí, vuelva a decir "webdospuntocero".

Obviamente, <a href="http://bambooapps.com/arriba/">el proyecto</a>, a estas alturas, tiene una capa de polvo de un metro de grosor. Lo que tampoco tiene porqué ser algo necesariamente malo. Veremos.]]>
        
    </content>
</entry>
<entry>
    <title>iPhone 3G</title>
    <link rel="alternate" type="text/html" href="http://www.design-nation.net/es/archivos/003837.php" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.design-nation.net/cgi-bin/mt-atom.cgi/weblog/blog_id=3/entry_id=3837" title="iPhone 3G" />
    <id>tag:www.design-nation.net,2008:/es//3.3837</id>
    
    <published>2008-06-10T02:48:39Z</published>
    <updated>2008-06-10T03:04:09Z</updated>
    
    <summary>Apple nunca se ha caracterizado por utilizar la misma vara de medir los productos que utilizan el resto de fabricantes. Por eso, un teléfono caro y corto en funcionalidades en comparación con la competencia, lleva un año siendo el producto...</summary>
    <author>
        <name>Cesar Tardaguila</name>
        <uri>http://www.design-nation.net</uri>
    </author>
            <category term="Cocoa" />
            <category term="Flash-Actionscript" />
            <category term="General" />
            <category term="Java" />
    
    <content type="html" xml:lang="es" xml:base="http://www.design-nation.net/es/">
        <![CDATA[Apple nunca se ha caracterizado por utilizar la misma vara de medir los productos que utilizan el resto de fabricantes. Por eso, un teléfono caro y corto en funcionalidades en comparación con la competencia, lleva un año siendo el producto estrella de la compañía.

Imagino que hoy toda la web especializada en el cacharreo estará dándole mil vueltas a la lista de "cosas" que tiene el teléfono. Sinceramente, eso no creo que sea lo más importante del anuncio de ayer.

Desde mi punto de vista, lo más significativo es que la keynote de apertura de la WWDC se dedique prácticamente en exclusiva al lanzamiento de un producto y de un servicio (.Mac) remodelado en apoyo de ese producto. Porque eso es lo que da la idea real de dónde está Apple hoy en día, y de hacia dónde se va a seguir dirigiendo en el futuro cercano.

Tampoco creo que nadie se pueda engañar. Ya hace cosa de un año que sabemos que para Apple, el ordenador no es el producto estrella del catálogo, sino un producto más. Incluso, en breve, me temo, el ordenador será sólo la herramienta que los desarrolladores van a necesitar para trabajar en el "auténtico" producto Apple: el iPhone. Es lo que hay, guste o no.

Ahora bien, desde el punto de vista de un desarrollador que <a href="http://www.bambooapps.com">intenta vender aplicaciones</a>, hoy es un día para estar satisfechos. Apple deja el iPhone en un precio en el que es imposible resistirse (y hasta donde yo recuerdo, es la primera vez que un producto de Apple es más barato que la competencia), y nos permite distribuir aplicaciones a través de un canal embebido en el sistema, con coste cero para nosotros, y con exposición máxima. Dicho de otra forma, el Tito Estíf ha hecho todo lo posible para que sea casi obligatorio para cualquier desarrollador el plantearse seriamente el intentar construir algo para el iPhone.

En eso, ganamos todos. El que programa porque lo va a tener algo más fácil para intentar vender; Apple, porque se está asegurando la existencia de un amplio catálogo de aplicaciones; el usuario final, porque va a tener muchas cosas buenas donde elegir. 

Como mínimo, desde luego, a mí me han hecho replantearme si la idea en la que estoy trabajando va a ser finalmente para escritorio o para iPhone. Y es que no es lo mismo intentar vender una aplicación para una plataforma con un 3% de penetración que para lo que parece que va a ser el cacharro de la temporada.]]>
        
    </content>
</entry>
<entry>
    <title>Testing: Hopefully not nobody</title>
    <link rel="alternate" type="text/html" href="http://www.design-nation.net/es/archivos/003836.php" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.design-nation.net/cgi-bin/mt-atom.cgi/weblog/blog_id=3/entry_id=3836" title="Testing: Hopefully not nobody" />
    <id>tag:www.design-nation.net,2008:/es//3.3836</id>
    
    <published>2008-04-23T10:33:03Z</published>
    <updated>2008-04-23T10:33:21Z</updated>
    
    <summary>Que yo recuerde, las versiones anteriores de XCode no incluían en la plantilla de los proyectos ningún archivo de créditos. Según parece, ahora ya sí... &quot;Hopefully not nobody&quot;. Tiene su chispa....</summary>
    <author>
        <name>Cesar Tardaguila</name>
        <uri>http://www.design-nation.net</uri>
    </author>
            <category term="Cocoa" />
            <category term="Flash-Actionscript" />
            <category term="Java" />
            <category term="Mac" />
    
    <content type="html" xml:lang="es" xml:base="http://www.design-nation.net/es/">
        <![CDATA[<p>Que yo recuerde, las versiones anteriores de XCode no incluían en la plantilla de los proyectos ningún archivo de créditos. Según parece, ahora ya sí...</p>

<p><img src="http://www.design-nation.net/es//hopefully.png" alt="hopefully.png" border="0" width="364" height="414" /></p>

<p>"Hopefully not nobody". Tiene su chispa.</p>]]>
        
    </content>
</entry>
<entry>
    <title>FND 1.2</title>
    <link rel="alternate" type="text/html" href="http://www.design-nation.net/es/archivos/003835.php" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.design-nation.net/cgi-bin/mt-atom.cgi/weblog/blog_id=3/entry_id=3835" title="FND 1.2" />
    <id>tag:www.design-nation.net,2008:/es//3.3835</id>
    
    <published>2008-04-01T12:23:07Z</published>
    <updated>2008-04-01T12:23:33Z</updated>
    
    <summary>Se acaba de liberar una nueva versión de FND (film is not dead), la aplicación para Mac OS X que viene en ayuda de aquellos que amamos la fotografía analógica y que disfrutamos revelando película con nuestras propias manos. FND...</summary>
    <author>
        <name>Cesar Tardaguila</name>
        <uri>http://www.design-nation.net</uri>
    </author>
            <category term="Cocoa" />
            <category term="Flash-Actionscript" />
            <category term="Java" />
            <category term="Mac" />
    
    <content type="html" xml:lang="es" xml:base="http://www.design-nation.net/es/">
        <![CDATA[<p>Se acaba de liberar una nueva versión de <a href="http://bambooapps.com/fnd/">FND (film is not dead)</a>, la aplicación para Mac OS X que viene en ayuda de aquellos que amamos la fotografía analógica y que disfrutamos revelando película con nuestras propias manos.</p>

<p>FND es una tabla de tiempos y reveladores, que permite tener organizada y clasificada tu experiencia con las diferentes combinaciones de película y revelador. Además, FND es un reloj de revelado, que puede funcionar en modo fullscreen, y que es controlable a través del Apple Remote.</p>

<p>La aplicación es sólo para Leopard, tiene un período de prueba de 30 días, y su precio es de 12.95 dólares.</p>

<p>Esta nueva versión incluye, entre varias mejoras de usabilidad, la localización en castellano.</p>]]>
        
    </content>
</entry>
<entry>
    <title>Uso de Core Animation para modificar el contenido de una vista</title>
    <link rel="alternate" type="text/html" href="http://www.design-nation.net/es/archivos/003834.php" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.design-nation.net/cgi-bin/mt-atom.cgi/weblog/blog_id=3/entry_id=3834" title="Uso de Core Animation para modificar el contenido de una vista" />
    <id>tag:www.design-nation.net,2008:/es//3.3834</id>
    
    <published>2008-03-19T04:36:35Z</published>
    <updated>2008-03-19T04:36:55Z</updated>
    
    <summary>Uno de los frameworks que han hecho su debut con Leopard ha sido Core Animation. Según Apple, Core Animation es un framework para renderizado gráfico, proyección y animación. Lo que, traducido, quiere decir, que es un framework que facilita enormemente...</summary>
    <author>
        <name>Cesar Tardaguila</name>
        <uri>http://www.design-nation.net</uri>
    </author>
            <category term="Cocoa" />
            <category term="Flash-Actionscript" />
            <category term="Java" />
            <category term="Mac" />
    
    <content type="html" xml:lang="es" xml:base="http://www.design-nation.net/es/">
        <![CDATA[<p>Uno de los frameworks que han hecho su debut con Leopard ha sido Core Animation.</p>

<p>Según Apple, Core Animation es un framework para renderizado gráfico, proyección y animación. Lo que, traducido, quiere decir, que es un framework que facilita enormemente la animación de elementos de interfaz.</p>

<p>Por ejemplo, es muy sencillo cambiar en tiempo de ejecución el contenido de una vista, sustituyéndolo por otra vista completamente distinta, presentando el cambio con una animación discreta, pero efectiva para reforzar el feedback que recibe el usuario del proceso.</p>

<p>En este ejemplo vamos a partir de este primer estado:</p>

<p><img src="http://www.design-nation.net/es//swap_final_1.png" alt="swap_final_1.png" border="0" width="560" height="243" /></p>

<p>Para llegar a este otro:</p>

<p><img src="http://www.design-nation.net/es//swap_final_2.png" alt="swap_final_2.png" border="0" width="560" height="243" /></p>

<p>Como puede verse, en este caso el cambio no es muy grande, se pasa de un slider a un desplegable, no obstante, la transición se hará utilizando la animación por defecto del framework (dissolve).</p>

<p>Construir el interfaz de la aplicación es sencillo. En la ventana principal de la misma, voy a colocar un botón, que será el que lance la animación, y una instancia de NSView, cuyo contenido iré modificando en tiempo de ejecución. Éste sería el aspecto de mi ventana:</p>

<p><img src="http://www.design-nation.net/es//swap_ventana.png" alt="swap_ventana.png" border="0" width="560" height="243" /></p>

<p>Además, construyo dos instancias más de NSView:</p>

<p><img src="http://www.design-nation.net/es//swap_view1.png" alt="swap_view1.png" border="0" width="381" height="193" /></p>

<p><img src="http://www.design-nation.net/es//swap_view2.png" alt="swap_view2.png" border="0" width="243" height="198" /></p>

<p>Como se puede ver, el ancho de las dos vistas es diferente. </p>

<p>Construyo también el esqueleto del controlador de la aplicación. Tendré tres outlets, uno a cada uno de las tres vistas (la de la ventana principal, y las dos vistas independientes). Además, tendré un action para el botón de "swap" y un booleano que me indicará si la vista que se está mostrando en cada instante es la primera o la segunda:</p>

<p>#import <Cocoa/Cocoa.h></p>

<p><br />
@interface ViewSwapController : NSObject <br />
{<br />
	IBOutlet NSView *containerView;<br />
	IBOutlet NSView *firstView;<br />
	IBOutlet NSView *secondView;<br />
	<br />
	BOOL showFirst;<br />
}</p>

<p>-(IBAction) swapView: (id) sender;<br />
@end</p>

<p>Tras crear la instancia de NSObject en Interface Builder y asignarle como clase mi controlador, la estructura del nib sería como la siguiente:</p>

<p><img src="http://www.design-nation.net/es//swap_nib.png" alt="swap_nib.png" border="0" width="399" height="430" /></p>

<p>Quiero que mi controlador haga lo siguiente: al arrancar la aplicación, insertará dentro de la vista de la ventana principal la primera de las dos vistas independientes que he creado, y cuando se haga clic en el botón de "swap" se cambiará esa vista por la segunda.</p>

<p>Por tanto, el método awakeFromNib será:</p>

<p>-(void) awakeFromNib<br />
{	<br />
	showFirst = NO;<br />
	<br />
	[ containerView setWantsLayer: YES ];<br />
	<br />
	[ [ containerView animator ] addSubview: firstView ];<br />
}</p>

<p>Simplemente, preparo la vista de la ventana principal para que sea animable, y le añado como subvista la primera de mis vistas personalizadas.</p>

<p>Al hacer clic en el botón:</p>

<p>-(IBAction) swapView: (id) sender<br />
{<br />
	NSRect containerFrame = [ containerView frame ];<br />
	NSRect firstViewFrame;<br />
	NSNumber *newCoord;<br />
	NSView *tempFirst;<br />
	NSView *tempSecond;<br />
	<br />
	if( showFirst )<br />
	{<br />
		tempFirst = secondView;<br />
		tempSecond = firstView;<br />
		<br />
		showFirst = NO;<br />
	}<br />
	else<br />
	{<br />
		tempFirst = firstView;<br />
		tempSecond = secondView;<br />
		<br />
		showFirst = YES;<br />
	}<br />
	<br />
	[ [ containerView animator ] replaceSubview: tempFirst with: tempSecond ];		<br />
	<br />
	firstViewFrame = [ tempSecond frame ];<br />
	<br />
	newCoord = [ NSNumber numberWithFloat: containerFrame.size.width /2 - firstViewFrame.size.width/2 ];</p>

<p>	[ tempSecond setFrameOrigin: NSMakePoint( [ newCoord intValue ] , 0 ) ];		<br />
	</p>

<p>}</p>

<p><br />
En primer lugar, calculo el ancho de la vista contenedor, y de la vista que quiero colocar dentro de la misma, para luego poder centrarla, y posteriormente reemplazo la vista que esté dentro del contenedor por la que corresponda.</p>

<p>Lo importante, lo que hace que la transición entre las dos vistas sea animada, es que no ataco directamente la vista contenedor para modificar su contenido, sino que utilizo el decorator que crea CoreAnimation (que se llama animator) para que, de esa forma, cualquier modificación de las propiedades de esa vista se muestre de forma animada.</p>

<p>El proyecto puede descargarse del repositorio público de subversion:</p>

<p>svn co http://svn.liadorasoft.com/viewswap ViewSwap</p>

<p>Enlaces relacionados:<br />
<a href="http://www.design-nation.net/es/archivos/003819.php">Un clon de Photo Booth en 32 minutos</a><br />
<a href="http://www.design-nation.net/es/archivos/003829.php">Extensión por delegación</a><br />
<a href="http://www.design-nation.net/es/archivos/003830.php">Bindings, NSArrayController y Value Transformers</a></p>]]>
        
    </content>
</entry>
<entry>
    <title>iPhone SDK</title>
    <link rel="alternate" type="text/html" href="http://www.design-nation.net/es/archivos/003833.php" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.design-nation.net/cgi-bin/mt-atom.cgi/weblog/blog_id=3/entry_id=3833" title="iPhone SDK" />
    <id>tag:www.design-nation.net,2008:/es//3.3833</id>
    
    <published>2008-03-07T04:26:06Z</published>
    <updated>2008-03-07T04:38:49Z</updated>
    
    <summary>Ya está, ya hay un SDK para el iPhone/iPod Touch. Por fin se van a poder desarrollar y distribuir aplicaciones de forma &quot;oficial&quot;, soportada por Apple y sin necesidad de hacer nada estraño con el aparato. Desde mi punto de...</summary>
    <author>
        <name>Cesar Tardaguila</name>
        <uri>http://www.design-nation.net</uri>
    </author>
            <category term="Cocoa" />
            <category term="Flash-Actionscript" />
            <category term="General" />
            <category term="Java" />
            <category term="Mac" />
    
    <content type="html" xml:lang="es" xml:base="http://www.design-nation.net/es/">
        <![CDATA[<p>Ya está, ya hay un SDK para el iPhone/iPod Touch. Por fin se van a poder desarrollar y distribuir aplicaciones de forma "oficial", soportada por Apple y sin necesidad de hacer nada estraño con el aparato.</p>

<p>Desde mi punto de vista, como parte interesada, como usuario y como desarrollador, hay varias cosas que me han llamado la atención.</p>

<p><strong>¿Documentación?</strong><br />
En primer lugar, la mayor sorpresa ha sido lo bien documentada que está la plataforma, sobre todo teniendo en cuenta que Apple tiende a producir una documentación más bien opaca, que es poco más que una enumeración de los interfaces de sus APIs.</p>

<p>Esta vez no sólo se han publicado documentos "en papel" sino una serie de vídeos en ADC on iTunes que sobrepasan con creces, en calidad de contenidos, lo que había disponible hasta ahora (exceptuando las sesiones de la WWDC). Lo que me lleva a pensar dos cosas más.</p>

<p><strong>No es el iPhone ni el iPod, es lo que está por venir</strong><br />
La sensación, al menos la que yo tengo, es que lo que se documenta no es sólo el SDK para iPhone e iPod Touch, sino que lo se documenta es <em>la plataforma de Apple para dispositivos con pantalla táctil</em>.</p>

<p>Es decir, que la sensación que a mí me ha quedado es la de que lo que se abre hoy no es la puerta al desarrollo para un cacharro, sino para muchos, que compartirán ciertos frameworks. Conociendo la arquitectura de los frameworks de Apple no es nada descabellado pensar que este SDK mañana sirva para desarrollar aplicaciones para el sistema de control de un coche, o para un tablet, o para lo que sea que se pueda manejar con los dedos.</p>

<p>Y eso está muy bien.</p>

<p><strong>Cuota de mercado</strong><br />
La otra conclusión es que esta plataforma (la llamémosla móvil) no tiene las limitaciones en cuanto a cuota de mercado que tiene un Mac. Apple lo sabe, y le da la importancia pertinente al SDK. D e hecho, se ha dividido el Developer Connection en dos partes jerárquicamente igual de importantes: el iPhone Developer Program, y el Mac Developer Program. </p>

<p>Sinceramente, llama la atención ver el esfuerzo que ha puesto Apple en facilitar a los desarrolladores la adaptación a esta plataforma.</p>

<p>Eso es, obviamente, bueno. Cuantos más sean (o seamos) desarrollando aplicaciones, mejores aplicaciones habrá. Lo que lleva al siguiente punto.</p>

<p><strong>Modelo de distribución</strong><br />
Sinceramente, no me parece mal que las aplicaciones se distribuyan vía iTunes. No me tengo que preocupar de montar la web del producto, ni un sistema de cobro on-line, y más importante aún, mi aplicación está disponible para mis futuros usuarios desde el mismo dispositivo en el que se va a utilizar. Lo que va en la línea de actuación de Apple, por cierto, que no es otra que poner lo más fácil posible a la gente que pueda comprar. Y si yo quiero vender, y Apple lo pone fácil para comprar, la cosa me gusta.</p>

<p>Peeeeeeeeero, y siempre hay un pero, lo que no me gusta es que Apple tenga que aprobar la entrada de la aplicación en la tienda. Entiendo que ellos intentan proteger, por un lado, al proveedor de servicios móviles, y por otro, su propia reputación, pero eso tiene dos cosas muy malas, relacionadas: Apple puede decidir cerrar el paso a una aplicación porque le guste la idea, y puede decidir desarrollar una apliación similar por sí misma.</p>

<p>Lo de los 99$ por poder firmar aplicaciones y distribuirlas en la tienda de iTunes no me parece tan grave. Total, es lo que me iba a costar el hosting. Lo mismo pasa con el 30% de comisión que se queda Steve. Es alta, es cierto, pero tampoco es tan grave.</p>

<p>Lo que sí que toca las canicas es el empeño que tiene Apple en poner una línea entre usuarios/desarrolladores de USA y del resto del mundo. Que, digo yo, que algún día se nos va a acabar la paciencia.</p>

<p><strong>El flujo de trabajo</strong><br />
Lo primero que me ha llamado la atención del SDK es que el emulador funciona muy bien. Lo segundo es que, por favor, hace falta un Interface Builder específico, que para hacer layouts a mano ya existe Java.</p>

<p>Poco más se puede decir, la verdad. Las herramientas son las de siempre, el lenguaje es el de siempre (aunque, ojo, sin recolector de basura, así que hay que volver al hold me - use me - release me) y todo es como siempre.</p>

<p>Sólo que, esta vez, con muchísima más expectación que otras veces.</p>

<p>Ahora, ya, sólo queda empaparse por completo de la documentación, y comprobar si, por favor, finalmente ha entrado en el SDK público el acceso a los SyncServices...</p>]]>
        
    </content>
</entry>
<entry>
    <title>FND 1.1.1</title>
    <link rel="alternate" type="text/html" href="http://www.design-nation.net/es/archivos/003832.php" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.design-nation.net/cgi-bin/mt-atom.cgi/weblog/blog_id=3/entry_id=3832" title="FND 1.1.1" />
    <id>tag:www.design-nation.net,2008:/es//3.3832</id>
    
    <published>2008-02-10T12:42:03Z</published>
    <updated>2008-02-10T12:42:53Z</updated>
    
    <summary>Release de mantenimiento de FND (film is not dead), la aplicación para Mac OS X que viene en ayuda de aquellos que amamos la fotografía analógica y que disfrutamos revelando película con nuestras propias manos. FND es una tabla de...</summary>
    <author>
        <name>Cesar Tardaguila</name>
        <uri>http://www.design-nation.net</uri>
    </author>
            <category term="Cocoa" />
            <category term="Flash-Actionscript" />
            <category term="General" />
            <category term="Java" />
    
    <content type="html" xml:lang="es" xml:base="http://www.design-nation.net/es/">
        <![CDATA[<p><a href="http://bambooapps.com/2008/02/10/fnd-111/">Release de mantenimiento</a> de FND (film is not dead), la aplicación para Mac OS X que viene en ayuda de aquellos que amamos la fotografía analógica y que disfrutamos revelando película con nuestras propias manos.</p>

<p>FND es una tabla de tiempos y reveladores, que permite tener organizada y clasificada tu experiencia con las diferentes combinaciones de película y revelador. Además, FND es un reloj de revelado, que puede funcionar en modo fullscreen, y que es controlable a través del Apple Remote.</p>

<p>La aplicación es sólo para Leopard, tiene un período de prueba de 30 días, y su precio es de 12.95 dólares.</p>]]>
        
    </content>
</entry>
<entry>
    <title>Entresijos. Haciendo la web. El nuevo proyecto de Design-Nation</title>
    <link rel="alternate" type="text/html" href="http://www.design-nation.net/es/archivos/003831.php" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.design-nation.net/cgi-bin/mt-atom.cgi/weblog/blog_id=3/entry_id=3831" title="Entresijos. Haciendo la web. El nuevo proyecto de Design-Nation" />
    <id>tag:www.design-nation.net,2008:/es//3.3831</id>
    
    <published>2008-01-31T18:33:55Z</published>
    <updated>2008-02-01T21:44:21Z</updated>
    
    <summary>Durante los próximos días, tomará cuerpo &quot;Entresijos. Haciendo la web&quot;, el nuevo y por ahora último proyecto que sale de la cocina de ideas del emporio Design-Nation. ¿Qué es &quot;Entresijos&quot; ? Se trata de un podcast, en formato entrevista y...</summary>
    <author>
        <name>Javier Tardaguila</name>
        <uri>http://www.design-nation.net</uri>
    </author>
            <category term="General" />
            <category term="Noticias internet" />
    
    <content type="html" xml:lang="es" xml:base="http://www.design-nation.net/es/">
        <![CDATA[<p>Durante los próximos días, tomará cuerpo "<a href="http://www.design-nation.net/entresijos/">Entresijos. Haciendo la web</a>", el nuevo y por ahora último proyecto que sale de la cocina de ideas del emporio Design-Nation.</p>

<p>¿Qué es "Entresijos" ?</p>

<p>Se trata de un podcast, en formato entrevista y mesa redonda, de una duración no superior a media hora por episodio, por el que queremos que pase la mayor cantidad de profesionales que, de una u otra manera, desarrollen su actividad en relación con internet.</p>

<p>No es un podcast de y para programadores, sino que queremos que sirva como plataforma en la que todos los perfiles implicados en la construcción de internet (programadores, técnicos de sistemas, diseñadores, expertos en HCI, formadores, jefes de proyecto, bloggers, editores de webs de noticias, etc) y también aquellos que desde el otro lado de la barrera utilizan lo que los primeros construyen, puedan explicar en qué consiste su trabajo, cuáles son los retos con los que se enfrentan día a día, y cuál es la dirección que creen que debe tomar el futuro cercano, tanto de su parcela profesional como del negocio en general.</p>

<p>En el grupo de personas con el que estamos contactando hay programadores cliente y programadores servidor, técnicos de sistemas, diseñadores, animadores, expertos en e-learning, expertos en usabilidad,  directores de agencias de publicidad, o project managers.</p>

<p>Aprovechamos desde ya, para agradecer la colaboración de quienes en el último mes y medio nos han confirmado su deseo de participar. Y confiamos en que haya más gente colaborando a futuro.</p>

<p>Esperamos que os guste. </p>]]>
        
    </content>
</entry>
<entry>
    <title>Bindings, NSArrayController y Value Transformers</title>
    <link rel="alternate" type="text/html" href="http://www.design-nation.net/es/archivos/003830.php" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.design-nation.net/cgi-bin/mt-atom.cgi/weblog/blog_id=3/entry_id=3830" title="Bindings, NSArrayController y Value Transformers" />
    <id>tag:www.design-nation.net,2008:/es//3.3830</id>
    
    <published>2008-01-23T10:07:44Z</published>
    <updated>2008-01-23T10:24:08Z</updated>
    
    <summary>Parece el título de una mala película de acción, de esas que estiran hasta más allá de lo razonable y lo creíble la trama de un comic, pero es aún peor, porque es el título de la última aventura de...</summary>
    <author>
        <name>Cesar Tardaguila</name>
        <uri>http://www.design-nation.net</uri>
    </author>
            <category term="Cocoa" />
            <category term="Flash-Actionscript" />
            <category term="Java" />
    
    <content type="html" xml:lang="es" xml:base="http://www.design-nation.net/es/">
        <![CDATA[<p>Parece el título de una mala película de acción, de esas que estiran hasta más allá de lo razonable y lo creíble la trama de un comic, pero es aún peor, porque es el título de la última aventura de El Gran Dragón.</p>

<p>Y es que Bruce le ha ordenado que construya una prueba de concepto, una aplicación funcional, pero no muy compleja, que presente en un listado unos cuantos iconos. En concreto, los que corresponden con NSComputer, NSFolderBurnable y NSFolderSmart, que como El Gran Dragón bien sabe, Apple ha expuesto para su uso a partir de Leopard.</p>

<p>El Gran Dragón sabe que su Gran Maestro gusta de las aplicaciones sencillas y elegantes, de tener un núcleo funcional desde etapas muy tempranas sobre el que ir realizando los refinamientos necesarios y, por eso, su primera idea llega rápida como el ataque de una serpiente: "voy a construir una aplicación con un controlador, que tenga agregado un array mutable, array que controlaré con una instancia de NSArrayController, de forma que, por bindings, asigne el contenido del listado que constituye el interfaz de la aplicación a partir del contenido de ese array".</p>

<p>No está mal. Una solución sencilla, elegante, que utiliza en su beneficio muchos de los frameworks y metodologías de desarrollo para Mac OS X y cuya arquitectura sigue las líneas maestras de lo que se consideran "buenas prácticas".</p>

<p>Por tanto, El Gran Dragón comienza por crear el proyecto, como siempre, y por crear el controlador de la aplicación, una clase llamada AppController, que agregará un array mutable. La cabecera de esa clase sería por tanto:</p>

<p>#import <Cocoa/Cocoa.h></p>

<p><br />
@interface AppController : NSObject <br />
{<br />
	NSMutableArray *iconsCollection;<br />
}</p>

<p>@property(copy, readwrite) NSMutableArray *iconsCollection;</p>

<p>@end</p>

<p>El interfaz de la aplicación tampoco tiene mucha complicación. Basta con crear en Interface Builder una instancia de NSObject y asignarle su tipo al controlador de la aplicación, y construir un interfaz con un NSTableView con una única columna, sobre la que El Gran Dragón arrastra una instancia de NSImageCell, para de esa forma poder presentar imágenes en la tabla.</p>

<p><img src="http://www.design-nation.net/es//interfaz_transformer.png" alt="interfaz_transformer.png" border="0" width="210" height="460" /></p>

<p>Bien, se dice a sí mismo el Gran Dragón. "Como tengo un controlador de la aplicación responsable de crear un array mutable, si consigo colocar en ese array mutable las imágenes que quiero presentar en el interfaz, sólo tendría que asignar el binding correspondiente en Interface Builder para que mi aplicación presentara las imágenes". </p>

<p>Como ya era tarde, El Gran Dragón se marchó a la cama sonriente, pensando que había encontrado la solución a su problema. Sin embargo, a altas horas de la madrugada, su maestro se le apareció en sueños: "Gran Dragón, ¿acaso has olvidado todo lo que te he enseñado? De verdad crees que es necesario crear esas imágenes? ¿Y si quisieras serializar el modelo a disco? No entiendes que no es necesario crear tantas instancias de NSImage, sobe todo si las puedes crear en tiempo de ejecución? ¿No te parece?"</p>

<p>El Gran Dragón despertó sudoroso, pero con una mirada de gran determinación. "¡Es cierto! Puedo crear las instancias de NSImage al vuelo, lanzándole un mensaje como éste!":</p>

<p>[ NSImage imageNamed: @"NSComputer" ];</p>

<p>Por tanto, sólo necesitaría guardar en el modelo las cadenas de texto con los nombres de las imágenes a crear. Pero, ¿cómo hago para convertir esa cadena de texto en una instancia de NSImage, que es a lo que necesito bindar la columna de mi tabla?</p>

<p>Pues utilizando un Value Transformer. Un Value Transformer es una clase que ejerce como mediador en el mecanismo de bindings. Si esa clase existe, antes de pasarle al interfaz lo que debe dibujar, se le pasa al mediador el valor extraído del modelo, y es el mediador el que, tras hacer lo que deba con ese valor, quien le termina por dar al interfaz lo que éste necesita.</p>

<p>En este caso, el interfaz (la columna de la tabla) necesita instancias de NSImage, mientras que lo que El Gran Dragón va a guardar en el modelo con cadenas de texto. Por tanto, el Value Transformer será el que cree las instancias de NSImage necesarias a partir de ese valor de texto.</p>

<p>Lo primero es crear la entidad básica del modelo. El Gran Dragón ha decidido, en un alarde de originalidad, llamarla AppEntity:</p>

<p>#import <Cocoa/Cocoa.h></p>

<p><br />
@interface AppEntity : NSObject <br />
{<br />
	NSString *iconName;<br />
}<br />
@property(copy, readwrite) NSString *iconName;<br />
@end</p>

<p><br />
La implementación:</p>

<p>#import "AppEntity.h"</p>

<p><br />
@implementation AppEntity<br />
@synthesize iconName;<br />
@end</p>

<p><br />
Ahora, El Gran Dragón escribe la implementación de su controlador para que, al crearse, éste cree las tres instancias de esa entidad que El Gran Maestro le ha pedido. Por tanto, AppController.m será:</p>

<p>#import "AppController.h"<br />
#import "AppEntity.h"<br />
#import "DNIconValueTransformer.h"</p>

<p><br />
@implementation AppController<br />
@synthesize iconsCollection;<br />
-(id) init<br />
{<br />
	self = [ super init ];<br />
	<br />
	NSValueTransformer *iconTransformer = [ [ DNIconValueTransformer alloc ] init ];<br />
	[ NSValueTransformer setValueTransformer: iconTransformer forName:@"IconImageTransformer"];		<br />
	<br />
	iconsCollection = [ [ NSMutableArray alloc ] init ];<br />
	<br />
	AppEntity *entityOne = [ [ AppEntity alloc ] init ];<br />
	entityOne.iconName = @"NSComputer";<br />
	[ iconsCollection addObject: entityOne ];</p>

<p>	AppEntity *entityTwo = [ [ AppEntity alloc ] init ];<br />
	entityTwo.iconName = @"NSFolderBurnable";<br />
	[ iconsCollection addObject: entityTwo ];</p>

<p>	AppEntity *entityThree = [ [ AppEntity alloc ] init ];<br />
	entityThree.iconName = @"NSFolderSmart";	<br />
	[ iconsCollection addObject: entityThree ];	<br />
	<br />
	return self;<br />
}<br />
@end</p>

<p>Como puede verse, al inicializarse el controlador también se registra el Value Transformer, asignándole como nombre IconImageTransformer.</p>

<p>El siguiente paso de El Gran Dragón, por tanto, es escribir esa clase, que tendrá la siguiente cabecera:</p>

<p>#import <Cocoa/Cocoa.h></p>

<p><br />
@interface DNIconValueTransformer : NSValueTransformer<br />
{</p>

<p>}</p>

<p>@end</p>

<p>Como se puede ver, el único misterio que tiene es que extiende de NSValueTransformer.</p>

<p>La implementación tiene un poco más de miga:</p>

<p>#import "DNIconValueTransformer.h"</p>

<p><br />
@implementation DNIconValueTransformer</p>

<p>+ (Class)transformedValueClass<br />
{<br />
	return [ NSImage class ]; <br />
}</p>

<p>+ (BOOL)allowsReverseTransformation<br />
{<br />
	return YES;<br />
}</p>

<p>- ( id ) transformedValue:( id )value<br />
{<br />
		NSLog( @"transformador %@", value );<br />
		<br />
		if( value != nil )<br />
		{<br />
			return [ NSImage imageNamed: value ];<br />
		}<br />
		else<br />
		{<br />
			NSLog( @"pasa por el transformador" );<br />
			return nil;<br />
		}<br />
}</p>

<p>@end</p>

<p>Aunque tampoco es muy complicada. El método transformedValueClass devuelve el nombre del tipo de retorno del método que va a realizar la transformación: transformedValue. En este caso, lo que se va a crear son imágenes, por tanto devuelve NSImage.</p>

<p>El método de transformación en sí tampoco es muy complejo. Simplemente se crea la instancia de NSImage a partir del nombre de la imagen que se le pasa al transformador desde el modelo.</p>

<p>Ahora, de vuelta en Interface Builder, hay que crear una instancia de NSArrayController, y encargarla manejar la colección de iconos:</p>

<p><img src="http://www.design-nation.net/es//controlador_Array.png" alt="controlador_Array.png" border="0" width="450" /></p>

<p>El último paso es asignar el binding de la columna de la tabla. </p>

<p><img src="http://www.design-nation.net/es//table_column_bindings.png" alt="table_column_bindings.png" border="0" width="299" height="380" /></p>

<p>Como se puede ver, se binda al valor de la propiedad iconName de la entidad del modelo, pero utilizando la transformación que El Gran Dragón registró previamente como IconImageTransformer.</p>

<p>De esa forma, el resultado final es el que se pretendía conseguir:</p>

<p><img src="http://www.design-nation.net/es//icons_final.png" alt="icons_final.png" border="0" width="210" height="460" /></p>

<p>Y se ha conseguido con un modelo ligero, sin gran consumo de memoria ni de recursos del sistema, que puede ser serializado fácilmente.</p>

<p>Es un paso más para El Gran Dragón en el largo camino de la sabiduría.</p>

<p>El proyecto completo puede descargarse de <a href="http://www.design-nation.net/es/archivos/transformers.zip">este enlace</a></p>]]>
        
    </content>
</entry>
<entry>
    <title>Extensión por delegación</title>
    <link rel="alternate" type="text/html" href="http://www.design-nation.net/es/archivos/003829.php" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.design-nation.net/cgi-bin/mt-atom.cgi/weblog/blog_id=3/entry_id=3829" title="Extensión por delegación" />
    <id>tag:www.design-nation.net,2008:/es//3.3829</id>
    
    <published>2008-01-08T05:47:46Z</published>
    <updated>2008-01-08T05:50:28Z</updated>
    
    <summary> Gran Maestro: La prueba de hoy en el largo y tortuoso camino del conocimiento, Gran Dragón, es programar una vista clickable, que puedas reutilizar en todas las futuras pruebas con las que te vas a encontrar, y que sea...</summary>
    <author>
        <name>Cesar Tardaguila</name>
        <uri>http://www.design-nation.net</uri>
    </author>
            <category term="Cocoa" />
            <category term="Flash-Actionscript" />
            <category term="Java" />
            <category term="Mac" />
    
    <content type="html" xml:lang="es" xml:base="http://www.design-nation.net/es/">
        <![CDATA[<p><br />
<strong>Gran Maestro</strong>: <em>La prueba de hoy en el largo y tortuoso camino del conocimiento, Gran Dragón, es programar una vista clickable, que puedas reutilizar en todas las futuras pruebas con las que te vas a encontrar, y que sea capaz de notificar al controlador de la aplicación en la que se esté utilizando cada uno de los clicks que reciba.<br />
</em></p>

<p><strong>Gran Dragón</strong>: <em>Gracias, Gran Maestro, por proponerme un reto de tal importancia.<br />
</em></p>

<p>El Gran Dragón sabe que no puede traicionar la confianza ni las expectatias de su maestro. Sabe que ha comenzado un largo camino, un camino lleno de escarpadas montañas, cruzado por anchos y profundos ríos, un camino del que parten otros muchos caminos que le pueden distraer de su objetivo final: llegar al estado mental en el que sólo hay una forma de pensar; la que termina con la máxima cohesión y el mínimo acoplamiento.</p>

<p>Por eso, y porque El Gran Dragón cree que la mejor forma de programar es iterativa, produciendo desde la primera iteración algo funcional, aunque no esté necesariamente muy refinado, comienza su aventura declarando una subclase de NSView, que, simplemente, sea capaz de capturar los clicks de ratón que se produzcan sobre ella. Además, El Gran Dragón quiere proporcionar feedback visual de las interacciones con su vista, por lo que va a hacer que la vista cambie de color, del gris en reposo, a un gris más claro cuando sea clickada.</p>

<p>Por tanto, la cabecera de su vista será:</p>

<p>#import <Cocoa/Cocoa.h></p>

<p><br />
@interface DNClickableView : NSView <br />
{<br />
	BOOL mouseIsPressingMe;<br />
}</p>

<p>@end</p>

<p><br />
Al inicializar la instancia de su clase, el Gran Dragón hará que la variable booleana valga false. Cada vez que redibuje el contenido de su vista, comprobará el valor de esa variable: si es true, el fondo será gris claro, y si es false, gris:</p>

<p>- (id)initWithFrame:(NSRect)frame <br />
{<br />
    self = [super initWithFrame:frame];<br />
	<br />
    if (self) <br />
	{<br />
		mouseIsPressingMe = NO;<br />
    }<br />
	<br />
    return self;<br />
}</p>

<p>- (void)drawRect:(NSRect)rect <br />
{<br />
    if ( mouseIsPressingMe )<br />
	{<br />
		[ [ NSColor lightGrayColor ] set ];<br />
	}<br />
	else<br />
	{ <br />
		[ [ NSColor grayColor ] set ];<br />
	}<br />
	<br />
    NSRectFill( rect );<br />
}</p>

<p><br />
Para capturar los eventos de ratón sobre esa vista, basta con declararlos, sobreescribiendo por tanto los correspondientes a NSView, en la implementación de la subclase:</p>

<p>- ( void ) mouseDown: ( NSEvent * ) theEvent <br />
{<br />
	mouseIsPressingMe = YES;<br />
	[ self setNeedsDisplay: YES ];<br />
}</p>

<p>- (void)mouseUp:(NSEvent *)theEvent <br />
{<br />
    mouseIsPressingMe = NO;<br />
    [ self setNeedsDisplay: YES ];<br />
}</p>

<p>Por tanto, la declaración completa de la implementación de la clase sería:</p>

<p>#import "DNClickableView.h"</p>

<p><br />
@implementation DNClickableView</p>

<p>- (id)initWithFrame:(NSRect)frame <br />
{<br />
    self = [super initWithFrame:frame];<br />
	<br />
    if (self) <br />
	{<br />
		mouseIsPressingMe = NO;<br />
    }<br />
	<br />
    return self;<br />
}</p>

<p>- (void)drawRect:(NSRect)rect <br />
{<br />
    if ( mouseIsPressingMe )<br />
	{<br />
		[ [ NSColor lightGrayColor ] set ];<br />
	}<br />
	else<br />
	{ <br />
		[ [ NSColor grayColor ] set ];<br />
	}<br />
	<br />
    NSRectFill( rect );<br />
}</p>

<p>#pragma mark -<br />
#pragma mark mouse handling</p>

<p>- ( void ) mouseDown: ( NSEvent * ) theEvent <br />
{<br />
	mouseIsPressingMe = YES;<br />
	[ self setNeedsDisplay: YES ];<br />
}</p>

<p>- (void)mouseUp:(NSEvent *)theEvent <br />
{<br />
    mouseIsPressingMe = NO;<br />
    [ self setNeedsDisplay: YES ];<br />
}<br />
@end</p>

<p><br />
El Gran Dragón sabe que debe testar mucho y desde muy pronto, por lo que, para probar la funcionalidad de su clase, declara un controlador con un outlet hacia su vista, y compila y prueba el proyecto (El Gran Dragón da por supuesto que le lector sabe cómo hacer eso en XCode 3; no obstante, se puede encontrar <a href="http://www.design-nation.net/es/archivos/003819.php">más información sobre cómo hacerlo aquí</a>)</p>

<p>Bien, el Gran Dragón está satisfecho de su primera iteración. Tiene una aplicación que compila aunque no cumple con uno de los requisitos pedidos: que la vista notifique al controlador los clicks recibidos.</p>

<p>Ahora ha llegado el momento de meditar, con la cabeza fría, sobre los diferentes caminos que se presentan ante el Gran Dragón.</p>

<p>El primer camino, el más obvio, y probablemente el más sencillo y rápido de implementar sería declarar una variable de clase en la vista, en la que guardar una referencia al controlador, de forma que, al capturar el clic, se envíe un mensaje al controlador de la aplciación.</p>

<p>No está mal, piensa El Gran Dragón. Sin embargo, ¿hasta qué punto esa solución es portable? ¿Hasta qué punto esa misma vista se podría reutilizar en más proyectos?</p>

<p>El Gran Dragón sonríe, con la satisfacción de saberse en el buen camino. Sabe que esa primera solución, la más rápida, es, probablemente, la menos adecuada. En primer lugar, porque implica que tanto la vista como el controlador tengan una referencia cruzada el uno al otro. </p>

<p>En segundo lugar, porque si se hacen las cosas como se debería, la referencia al controlador que se guarda en la vista debería estar declarada con el tipo del controlador. Lo que no la hace precisamente portable. Claro, que eso se podría solventar haciendo que esa referencia sea de tipo un protocolo que implemente el controlador. Lo que tampoco es bastante portable, porque obliga a que el controlador de cualquier aplicación que quiera utilizar esta vista deba implementar ese protocolo.</p>

<p>El Gran Dragón, por tanto, deshecha la primera solución.</p>

<p>La segunda solución que le viene a la cabeza es utilizar una notificación, de forma que la vista lance esa notificación (lo que en la mayoría de lenguajes se llama un evento), que será escuchada por el controlador.</p>

<p>El problema en esta segunda solución es que la implementación de las notificaciones en Objective-C es un poco particular. Las notificaciones se emiten y se reciben a través de un singleton (NSNotificationCenter) de forma que es relativamente sencillo pisarse un pie con el otro, y hacer que una notificación sea escuchada por quien no debe.</p>

<p>Además, las notificaciones hacen el código un poco más difícil de leer, y tampoco es que sean demasiado amigables a la hora de pasar parámetros. </p>

<p>El Gran Dragóm, por tanto, inmerso como está en la búsqueda de la elegancia en su código, deshecha la segunda solución.</p>

<p>La tercera solución, sin embargo, es utilizar uno de los patrones más comunes en Cocoa: la delegación.</p>

<p>La extensión por delegación no es más que una forma de composición un poco más sofisticada. Una clase, la que se quiere extender, puede delegar detalles concretos de implementación (lo que es susceptible de cambiar entre una utilización y otra de la clase) en otras clases, de forma que, en tiempo de ejecución, se pueden delegar responsabilidades en clases concretas declaradas a ese efecto.</p>

<p>Ese patrón es muy sencillo de implementar en Objective-C, como bien sabe El Gran Dragón, gracias a la naturaleza tan dinámica del lenguaje, y a que siempre se puede saber si una clase va a poder responder o no a un mensaje.</p>

<p>El Gran Dragón comienza, por tanto, la escalada de la delegación declarando una variable de clase en la vista, junto con sus accesors:</p>

<p>#import <Cocoa/Cocoa.h></p>

<p><br />
@interface DNClickableView : NSView <br />
{<br />
	BOOL mouseIsPressingMe;<br />
	id delegate;<br />
}</p>

<p>- (id) delegate;<br />
- (void) setDelegate: (id) newDelegate;</p>

<p>-(void) viewWasClicked;<br />
@end</p>

<p>Además, declara un método que será ejecutado cuando se haga click en la vista (viewWasClicked)</p>

<p>Por tanto, los métodos dedicados a la captura de los clics quedarían así:</p>

<p>- ( void ) mouseDown: ( NSEvent * ) theEvent <br />
{<br />
	mouseIsPressingMe = YES;<br />
	[ self setNeedsDisplay: YES ];<br />
}</p>

<p>- (void)mouseUp:(NSEvent *)theEvent <br />
{<br />
    mouseIsPressingMe = NO;<br />
    [ self setNeedsDisplay: YES ];<br />
	<br />
	[ self viewWasClicked ];<br />
}</p>

<p>Los acessors para el delegate:<br />
- (id)delegate<br />
{<br />
	return delegate;<br />
}</p>

<p>- (void)setDelegate:(id)newDelegate <br />
{<br />
	delegate = newDelegate;<br />
}</p>

<p>El método que gestiona los clicks:</p>

<p>-(void) viewWasClicked<br />
{<br />
	if( [ delegate respondsToSelector: @selector( viewWasClicked ) ] )<br />
	{<br />
		[ delegate viewWasClicked ];<br />
	}<br />
}</p>

<p>Ahí es donde el Gran Dragón se siente más orgulloso. Para evitar estar enviando mensajes a nil, comprueba que lo que se haya asignado como delegate responde al mensaje viewWasClicked. En caso de responder, reenvía el mensaje a esa clase, y en caso de no responder a él, lo deja morir.</p>

<p>En el controlador, sólo faltaría asignar el delegate:</p>

<p>-(void) awakeFromNib<br />
{<br />
	[ clickView setDelegate: self ];<br />
}</p>

<p><br />
Por tanto, la implementación completa de la vista sería:</p>

<p>#import "DNClickableView.h"</p>

<p><br />
@implementation DNClickableView</p>

<p>- (id)initWithFrame:(NSRect)frame <br />
{<br />
    self = [super initWithFrame:frame];<br />
	<br />
    if (self) <br />
	{<br />
        // Initialization code here.<br />
		<br />
		mouseIsPressingMe = NO;<br />
    }<br />
	<br />
    return self;<br />
}</p>

<p>- (void)drawRect:(NSRect)rect <br />
{<br />
    if ( mouseIsPressingMe )<br />
	{<br />
		[ [ NSColor lightGrayColor ] set ];<br />
	}<br />
	else<br />
	{ <br />
		[ [ NSColor grayColor ] set ];<br />
	}<br />
	<br />
    NSRectFill( rect );<br />
}</p>

<p>#pragma mark -<br />
#pragma mark mouse handling</p>

<p>- ( void ) mouseDown: ( NSEvent * ) theEvent <br />
{<br />
	mouseIsPressingMe = YES;<br />
	[ self setNeedsDisplay: YES ];<br />
}</p>

<p>- (void)mouseUp:(NSEvent *)theEvent <br />
{<br />
    mouseIsPressingMe = NO;<br />
    [ self setNeedsDisplay: YES ];<br />
	<br />
	[ self viewWasClicked ];<br />
}</p>

<p><br />
#pragma mark -<br />
#pragma mark delegate handling</p>

<p>- (id)delegate<br />
{<br />
	return delegate;<br />
}</p>

<p>- (void)setDelegate:(id)newDelegate <br />
{<br />
	delegate = newDelegate;<br />
}</p>

<p>-(void) viewWasClicked<br />
{<br />
	if( [ delegate respondsToSelector: @selector( viewWasClicked ) ] )<br />
	{<br />
		[ delegate viewWasClicked ];<br />
	}<br />
}</p>

<p><br />
-(void) dealloc<br />
{<br />
	[ delegate release ];<br />
	[ super dealloc ];<br />
}<br />
@end</p>

<p><br />
y la del controlador:</p>

<p>@implementation DNAppController</p>

<p>-(void) awakeFromNib<br />
{<br />
	[ clickView setDelegate: self ];<br />
}</p>

<p>#pragma mark -<br />
#pragma mark DNClickableView delegate method</p>

<p>-(void) viewWasClicked<br />
{<br />
	NSLog( @"DNAppController.viewWasClicked" );<br />
}<br />
@end</p>

<p><br />
Mucho mejor. El Gran Dragón se siente satisfecho, porque aunque aparentemente haya implementado una solución similar a la primera que deshechó, ha ganado muchísimo en flexibilidad. En este ejemplo, el delegate se ha asignado al controlador, pero podría ser cualquier clase, instanciada directamente en el controlador, o producto de algún patrón de creación.</p>

<p>Sin embargo, el Gran Dragón sabe que su Gran Maestro, hombre noble y de infinita sabiduría pero muy exigente, no va a ver con buenos ojos que haya declarado la referencia al delegate como id, sin más.</p>

<p>Objective-C soporta protocolos, por lo que el método que se va a delegar, podría estar declarado en un protocolo, en un protocolo informal en realidad. ¿Porqué informal? Porque de esa forma no se obliga a nadie que lo cumpla a que implemente todos los métodos declarados en el mismo.</p>

<p>Por cierto, El Gran Dragón sabe que su solución está un pelín obsoleta con la introducción de Objective-C 2.0, ya que los ingenieros de Apple recomiendan que en la nueva iteración del lenguaje no se utilicen protocolos informales, sino que prefieren que se utilicen protocolos formales con métodos opcionales.</p>

<p>No obstante, El Gran Dragón quiere terminar con el proyecto, porque fuera del templo brilla el sol y le apetece salir a hacer fotos, así que comienza por declarar el protocolo informal, en la cabecera de la vista:</p>

<p>@interface DNClickableView : NSView <br />
{<br />
	BOOL mouseIsPressingMe;<br />
	id  delegate;<br />
}</p>

<p>- (id) delegate;<br />
- (void) setDelegate: (id) newDelegate;</p>

<p>@end</p>

<p>@interface NSObject ( DNClickableViewDelegate )<br />
-(void) viewWasClicked;<br />
@end</p>

<p><br />
De esa forma, el compilador creerá que todos los objetos conforman ese protocolo, aunque en realidad, al ser informal, no tienen porqué implementar el método declarado en él.</p>

<p>El Gran Dragón está contento. Su subclase de NSView puede reutilizarse en todos los proyectos, porque no está vinculada a ningún controlador concreto, ni siquiera a un interfaz de éste, y lo que es mejor, la funcionalidad que se quiere asignar al click del ratón, que puede ser diferente en cada caso, puede estar encapsulada en una clase que se le proporciona a la vista, sin que ésta sepa nada de ella, ni de sus detalles de implementación, ni de su forma de creación.</p>

<p>El Gran Maestro, mientras tanto, mira orgulloso a su pupilo, pensando ya en el próximo reto...</p>]]>
        
    </content>
</entry>
<entry>
    <title>Instalación de git en Mac OS X 10.5 Leopard</title>
    <link rel="alternate" type="text/html" href="http://www.design-nation.net/es/archivos/003828.php" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.design-nation.net/cgi-bin/mt-atom.cgi/weblog/blog_id=3/entry_id=3828" title="Instalación de git en Mac OS X 10.5 Leopard" />
    <id>tag:www.design-nation.net,2008:/es//3.3828</id>
    
    <published>2008-01-06T13:21:52Z</published>
    <updated>2008-01-08T05:59:20Z</updated>
    
    <summary>Como estoy hasta el gorro de las peleas a brazo partido con Subversion, he decidido comenzar a utilizar git para los proyectos nuevos. La instalación de git en Leopard (Mac OS X 10.5.1) es muy sencilla. El primer paso es...</summary>
    <author>
        <name>Cesar Tardaguila</name>
        <uri>http://www.design-nation.net</uri>
    </author>
            <category term="Cocoa" />
            <category term="Flash-Actionscript" />
            <category term="General" />
            <category term="Java" />
    
    <content type="html" xml:lang="es" xml:base="http://www.design-nation.net/es/">
        <![CDATA[<p>Como estoy hasta el gorro de las peleas a brazo partido con Subversion, he decidido comenzar a utilizar <a href="http://git.or.cz/">git</a> para los proyectos nuevos.</p>

<p>La instalación de git en Leopard (Mac OS X 10.5.1) es muy sencilla. </p>

<p>El primer paso es descargar el tar con la última versión (a día de hoy la 1.5.3.7), y descomprimirlo (ya desde el Terminal):</p>

<p>tar xvzf git-1.5.3.7.tar.gz</p>

<p>A continuación, desde la carpeta generada al descomprimir el tar:</p>

<p>make configure<br />
./configure --prefix=/usr/local<br />
make all<br />
sudo make install</p>

<p>Y listo. Ya se pueden borrar tanto el tar como la carpeta donde éste se descomprimió.</p>]]>
        
    </content>
</entry>
<entry>
    <title>¡Al abordaje!</title>
    <link rel="alternate" type="text/html" href="http://www.design-nation.net/es/archivos/003827.php" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.design-nation.net/cgi-bin/mt-atom.cgi/weblog/blog_id=3/entry_id=3827" title="¡Al abordaje!" />
    <id>tag:www.design-nation.net,2007:/es//3.3827</id>
    
    <published>2007-12-10T05:26:47Z</published>
    <updated>2007-12-10T05:28:22Z</updated>
    
    <summary>Asunto espinoso éste del pirateo, pero que me apetece abordar ahora que veo los toros, al menos durante unas horas al día, desde el otro lado de la barrera. Partimos de la siguiente premisa: tengo una aplicación completa, y otra...</summary>
    <author>
        <name>Cesar Tardaguila</name>
        <uri>http://www.design-nation.net</uri>
    </author>
            <category term="Cocoa" />
            <category term="Flash-Actionscript" />
            <category term="General" />
            <category term="Java" />
            <category term="Mac" />
    
    <content type="html" xml:lang="es" xml:base="http://www.design-nation.net/es/">
        <![CDATA[<p>Asunto espinoso éste del pirateo, pero que me apetece abordar ahora que veo los toros, al menos durante unas horas al día, desde el otro lado de la barrera.</p>

<p>Partimos de la siguiente premisa: tengo <a href="http://bambooapps.com/fnd/">una aplicación completa</a>, y <a href="http://bambooapps.com/arriba/">otra en espera de poder ser lanzada</a>, que pretendo vender, a un precio que considero razonable, y que creo que es proporcionado para lo que la aplicación puede ofrecer y para la utilidad que se le puede extraer.</p>

<p><strong>Hay 10 tipos de personas: los que pagan por el software y los que no lo hacen.</strong></p>

<p>Recuerdo una conversación en la última Caverna de los Hombres Malos. Yo estaba hablando con el compañero de la mesa de al lado, porque había recibido una oferta de Adobe por la que me podía hacer con un Photoshop CS3 por dos perras (no recuerdo sin 50 euros, o algo así), y le estaba preguntando si le interesaba a él, cuando el compañero de dos mesas más allá, sin esperar respuesta, saltó con un sonoro "¿para qué pagar por algo que puedes tener gratis?"</p>

<p>Hay que asumir que hay quien nunca va a comprar tu programa, ni cualquier otro. Punto pelota. No importa el precio ni la lista de funcionalidades, ni si es fácil o no de usar. No importa nada. Hay quien nunca va a gastar dinero en software, y no importa el porqué de su decisión.</p>

<p>Contra eso no se puede hacer nada, ni siquiera entrar a juzgarlo, así que lo mejor es olvidarlo y seguir adelante.</p>

<p><strong>La condición humana</strong></p>

<p>Si embargo, que alguien no esté en el grupo anterior no implica que vaya a pagar por tu programa.</p>

<p>Obviamente, uno no está en la situación de poder hacer lo que hacen Adobe, Microsoft o Apple, y pedirle al usuario el dinero por adelantado, antes de que pruebe el software. Por eso, lo lógico, lo razonable, incluso lo mejor a largo plazo es llegar a un acuerdo claro y sencillo: yo te doy una copia de mi programa, tú la pruebas 30 días, y se te gusta lo que has visto me das 13 dólares. No me importa lo que hagas con el programa pasado ese tiempo, no me importa que lo uses en uno, dos, tres o treinta ordenadores. Obviamente, preferiría que si lo vas a usar en 30 ordenadores me pagaras 30 veces, pero tampoco me voy a meter en eso. </p>

<p>Es tuyo, haz con ello lo que quieras. El plan es sencillo y fácil de recordar, ¿no?</p>

<p>Sin embargo, el plan tiene un fallo. Y bastante grande, por cierto: el ser humano no es así. </p>

<p>Seguro que hay quien está pendiente de si el período de prueba termina o no, de si debe hacer el pago o no, pero lo más normal es que si el software no te da un empujoncito, y te recuerda de alguna forma cuál era el trato original, aquí no ocurra nada. </p>

<p>Pero darte un empujoncito no es lo mismo que pegarte cuatro tiros, no. Tal  y como yo lo entiendo, un empujoncito es decirte: han pasado los 30 días; si no me das un número de serie válido, me cierro. Si el programa recibe un número de serie que valide contra el algoritmo que lo generó, aquí no ha pasado nada, y si no lo recibe, aquí tampoco ha pasado nada; cada uno por su lado, y punto.</p>

<p>Pero hay que ser comedido. Obviamente, no es justificable tocar el sistema de archivos del usuario ni su configuración de arranque, ni hacer ninguna perrería. Simplemente, hay que asumir que la relación no ha funcionado, y salir de esa relación con la mejor disposición posible para iniciar la siguiente. Sin acritud.</p>

<p><strong>Poner puertas al campo</strong></p>

<p>Dice el refrán castellano que no se pueden poner puertas al campo. En el mundo en el que vivimos no se puede pretender crear una protección anticopia inviolable.</p>

<p>Por eso, y pese a que haya quien considera esto como una demostración de egolatría, cuando llega el momento de ponerse a pensar en cómo dar el empujón a tus usuarios para que hagan el desembolso deseado, hay que ser realista. ¿Hasta qué punto merece la pena complicarse intentando lo imposible?</p>

<p>En mi caso, el límite está claro. Hago lo necesario para que esas personas a las que habitualmente nos referimos como "usuarios medios" crean que su única salida para seguir usando la aplicación, una vez pasado el período de prueba, sea pagar. A partir de ahí, cualquier esfuerzo es en vano. Siempre va a haber alguien que va a encontrar la forma de romper cualquier muralla que yo crea haber construido.</p>

<p>Por eso, creo que no merece la pena intentar construir esa muralla, y sí dedicar parte de ese tiempo a implementar cosas útiles para los usuarios de la aplicación. Que para eso han pagado, por cierto.</p>

<p><strong>¿Pero eso no es dejar la puerta entreabierta?</strong></p>

<p>Todo depende de cómo se quiera mirar, imagino. Habrá quien diga que no intentar blindar tu aplicación contra cualquier contingencia es más bien poco coherente, porque en el fondo estás dejando la puerta abierta para que quien quiera, encuentre la forma de utilizarla. </p>

<p>Claro que, ¿quién dejaría esa puerta abierta? ¿Y para qué?</p>

<p><strong>No tiene por qué ser malo que tu aplicación sea pirateada</strong></p>

<p>Así de simple. En muchas circunstancias, es bueno que tu aplicación sea pirateada. Es una forma de tener usuarios, de aumentar tu distribución, o si se quiere llamar así, de ganar cuota de mercado.</p>

<p>No sería la primera vez que alguno de los grandes (¿alguien se acuerda de windows 2000?), por un supuesto error, deja al alcance de todo el mundo una copia de alguno de sus productos, mientras hace como que no se ha dado cuenta y como que está mirando a otro lado.</p>

<p>Lo malo es que eso no es mucho más ético que borrarle la carpeta del sistema a un usuario al que le ha caducado la trial. No se puede pedir dinero con una mano mientras con la otra haces lo posible para que la distribución aumente a base de ofrecerlo gratis en canales de distribución no oficiales.</p>

<p><strong>¿En qué quedamos entonces?</strong></p>

<p>Pues en que, para mí al menos, el usuario ideal es el que compra mi programa después de haberlo probado, y de haber comprobado que cumple sus expectativas, que le puede resultar útil, bien sea ahora mismo o bien en un futuro no muy lejano. El usuario que ha meditado su decisión, que no compra por impulso, con el que puedo contar para comenzar a construir una segunda versión de la aplicación y que probablemente me va a aportar muy buenas ideas sobre cómo se puede mejorar el programa.</p>

<p>Y a ese tipo de usuario hay que cuidarle, sin marearle con procesos de activación ni de validación de licencias complicados, sin limitarle el uso del programa, sin considerarle un ladrón a priori, confiando en él y dándole, en definitiva, libertad absoluta para utilizar el programa a su antojo. Que para eso ha pagado.</p>

<p>¿Lo demás? Lo demás me da igual. No me importa si mi aplicación termina en mininova, no me importa si hay cuarenta números de serie por ahí corriendo. Podría hacerlo sin mucho problema, pero no voy a bloquearlos en siguientes versiones. ¿Por qué? Porque no creo que me estén robando, ni que me estén haciendo perder dinero. ¿Qué dinero pierdo yo porque alguien use mi programa sin pagarme por ello? Ciertamente, dejo de ingresar algo, pero no ingresar no es lo mismo que ser robado.</p>

<p>No creo que se pueda luchar contra el pirateo, porque ni siquiera sé muy bien si hay algo contra lo que luchar, ni mucho menos que se deba luchar activamente contra ello.</p>

<p>Simplemente, quiero que, aquél que encuentre útil mi programa se plantee que es justo hacerme llegar algo de dinero tanto para compensar el esfuerzo realizado, como para animar a seguir realizándolo. Nada más y nada menos.</p>]]>
        
    </content>
</entry>
<entry>
    <title>FND 1.1</title>
    <link rel="alternate" type="text/html" href="http://www.design-nation.net/es/archivos/003826.php" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.design-nation.net/cgi-bin/mt-atom.cgi/weblog/blog_id=3/entry_id=3826" title="FND 1.1" />
    <id>tag:www.design-nation.net,2007:/es//3.3826</id>
    
    <published>2007-12-06T09:52:52Z</published>
    <updated>2007-12-06T09:55:08Z</updated>
    
    <summary> Una nota rápida para informar del lanzamiento de la versión 1.1 de FND. La lista de nuevas funcionalidades es corta: soporte para el Apple Remote. Sin embargo, la importancia del release, para mí al menos, no está en la...</summary>
    <author>
        <name>Cesar Tardaguila</name>
        <uri>http://www.design-nation.net</uri>
    </author>
            <category term="Cocoa" />
            <category term="Flash-Actionscript" />
            <category term="General" />
            <category term="Java" />
    
    <content type="html" xml:lang="es" xml:base="http://www.design-nation.net/es/">
        <![CDATA[<p>
Una nota rápida para informar del lanzamiento de la <a href="http://bambooapps.com/fnd/">versión 1.1 de FND</a>. 
</p><p>
La lista de nuevas funcionalidades es corta: soporte para el Apple Remote. Sin embargo, la importancia del release, para mí al menos, no está en la longitud de la lista de cambios respecto a la versión anterior, sino en que es el primer paso adelante en el roadmap previsto.
</p><p>
La nueva versión puede descargarse desde el mecanismo de actualización de la propia aplicación, o <a href="http://bambooapps.com/fnd/">directamente en bambooapps</a>.
</p>]]>
        
    </content>
</entry>

</feed> 