Vinicius Quaiato2012-09-20T07:35:42-07:00http://viniciusquaiato.com/Vinicius Quaiatovinicius.quaiato@gmail.comASP.NET MVC upload de imagens + JCrop + Resize + progressbar + tudo assíncrono 22012-08-03T00:00:00-07:00http://viniciusquaiato.com/blog/upload-imagens-jcrop-resize-progressbar-assincrono-2<h1>Colocando o JCrop para funcionar</h1>
<p>Dando continuidado ao post de <a href="http://viniciusquaiato.com/blog/upload-imagens-jcrop-resize-progressbar-assincrono/">Upload + Progressbar + JCrop assíncrono</a> agora nós
vamos fazer o download do <a href="http://deepliquid.com/content/Jcrop_Download.html">JCrop</a> e referenciá-lo em nossa view.
Descompacte o zip e referencie estes arquivos um javascript:</p>
<div class="highlight"><pre><code class="html"><span class="nt"><script </span><span class="na">src=</span><span class="s">'@Url.Content("~/Scripts/jquery.Jcrop.min.js")'</span> <span class="na">type=</span><span class="s">"text/javascript"</span><span class="nt">></script></span>
</code></pre>
</div>
<p>E um stylesheet:</p>
<div class="highlight"><pre><code class="html"><span class="nt"><link</span> <span class="na">rel=</span><span class="s">"stylesheet"</span> <span class="na">href=</span><span class="s">'@Url.Content("~/Content/jcrop/jquery.Jcrop.min.css")'</span> <span class="na">type=</span><span class="s">"text/css"</span> <span class="nt">/></span>
</code></pre>
</div>
<p>Feito isso vamos adicionar um novo formulário em nossa página. Eu optei por um novo formulário para deixar as coisas bem separadas, vejam abaixo:</p>
<div class="highlight"><pre><code class="html">@using (Html.BeginForm("Crop", "Upload", null, FormMethod.Post, new { enctype = "multipart/form-data", name = "crop" })) {
<span class="nt"><input</span> <span class="na">type=</span><span class="s">"hidden"</span> <span class="na">name=</span><span class="s">"url"</span> <span class="nt">/></span>
<span class="nt"><input</span> <span class="na">type=</span><span class="s">"hidden"</span> <span class="na">name=</span><span class="s">"x1"</span> <span class="na">id=</span><span class="s">"x1"</span> <span class="nt">/></span>
<span class="nt"><input</span> <span class="na">type=</span><span class="s">"hidden"</span> <span class="na">name=</span><span class="s">"x2"</span> <span class="na">id=</span><span class="s">"x2"</span> <span class="nt">/></span>
<span class="nt"><input</span> <span class="na">type=</span><span class="s">"hidden"</span> <span class="na">name=</span><span class="s">"y1"</span> <span class="na">id=</span><span class="s">"y1"</span> <span class="nt">/></span>
<span class="nt"><input</span> <span class="na">type=</span><span class="s">"hidden"</span> <span class="na">name=</span><span class="s">"y2"</span> <span class="na">id=</span><span class="s">"y2"</span> <span class="nt">/></span>
<span class="nt"><input</span> <span class="na">type=</span><span class="s">"submit"</span> <span class="na">value=</span><span class="s">"Recortar"</span> <span class="na">class=</span><span class="s">"hidden"</span> <span class="na">id=</span><span class="s">"recortar"</span> <span class="nt">/></span>
}
<span class="nt"><img</span> <span class="na">src=</span><span class="s">""</span> <span class="na">class=</span><span class="s">"hidden"</span> <span class="na">id=</span><span class="s">"imagem_final"</span><span class="nt">></img></span>
</code></pre>
</div>
<p>Reparem que tudo que temos aí são campos hidden. O primeiro deles irá guardar a URL da imagem que queremos recortar e com isso eu não farei o upload de uma nova imagem para o servidor. Os outros campos são as coordenadas para o recorte.</p>
<p>Todas estas informações serão alimentadas pelo javascript e pelo próprio JCrop. Vejam como configuraremos o JCrop:</p>
<div class="highlight"><pre><code class="html"><span class="lineno"> 1</span> function showCoords(c) {
<span class="lineno"> 2</span> $("#x1").val(c.x);
<span class="lineno"> 3</span> $("#x2").val(c.x2);
<span class="lineno"> 4</span> $("#y1").val(c.y);
<span class="lineno"> 5</span> $("#y2").val(c.y2);
<span class="lineno"> 6</span>
<span class="lineno"> 7</span> $("#recortar").removeClass("hidden");
<span class="lineno"> 8</span> }
<span class="lineno"> 9</span> function ativarJCrop() {
<span class="lineno">10</span> $('#imagem_crop').Jcrop({
<span class="lineno">11</span> bgColor: 'black',
<span class="lineno">12</span> bgOpacity: .4,
<span class="lineno">13</span> aspectRatio: 1,
<span class="lineno">14</span> onSelect: showCoords
<span class="lineno">15</span> });
<span class="lineno">16</span> }
</code></pre>
</div>
<p>Estas duas funções são tudo o que precisamos. E eu vou chamar a função <em>ativarJCrop</em> dentro do <em>success</em> do upload da imagem (<a href="http://viniciusquaiato.com/blog/upload-imagens-jcrop-resize-progressbar-assincrono/">confira aqui no artigo anterior</a>).</p>
<h1>Realizando o crop no servidor</h1>
<p>Para realizarmos o crop no servidor teremos algo parecido com isso:</p>
<div class="highlight"><pre><code class="csharp"><span class="lineno"> 1</span> <span class="na">[HttpPost]</span>
<span class="lineno"> 2</span> <span class="k">public</span> <span class="n">ActionResult</span> <span class="nf">Crop</span><span class="p">()</span> <span class="p">{</span>
<span class="lineno"> 3</span> <span class="kt">var</span> <span class="n">imagem_url</span> <span class="p">=</span> <span class="n">Request</span><span class="p">.</span><span class="n">Form</span><span class="p">[</span><span class="s">"url"</span><span class="p">];</span>
<span class="lineno"> 4</span> <span class="kt">var</span> <span class="n">x1</span> <span class="p">=</span> <span class="kt">int</span><span class="p">.</span><span class="n">Parse</span><span class="p">(</span><span class="n">Request</span><span class="p">.</span><span class="n">Form</span><span class="p">[</span><span class="s">"x1"</span><span class="p">]);</span>
<span class="lineno"> 5</span> <span class="kt">var</span> <span class="n">x2</span> <span class="p">=</span> <span class="kt">int</span><span class="p">.</span><span class="n">Parse</span><span class="p">(</span><span class="n">Request</span><span class="p">.</span><span class="n">Form</span><span class="p">[</span><span class="s">"x2"</span><span class="p">]);</span>
<span class="lineno"> 6</span> <span class="kt">var</span> <span class="n">y1</span> <span class="p">=</span> <span class="kt">int</span><span class="p">.</span><span class="n">Parse</span><span class="p">(</span><span class="n">Request</span><span class="p">.</span><span class="n">Form</span><span class="p">[</span><span class="s">"y1"</span><span class="p">]);</span>
<span class="lineno"> 7</span> <span class="kt">var</span> <span class="n">y2</span> <span class="p">=</span> <span class="kt">int</span><span class="p">.</span><span class="n">Parse</span><span class="p">(</span><span class="n">Request</span><span class="p">.</span><span class="n">Form</span><span class="p">[</span><span class="s">"y2"</span><span class="p">]);</span>
<span class="lineno"> 8</span> <span class="kt">var</span> <span class="n">nomeFinal</span> <span class="p">=</span> <span class="s">"../uploads/imagem_crop"</span> <span class="p">+</span> <span class="n">Path</span><span class="p">.</span><span class="n">GetExtension</span><span class="p">(</span><span class="n">imagem_url</span><span class="p">);</span>
<span class="lineno"> 9</span>
<span class="lineno">10</span> <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">response</span> <span class="p">=</span> <span class="k">new</span> <span class="n">StreamReader</span><span class="p">(</span><span class="n">Server</span><span class="p">.</span><span class="n">MapPath</span><span class="p">(</span><span class="n">imagem_url</span><span class="p">)))</span> <span class="p">{</span>
<span class="lineno">11</span> <span class="n">Bitmap</span> <span class="n">imagem</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Bitmap</span><span class="p">(</span><span class="n">response</span><span class="p">.</span><span class="n">BaseStream</span><span class="p">);</span>
<span class="lineno">12</span>
<span class="lineno">13</span> <span class="kt">int</span> <span class="n">largura</span> <span class="p">=</span> <span class="n">x2</span> <span class="p">-</span> <span class="n">x1</span><span class="p">;</span>
<span class="lineno">14</span> <span class="kt">int</span> <span class="n">altura</span> <span class="p">=</span> <span class="n">y2</span> <span class="p">-</span> <span class="n">y1</span><span class="p">;</span>
<span class="lineno">15</span>
<span class="lineno">16</span> <span class="n">Bitmap</span> <span class="n">target</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Bitmap</span><span class="p">(</span><span class="n">largura</span><span class="p">,</span> <span class="n">altura</span><span class="p">);</span>
<span class="lineno">17</span> <span class="n">Rectangle</span> <span class="n">cropRect</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Rectangle</span><span class="p">(</span><span class="n">x1</span><span class="p">,</span> <span class="n">y1</span><span class="p">,</span> <span class="n">largura</span><span class="p">,</span> <span class="n">altura</span><span class="p">);</span>
<span class="lineno">18</span>
<span class="lineno">19</span> <span class="k">using</span> <span class="p">(</span><span class="n">Graphics</span> <span class="n">g</span> <span class="p">=</span> <span class="n">Graphics</span><span class="p">.</span><span class="n">FromImage</span><span class="p">(</span><span class="n">target</span><span class="p">))</span> <span class="p">{</span>
<span class="lineno">20</span> <span class="n">g</span><span class="p">.</span><span class="n">DrawImage</span><span class="p">(</span><span class="n">imagem</span><span class="p">,</span> <span class="k">new</span> <span class="n">Rectangle</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">largura</span><span class="p">,</span> <span class="n">altura</span><span class="p">),</span> <span class="n">cropRect</span><span class="p">,</span> <span class="n">GraphicsUnit</span><span class="p">.</span><span class="n">Pixel</span><span class="p">);</span>
<span class="lineno">21</span> <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">fileStream</span> <span class="p">=</span> <span class="k">new</span> <span class="n">FileStream</span><span class="p">(</span><span class="n">Server</span><span class="p">.</span><span class="n">MapPath</span><span class="p">(</span><span class="n">nomeFinal</span><span class="p">),</span> <span class="n">FileMode</span><span class="p">.</span><span class="n">OpenOrCreate</span><span class="p">))</span> <span class="p">{</span>
<span class="lineno">22</span> <span class="n">target</span><span class="p">.</span><span class="n">Save</span><span class="p">(</span><span class="n">fileStream</span><span class="p">,</span> <span class="n">imagem</span><span class="p">.</span><span class="n">RawFormat</span><span class="p">);</span>
<span class="lineno">23</span> <span class="n">fileStream</span><span class="p">.</span><span class="n">Flush</span><span class="p">();</span>
<span class="lineno">24</span> <span class="p">}</span>
<span class="lineno">25</span> <span class="p">}</span>
<span class="lineno">26</span> <span class="p">}</span>
<span class="lineno">27</span>
<span class="lineno">28</span> <span class="k">return</span> <span class="nf">Json</span><span class="p">(</span><span class="k">new</span> <span class="p">{</span> <span class="n">imagem_recortada</span> <span class="p">=</span> <span class="n">nomeFinal</span> <span class="p">});</span>
<span class="lineno">29</span> <span class="p">}</span>
</code></pre>
</div>
<p>Basicamente o que esse código faz é recortar uma imagem. É um <em>código padrão</em> então vou vou explicá-lo. Reparem apenas que ao final retornamos um json. É com isto que exibiremos a imagem recortada após o trabalho do server.</p>
<p>Para isso vamos adicionar o <em>ajaxForm</em> ao nosso formulário de crop:</p>
<div class="highlight"><pre><code class="html"><span class="lineno"> 1</span> $('form[name=crop]').ajaxForm({
<span class="lineno"> 2</span> dataType: 'json',
<span class="lineno"> 3</span> success: function (data) {
<span class="lineno"> 4</span> jcrop.destroy();
<span class="lineno"> 5</span> $(".progress").addClass("hidden");
<span class="lineno"> 6</span> $("#imagem_crop").addClass("hidden");
<span class="lineno"> 7</span> $("#imagem_crop").removeAttr("style");
<span class="lineno"> 8</span> $("#recortar").addClass("hidden");
<span class="lineno"> 9</span>
<span class="lineno">10</span> $("#imagem_final").attr("src", data.imagem_recortada);
<span class="lineno">11</span> $("#imagem_final").removeClass("hidden");
<span class="lineno">12</span> }
<span class="lineno">13</span> });
</code></pre>
</div>
<p>Pronto! Agora tudo está feito e funcionando:</p>
<p><img src="/images_posts/upload-progressbar-assincrono-3.png" class="post_img"/>
<img src="/images_posts/upload-progressbar-assincrono-4.png" class="post_img"/></p>
<h1>Resumindo</h1>
<p>Com isso terminamos nosso upload e crop assíncrono com Jquery, JCrop e ASP.NET MVC.
Até que é uma tarefa simples depois de ter entendido tudo que é necessário. Eu fiz algumas firulas para esconder e exibir uma série de componentes na tela e tudo o mais, mas pode ser que vocês não precisem disso.</p>
<p>O código completo está no github <a href="https://github.com/vquaiato/upload-crop-async-sample">https://github.com/vquaiato/upload-crop-async-sample</a></p>
Rodando Nuget no Mono2012-07-20T00:00:00-07:00http://viniciusquaiato.com/blog/usando-nuget-com-mono<p>Fala galera, beleza? Esses dias eu quis experimentar o <a href="http://nuget.org/">Nuget</a>(com <a href="http://www.mono-project.com/Main_Page">Mono</a>) no meu Mac. Aparentemente não temos um console pro Nuget no <a href="http://monodevelop.com/">Monodevelop</a>, mas isso não é o que nos impediria de tentar já que o Nuget possui uma command-line tool certo?</p>
<h2>Baixando o Nuget</h2>
<p>A primeira coisa que fiz foi baixar a command-line tool do Nuget no codeplex <a href="http://nuget.codeplex.com/releases">http://nuget.codeplex.com/releases</a> <em>(sim vamos baixar um .exe mesmo)</em></p>
<h2>Rodando o Nuget</h2>
<p>Suponho que você já possui o <a href="http://www.mono-project.com/Main_Page">Mono</a> instalado em seu ambiente. Vamos abrir o terminal e digitar:</p>
<div class="highlight"><pre><code class="bash">mono NuGet.exe
</code></pre>
</div>
<p>Feito isso vamos receber um erro como esse:</p>
<blockquote><p>vquaiato [nuget_testes] $ mono NuGet.exe</p>
<p>WARNING: The runtime version supported by this application is unavailable.
Using default runtime: v2.0.50727</p>
<p>Unhandled Exception: System.TypeLoadException: Could not load type 'NuGet.Program' from assembly 'NuGet, Version=2.0.30619.9000, Culture=neutral, PublicKeyToken=null'.
[ERROR] FATAL UNHANDLED EXCEPTION: System.TypeLoadException: Could not load type 'NuGet.Program' from assembly 'NuGet, Version=2.0.30619.9000, Culture=neutral, PublicKeyToken=null'.</p></blockquote>
<p>Isso acontece pois o <a href="http://nuget.org/">Nuget</a> roda com a runtime 4.0 do .NET e o default do <a href="http://www.mono-project.com/Main_Page">Mono</a> é a runtime 2.0, mas isso é facilmente contornável:</p>
<div class="highlight"><pre><code class="bash">mono --runtime<span class="o">=</span>v4.0.30319 NuGet.exe
</code></pre>
</div>
<p>E o resultado disso deve ser parecido com isso:
<img src="/images_posts/rodando-nuget-com-mono.jpg" class="post_img" /></p>
<h2>Compilando o Mono</h2>
<p>Até aí tudo perfeito, se quisermos por exemplo procurar um pacote podemos digitar:</p>
<div class="highlight"><pre><code class="bash">mono --runtime<span class="o">=</span>v4.0.30319 NuGet.exe list nunit
</code></pre>
</div>
<p>E com isso teremos uma listagem de pacotes com o termo "nunit":
<img src="/images_posts/listando-pacotes-nuget-com-mono.png" class="post_img" /></p>
<p>O problema acontece quando tentamos instalar algum pacote:</p>
<div class="highlight"><pre><code class="bash">mono --runtime<span class="o">=</span>v4.0.30319 NuGet.exe install nunit
</code></pre>
</div>
<p>Obteremos um erro parecido com isso:</p>
<blockquote><p>vquaiato [nuget_testes] $ mono --runtime=v4.0.30319 NuGet.exe install nunit</p>
<p>Missing method System.Security.Cryptography.CryptoConfig::get_AllowOnlyFipsAlgorithms() in assembly /Library/Frameworks/Mono.framework/Versions/2.10.9/lib/mono/4.0/mscorlib.dll, referenced in assembly /Users/vquaiato/Projects/nuget_testes/NuGet.exe</p>
<p>Method not found: 'System.Security.Cryptography.CryptoConfig.get_AllowOnlyFipsAlgorithms'.</p></blockquote>
<p>O motivo é muito simples: este método não está implementado na versão de <strong><em>release</em></strong> atual do Mono!
Para <em>nossa alegria</em> este método já está implementado no <a href="https://github.com/mono/mono">github do Mono</a> há bastante tempo, então basta compilarmos o <a href="https://github.com/mono/mono">Mono usando o repositório do github</a>.</p>
<p>Eu assumo que você já possui uma versão do Mono(e do Git) instalada. Então vá ao terminal e digite:</p>
<div class="highlight"><pre><code class="bash">git clone git://github.com/mono/mono.git
<span class="nb">cd </span>mono
./autogen.sh --prefix<span class="o">=</span>/local-para-instalar-sua-versao-do-mono
make
</code></pre>
</div>
<p>O comando make pode demorar <strong><em>um pouco</em></strong>. Quando ele terminar:</p>
<div class="highlight"><pre><code class="bash">make install
</code></pre>
</div>
<p>Isso também pode <strong><em>demorar</em></strong>. Mas quando terminarmos poderemos finalmente baixar nossos pacotes utilizando o Nuget:</p>
<div class="highlight"><pre><code class="bash">/./local-onde-instalou-o-novo-mono/bin/mono NuGet.exe install MvcScaffolding
</code></pre>
</div>
<p>Neste caso estamos instalando o MVCScaffolding, veja que realmente ele baixa todas as dependências:
<img src="/images_posts/instalando-pacote-nuget-com-mono.jpg" class="post_img" /></p>
<h2>Deixando mais elegante</h2>
<p>Para deixarmos tudo mais elegante crie um script chamado <strong><em>nuget</em></strong> em um local que esteja no seu PATH:</p>
<div class="highlight"><pre><code class="bash"><span class="c">#!/bin/sh</span>
<span class="nb">exec</span> /local-onde-instalou-o-novo-mono/bin/mono --gc<span class="o">=</span>sgen /local-onde-colocou-o-nuget/NuGet.exe <span class="s2">"$@"</span>
</code></pre>
</div>
<p>Dê permissão de execução para esse script:</p>
<div class="highlight"><pre><code class="bash">chmod +x /local-onde-criou-o-script/nuget
</code></pre>
</div>
<p>Agora podemos digitar:</p>
<div class="highlight"><pre><code class="bash">nuget install nome-do-pacote
</code></pre>
</div>
<h2>Resumindo</h2>
<p>Bastante simples hein? A princípio pode assustar um pouco mas garanto que é tudo tranquilo.
Se você tiver alguma dúvida ou problema para compilar o Mono o README deles no github vai ajudar.
Bom é isso. Pra quem quiser (assim como eu) usar um pouco de .NET no Mac e usar as facilidades do Nuget.</p>
Usando UITableView em apps iOS2012-06-07T00:00:00-07:00http://viniciusquaiato.com/blog/usando-uitableview-em-apps-ios<p>Muitas aplicações fazem uso de listagens de dados e no iOS vamos usar uma(ou mais) instância de <a href="http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableView_Class/Reference/Reference.html">UITableView</a> para realizar este trabalho.</p>
<p>Basicamente quando falamos de iOS e table view estamos falando de um controle com uma única coluna e uma lista de dados (o motivo de haver apenas uma coluna é o tamanho das telas).</p>
<p>Para ilustrarmos um primeiro uso de UITableView vamos incrementar o projeto de <em>Gastos de rua</em> para exibir uma listagem dos gastos realizados. Faremos algumas alterações para isso:</p>
<ol>
<li>Criar um novo View Controller e um arquivo nib para nossa listagem</li>
<li>Adicionar um UITableView a este nib para exibir os valores</li>
<li>Exibir os valores na UITableView</li>
</ol>
<h2>Criando um novo ViewController</h2>
<p>Vamos adicionar um novo ViewController em nossa aplicação, chamado de <em>ListaDeValoresViewController</em>, assim como vemos abaixo:</p>
<p><img src="/images_posts/criando-classe.png" class="post_img" /></p>
<p><img src="/images_posts/escolhendo-classe-base-como-uiviewcontroller.png" class="post_img" /></p>
<p>Feito isso vamos adicionar um botão à nossa tela para que possamos exibir nossa nova tela:</p>
<p><img src="/images_posts/adicionando-botao.png" class="post_img" /></p>
<p>Vamos então adicionar um import em nosso ViewController.m para que possamos chamar a nova tela:</p>
<div class="highlight"><pre><code class="objc"><span class="cp">#import "ListaDeValoresViewController.h"</span>
</code></pre>
</div>
<p>Agora vamos criar uma <a href="http://viniciusquaiato.com/blog/ibaction-iboutlet-eventos-manipualcao-views-no-ios/">IBAction</a> vinculada ao nosso botão que fará a chamada para a nova tela.</p>
<p>ViewController.h:</p>
<div class="highlight"><pre><code class="objc"><span class="k">-</span> <span class="p">(</span><span class="kt">IBAction</span><span class="p">)</span><span class="nf">verListaDeValores:</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="nv">sender</span><span class="p">;</span>
</code></pre>
</div>
<p>ViewController.m:</p>
<div class="highlight"><pre><code class="objc"><span class="k">-</span> <span class="p">(</span><span class="kt">IBAction</span><span class="p">)</span><span class="nf">verListaDeValores:</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="nv">sender</span> <span class="p">{</span>
<span class="n">ListaDeValoresViewController</span><span class="o">*</span> <span class="n">lista</span> <span class="o">=</span> <span class="p">[[</span><span class="n">ListaDeValoresViewController</span> <span class="n">alloc</span><span class="p">]</span>
<span class="nl">initWithNibName:</span><span class="s">@"ListaDeValoresViewController"</span>
<span class="nl">bundle:</span><span class="nb">nil</span><span class="p">];</span>
<span class="p">[</span><span class="n">self</span> <span class="nl">presentViewController:</span><span class="n">lista</span> <span class="nl">animated:</span><span class="n">YES</span><span class="p">];</span>
<span class="p">}</span>
</code></pre>
</div>
<p>Feito isso se rodarmos nossa app e clicarmos no botão veremos uma nova tela branca.
A mágica aqui fica por conta da chamada <a href="http://developer.apple.com/library/ios/documentation/uikit/reference/UIViewController_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40006926-CH3-SW75"><em>presentViewController</em></a> que como podemos imaginar apresenta um view controller e no nosso caso o view controller que carrega a lista de valores. Nada de outro mundo certo?</p>
<h2>Utilizando UITableView</h2>
<p>Na nossa view ListaDeValores.xib vamos adicionat um <a href="http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableView_Class/Reference/Reference.html">UITableView</a>, conforme abaixo:</p>
<p><img src="/images_posts/adicionando-uitableview.png" class="post_img" /></p>
<p>Basta arrastar e redimensionar o controle.</p>
<p>O segredo aqui é que um UITableView precisa de alguém que implemente dois protocolos: <a href="http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UITableViewDelegate_Protocol/Reference/Reference.html"><em>UITableViewDelegate</em></a> e <a href="http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableViewDataSource_Protocol/Reference/Reference.html"><em>UITableViewDataSource</em></a>
Basicamente estes caras são responsáveis por gerenciar uma série de aspectos de um UITableView e seus dados. Mas nós começaremos com o básico, suficiente para exibir nossos dados na listagem.</p>
<p>Vamos então adicionar os protocolos em nosso ListaDeValoresViewController.h e além disso vamos criar um construtor que receba nosso objeto gastos, teremos então esse código:</p>
<div class="highlight"><pre><code class="objc"><span class="cp">#import <UIKit/UIKit.h></span>
<span class="cp">#import "Gastos.h"</span>
<span class="k">@interface</span> <span class="nc">ListaDeValoresViewController</span> : <span class="nc">UIViewController</span><span class="o"><</span><span class="n">UITableViewDelegate</span><span class="p">,</span> <span class="n">UITableViewDataSource</span><span class="o">></span>
<span class="p">{</span>
<span class="n">Gastos</span><span class="o">*</span> <span class="n">gastos</span><span class="p">;</span>
<span class="n">Locale</span><span class="o">*</span> <span class="n">locale</span><span class="p">;</span>
<span class="n">NSNumberFormatter</span><span class="o">*</span> <span class="n">formatter</span><span class="p">;</span>
<span class="p">}</span>
<span class="o">-</span> <span class="p">(</span><span class="kt">IBAction</span><span class="p">)</span><span class="nl">voltar:</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="n">sender</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">id</span><span class="p">)</span> <span class="nf">initWithNibAndGastos:</span><span class="p">(</span><span class="n">NSString</span><span class="o">*</span><span class="p">)</span><span class="nv">nib</span> <span class="o">:</span> <span class="p">(</span><span class="n">Gastos</span><span class="o">*</span><span class="p">)</span><span class="n">passedGastos</span><span class="p">;</span>
<span class="k">@end</span>
</code></pre>
</div>
<p>Tranquilo, certo? Tudo que fazemos aí é criar uma variável de instância do tipo <em>Gastos</em>, um <a href="http://viniciusquaiato.com/blog/formatacao-de-valores-em-reais-no-ios/">formatter e locale</a> para exibir tudo bacana e criamos um método que inicializará nossa classe com o nome do arquivo nib e os gastos recebidos: <em>initWithNibAndGastos</em>.</p>
<p>Agora vamos implementar alguns métodos no ListaDeValoresViewController.m</p>
<div class="highlight"><pre><code class="objc"><span class="lineno"> 1</span> <span class="k">-</span> <span class="p">(</span><span class="kt">id</span><span class="p">)</span> <span class="nf">initWithNibAndGastos:</span><span class="p">(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">nib</span> <span class="o">:</span><span class="p">(</span><span class="n">Gastos</span> <span class="o">*</span><span class="p">)</span><span class="n">passedGastos</span><span class="p">{</span>
<span class="lineno"> 2</span> <span class="n">self</span> <span class="o">=</span> <span class="p">[</span><span class="n">super</span> <span class="nl">initWithNibName:</span><span class="n">nib</span> <span class="nl">bundle:</span><span class="nb">nil</span><span class="p">];</span>
<span class="lineno"> 3</span> <span class="n">gastos</span> <span class="o">=</span> <span class="n">passedGastos</span><span class="p">;</span>
<span class="lineno"> 4</span>
<span class="lineno"> 5</span> <span class="n">locale</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSLocale</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithLocaleIdentifier:</span><span class="s">@"pt_BR"</span><span class="p">];</span>
<span class="lineno"> 6</span> <span class="n">formatter</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSNumberFormatter</span> <span class="n">alloc</span><span class="p">]</span><span class="n">init</span><span class="p">];</span>
<span class="lineno"> 7</span> <span class="p">[</span><span class="n">formatter</span> <span class="nl">setLocale:</span> <span class="n">locale</span><span class="p">];</span>
<span class="lineno"> 8</span> <span class="p">[</span><span class="n">formatter</span> <span class="nl">setNumberStyle:</span><span class="n">NSNumberFormatterCurrencyStyle</span><span class="p">];</span>
<span class="lineno"> 9</span>
<span class="lineno">10</span> <span class="k">return</span> <span class="n">self</span><span class="p">;</span>
<span class="lineno">11</span> <span class="p">}</span>
<span class="lineno">12</span>
<span class="lineno">13</span> <span class="c1">//Métodos para TableView</span>
<span class="lineno">14</span> <span class="o">-</span> <span class="p">(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nl">tableView:</span><span class="p">(</span><span class="n">UITableView</span> <span class="o">*</span><span class="p">)</span><span class="n">tableView</span> <span class="nl">titleForHeaderInSection:</span><span class="p">(</span><span class="n">NSInteger</span><span class="p">)</span><span class="n">section</span><span class="p">{</span>
<span class="lineno">15</span> <span class="k">return</span> <span class="s">@"Valores gastos"</span><span class="p">;</span>
<span class="lineno">16</span> <span class="p">}</span>
<span class="lineno">17</span> <span class="o">-</span> <span class="p">(</span><span class="n">NSInteger</span><span class="p">)</span><span class="nl">tableView:</span><span class="p">(</span><span class="n">UITableView</span> <span class="o">*</span><span class="p">)</span><span class="n">tableView</span> <span class="nl">numberOfRowsInSection:</span><span class="p">(</span><span class="n">NSInteger</span><span class="p">)</span><span class="n">section</span>
<span class="lineno">18</span> <span class="p">{</span>
<span class="lineno">19</span> <span class="k">return</span> <span class="p">[</span><span class="n">gastos</span> <span class="n">totalDeGastos</span><span class="p">];</span>
<span class="lineno">20</span> <span class="p">}</span>
<span class="lineno">21</span>
<span class="lineno">22</span> <span class="o">-</span> <span class="p">(</span><span class="n">UITableViewCell</span> <span class="o">*</span><span class="p">)</span><span class="nl">tableView:</span><span class="p">(</span><span class="n">UITableView</span> <span class="o">*</span><span class="p">)</span><span class="n">tableView</span> <span class="nl">cellForRowAtIndexPath:</span><span class="p">(</span><span class="n">NSIndexPath</span> <span class="o">*</span><span class="p">)</span><span class="n">indexPath</span>
<span class="lineno">23</span> <span class="p">{</span>
<span class="lineno">24</span> <span class="k">static</span> <span class="n">NSString</span> <span class="o">*</span><span class="n">CellIdentifier</span> <span class="o">=</span> <span class="s">@"Cell"</span><span class="p">;</span>
<span class="lineno">25</span>
<span class="lineno">26</span> <span class="n">UITableViewCell</span> <span class="o">*</span><span class="n">cell</span> <span class="o">=</span> <span class="p">[</span><span class="n">tableView</span> <span class="nl">dequeueReusableCellWithIdentifier:</span><span class="n">CellIdentifier</span><span class="p">];</span>
<span class="lineno">27</span> <span class="k">if</span> <span class="p">(</span><span class="n">cell</span> <span class="o">==</span> <span class="nb">nil</span><span class="p">)</span> <span class="p">{</span>
<span class="lineno">28</span> <span class="n">cell</span> <span class="o">=</span> <span class="p">[[</span><span class="n">UITableViewCell</span> <span class="n">alloc</span><span class="p">]</span>
<span class="lineno">29</span> <span class="nl">initWithStyle:</span><span class="n">UITableViewCellStyleDefault</span>
<span class="lineno">30</span> <span class="nl">reuseIdentifier:</span><span class="n">CellIdentifier</span><span class="p">];</span>
<span class="lineno">31</span> <span class="p">}</span>
<span class="lineno">32</span>
<span class="lineno">33</span> <span class="n">cell</span><span class="p">.</span><span class="n">textLabel</span><span class="p">.</span><span class="n">text</span> <span class="o">=</span> <span class="p">[</span><span class="n">formatter</span> <span class="nl">stringFromNumber:</span><span class="p">[</span><span class="n">gastos</span> <span class="nl">gastoAtIndex:</span><span class="n">indexPath</span><span class="p">.</span><span class="n">row</span><span class="p">]];</span>
<span class="lineno">34</span>
<span class="lineno">35</span> <span class="k">return</span> <span class="n">cell</span><span class="p">;</span>
<span class="lineno">36</span> <span class="p">}</span>
</code></pre>
</div>
<p>Vamos lá: das <strong><em>linhas 1 até 11</em></strong> o que fazemos é instanciar nosso view controller com o nome do nib informado e o objeto gastos passado. Também inicializamos um formatter para deixar nosso números bacanas na listagem (<a href="http://viniciusquaiato.com/blog/formatacao-de-valores-em-reais-no-ios/">já vimos sobre isso aqui</a>). Este método comporta-se como um construtor retornando a si mesmo após chamar um método da classe base.</p>
<p>Nas <strong><em>linhas 14 até 16</em></strong> apenas informamos um título para o header da nossa seção (lembre-se que temos apenas uma).</p>
<p>Nas <strong><em>linhas 17 até 20</em></strong> o que fazemos é informar quantas linhas teremos nesta seção da nossa table. Um UITableView pode possuir diversas seções, por enquanto temos apenas uma então informamos o total de gastos em nosso objeto.</p>
<p>Nas <strong><em>linhas 22 até 36</em></strong> é onde de fato criamos as células da nossa table view. O que precisamos entender aqui é que esse é um padrão para otimizar o uso de memória. Entenda que se só conseguimos mostrar umas 5 rows de cada vez em uma tela não é preciso criar todas as rows da table. Então as rows são reaproveitadas e teremos apenas 5 ao todo. Assuma que aí apenas a <strong><em>linha 33</em></strong> é o que muda. Nesta linha formatamos o texto que será exibido na row.</p>
<p>Antes de finalizarmos vamos vincular o datasource e o delegate de nossa table view ao nosso file owner (ou seja o view controller onde implementamos tudo):</p>
<p><img src="/images_posts/vinculando-datasource-e-delegate-ao-tableview.png" class="post_img" /></p>
<p>Feito! Agora quando adicionarmos alguns valores na nossa tela principal e clicarmos no botão para vermos a listagem teremos algo assim:</p>
<p><img src="/images_posts/app-ios-usando-uitableview.png" class="post_img" /></p>
<h2>Resumindo</h2>
<p>Novamente parece que tivemos um mega trabalho quando na verdade os passos foram bem simples e tranquilos se você ler e tentar fazer o mesmo com calma.</p>
<p>Com isso estamos conseguindo dar uma cara mais interessante para nossa simples aplicação e já começamos a abrir caminho para os próximos passos como por exemplo: navegação.</p>
<p>Sem dúvida alguma essa já é quase uma aplicação que pode nos ajudar: se pensarmos em ao invés de um array de valores criarmos um dicionário com data:[valores] a coisa começa a ficar mais interessante.</p>
<p>Tente ler a documentação dos protocolos relacionados com UITableView(<a href="http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UITableViewDelegate_Protocol/Reference/Reference.html"><em>UITableViewDelegate</em></a> e <a href="http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableViewDataSource_Protocol/Reference/Reference.html"><em>UITableViewDataSource</em></a>) e verá que não é nenhum bicho de outro mundo.</p>
<p><a href="https://github.com/vquaiato/ios-blog-samples/tree/master/somatorioDeContasTableView">https://github.com/vquaiato/ios-blog-samples/tree/master/somatorioDeContasTableView</a></p>
<p>Abração,</p>
<p>Vinicius Quaiato.</p>
Fechando o teclado nas apps iOS2012-06-02T00:00:00-07:00http://viniciusquaiato.com/blog/fechando-teclado-nas-apps-ios<p>Quando estamos digitando algo em uma app iOS e queremos que o teclado "suma" é realmente chato se não conseguirmos fazer isso na app. Por este motivo explico aqui algumas formas de realizar isso e não frustrar a experiência do usuário.</p>
<p>Existem algumas formas(que eu conheço) para escondermos o teclado quando estamos editando um UITextField.</p>
<p>Voud descrever então cada uma das 3 maneiras que eu conheço (e que pelo que já pesquisei têm sido as mais utilizadas e indicadas).</p>
<h2>UITextFieldDelegateProtocol</h2>
<p>Este <a href="http://developer.apple.com/library/ios/#documentation/uikit/reference/UITextFieldDelegate_Protocol/UITextFieldDelegate/UITextFieldDelegate.html">protocolo</a> define quais mensagens são enviadas para um UITextField delegate no processo de edição de algum texto.</p>
<p>Utilizando este protocolo nós podemos esconder o teclado pressionando o botão "concluído" do teclado.</p>
<p>Vamos pegar nosso <a href="http://viniciusquaiato.com/blog/criando-classes-em-objective-c/">projeto dos gastos de rua</a> e vamos mudá-lo.</p>
<p>Primeiro vamos alterar nossa arquivo ViewController.h adicionando o protocolo:</p>
<div class="highlight"><pre><code class="objc"><span class="lineno">1</span> <span class="k">@interface</span> <span class="nc">ViewController</span> : <span class="nc">UIViewController</span><span class="o"><</span><span class="n">UITextFieldDelegate</span><span class="o">></span>
<span class="lineno">2</span> <span class="p">{</span>
<span class="lineno">3</span> <span class="n">Gastos</span><span class="o">*</span> <span class="n">gastos</span><span class="p">;</span>
<span class="lineno">4</span> <span class="p">}</span>
</code></pre>
</div>
<p>Altere apenas este ponto adicionando o <em>UITextFieldDelegate</em></p>
<p>Feito isso vamos implementar o seguinte método no ViewController.m:</p>
<div class="highlight"><pre><code class="objc"><span class="lineno">1</span> <span class="k">-</span> <span class="p">(</span><span class="kt">BOOL</span><span class="p">)</span><span class="nf">textFieldShouldReturn:</span><span class="p">(</span><span class="n">UITextField</span> <span class="o">*</span><span class="p">)</span><span class="nv">textField</span>
<span class="lineno">2</span> <span class="p">{</span>
<span class="lineno">3</span> <span class="p">[</span><span class="n">textField</span> <span class="n">resignFirstResponder</span><span class="p">];</span>
<span class="lineno">4</span> <span class="k">return</span> <span class="n">NO</span><span class="p">;</span>
<span class="lineno">5</span> <span class="p">}</span>
</code></pre>
</div>
<p>Este método diz que o UITextField deve responder ao click(tap) do botão <em>concluído</em>. E o que fazemos nesse código é enviar a mensagem <a href="http://developer.apple.com/library/ios/DOCUMENTATION/UIKit/Reference/UIResponder_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40006783-CH4-SW7"><em>resignFirstResponder</em></a> para o nosso UITextField.</p>
<p>Esta mensagem diz para o textField que ele não é mais o firstResponder daquela janela, ou seja, ele não é mais quem está respondendo aos eventos (taps, touches, etc) que ocorrerem. E assim é que o teclado irá "sumir", pois o UITextField já não é mais esse responder.</p>
<p>Como último passo vamos informar que o delegate do nosso UITextField é o nosso view controller. Você pode fazer isso direto na interface:</p>
<p><img src="/images_posts/vinculando_delegate_uitextfield_com_file_owner.png" class="post_img" /></p>
<p>Feito isso quando rodarmos nossa aplicação e pressionarmos o botão "concluído" o teclado será fechado.</p>
<h2>UITapGestureRecognizer</h2>
<p><a href="http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIGestureRecognizer_Class/Reference/Reference.html#//apple_ref/occ/cl/UIGestureRecognizer">UITapGestureRecognizer</a> classe nada mais faz do que fichar "esperando" por eventos do tipo "tap" (single ou multiple taps). Com isso podemos pegar os taps que ocorrerem na nossa view e fechar o teclado aberto, vejamos como fazer isso.</p>
<p>Vamos então alterar nosso ViewController.m da seguinte maneira:</p>
<div class="highlight"><pre><code class="objc"><span class="lineno"> 1</span> <span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">viewDidLoad</span><span class="p">{</span>
<span class="lineno"> 2</span> <span class="p">[</span><span class="n">super</span> <span class="n">viewDidLoad</span><span class="p">];</span>
<span class="lineno"> 3</span>
<span class="lineno"> 4</span> <span class="n">gastos</span> <span class="o">=</span> <span class="p">[[</span><span class="n">Gastos</span> <span class="n">alloc</span><span class="p">]</span><span class="n">init</span><span class="p">];</span>
<span class="lineno"> 5</span>
<span class="lineno"> 6</span> <span class="n">UITapGestureRecognizer</span> <span class="o">*</span><span class="n">tap</span> <span class="o">=</span> <span class="p">[[</span><span class="n">UITapGestureRecognizer</span> <span class="n">alloc</span><span class="p">]</span>
<span class="lineno"> 7</span> <span class="nl">initWithTarget:</span><span class="n">self</span>
<span class="lineno"> 8</span> <span class="nl">action:</span><span class="k">@selector</span><span class="p">(</span><span class="n">esconderTeclado</span><span class="p">)];</span>
<span class="lineno"> 9</span>
<span class="lineno">10</span> <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">view</span> <span class="nl">addGestureRecognizer:</span><span class="n">tap</span><span class="p">];</span>
<span class="lineno">11</span> <span class="p">}</span>
<span class="lineno">12</span>
<span class="lineno">13</span> <span class="k">-</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">esconderTeclado</span> <span class="p">{</span>
<span class="lineno">14</span> <span class="p">[</span><span class="n">valorDoGasto</span> <span class="n">resignFirstResponder</span><span class="p">];</span>
<span class="lineno">15</span> <span class="p">}</span>
</code></pre>
</div>
<p>Basicamente o que estamos fazendo é criando um tap recognizer informando para ele que quem vai receber as mensagens quando os taps ocorrerem, nesse caso o próprio viewcontroller como podem ver na <strong><em>linha 7</em></strong>.
Na <strong><em>linha 8</em></strong> o que fazemos é informar um método que será chamado quando o recognizer reconhecer um tap. Neste caso o método é o <em>esconderTeclado</em> que criamos nas <strong><em>linhas 13 a 15</em></strong>.
Na <strong><em>linha 10</em></strong> novamente enviamos a mensagem de <em>resignFirstResponder</em> ao nosso UITextField.</p>
<h2>TouchesBegan</h2>
<p>A terceira forma - e ao que parece uma das mais utilizadas - é fazer um <em>override</em> do método <a href="http://developer.apple.com/library/ios/DOCUMENTATION/UIKit/Reference/UIResponder_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40006783-CH4-SW1"><em>touchesBegan</em></a>.</p>
<p>Este método informa quando um ou mais toques sào feitos em uma window ou view.</p>
<p>Neste caso o que faremos é simplesmente enviar a mensagem <em>resignFirstResponder</em> quando um toque na view for feito:</p>
<div class="highlight"><pre><code class="objc"><span class="lineno">1</span> <span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">touchesBegan:</span><span class="p">(</span><span class="n">NSSet</span> <span class="o">*</span><span class="p">)</span><span class="nv">touches</span> <span class="nf">withEvent:</span><span class="p">(</span><span class="n">UIEvent</span> <span class="o">*</span><span class="p">)</span><span class="nv">event</span>
<span class="lineno">2</span> <span class="p">{</span>
<span class="lineno">3</span> <span class="p">[</span><span class="n">valorDoGasto</span> <span class="n">resignFirstResponder</span><span class="p">];</span>
<span class="lineno">4</span>
<span class="lineno">5</span> <span class="p">[</span><span class="n">super</span> <span class="nl">touchesBegan:</span><span class="n">touches</span> <span class="nl">withEvent:</span><span class="n">event</span><span class="p">];</span>
<span class="lineno">6</span> <span class="p">}</span>
</code></pre>
</div>
<p>Bastante simples. A única coisa diferente aqui é repassar o evento para a classe base na <strong><em>linha 5</em></strong> após fazermos o que precisávamos fazer na <strong><em>linha 3</em></strong>.</p>
<h2>Resumindo</h2>
<p>Estas são as três maneiras que eu conheço para fazermos o "teclado sumir" enquanto estivermos trabalhando com UITextFields.</p>
<p>O código do projeto de gastos de rua já está atualizado no <a href="https://github.com/vquaiato/ios-blog-samples">github</a> com essas melhorias.</p>
<p>Abraços,</p>
<p>Vinicius Quaiato.</p>
Formatação de valores em Reais(R$) no iOS2012-05-22T00:00:00-07:00http://viniciusquaiato.com/blog/formatacao-de-valores-em-reais-no-ios<p>Já que começamos a criar uma app que lida com valores monetários precisamos garantir que a nossa aplicação exiba corretamente os dados.
<em><a href="http://viniciusquaiato.com/tags/ios/">(confira todos os posts sobre iOS)</a></em></p>
<h2>Formatando valores em Reais R$</h2>
<p>Vamos formatar nosso valor de acordo com uma cultura específica, no nosso caso pt-BR, para deixarmos nosso valores monetário em Reais. Modificando um pouco nosso método addGasto (<a href="http://viniciusquaiato.com/blog/criando-classes-em-objective-c">do projeto anterior</a>) teremos isso:</p>
<div class="highlight"><pre><code class="objc"><span class="lineno"> 1</span> <span class="k">-</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">addGasto:</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="nv">sender</span><span class="p">{</span>
<span class="lineno"> 2</span> <span class="p">[</span><span class="n">gastos</span> <span class="nl">addGastoFromString:</span> <span class="n">valorDoGasto</span><span class="p">.</span><span class="n">text</span><span class="p">];</span>
<span class="lineno"> 3</span> <span class="n">valorDoGasto</span><span class="p">.</span><span class="n">text</span> <span class="o">=</span> <span class="s">@""</span><span class="p">;</span>
<span class="lineno"> 4</span>
<span class="lineno"> 5</span> <span class="n">numeroDeGastos</span><span class="p">.</span><span class="n">text</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSString</span> <span class="nl">stringWithFormat:</span><span class="s">@"%i"</span><span class="p">,</span> <span class="p">[</span><span class="n">gastos</span> <span class="n">totalDeGastos</span><span class="p">]];</span>
<span class="lineno"> 6</span>
<span class="lineno"> 7</span> <span class="kt">id</span> <span class="n">somatorioGastos</span> <span class="o">=</span> <span class="p">[</span><span class="n">gastos</span> <span class="n">somaDosGastos</span><span class="p">];</span>
<span class="lineno"> 8</span>
<span class="lineno"> 9</span> <span class="n">NSNumberFormatter</span> <span class="o">*</span><span class="n">formatter</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSNumberFormatter</span> <span class="n">alloc</span><span class="p">]</span><span class="n">init</span><span class="p">];</span>
<span class="lineno">10</span> <span class="p">[</span><span class="n">formatter</span> <span class="nl">setNumberStyle:</span><span class="n">NSNumberFormatterCurrencyStyle</span><span class="p">];</span>
<span class="lineno">11</span> <span class="n">NSLocale</span> <span class="o">*</span><span class="n">locale</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSLocale</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithLocaleIdentifier:</span><span class="s">@"pt_BR"</span><span class="p">];</span>
<span class="lineno">12</span> <span class="p">[</span><span class="n">formatter</span> <span class="nl">setLocale:</span> <span class="n">locale</span><span class="p">];</span>
<span class="lineno">13</span>
<span class="lineno">14</span> <span class="n">totalDosGastos</span><span class="p">.</span><span class="n">text</span> <span class="o">=</span> <span class="p">[</span><span class="n">formatter</span> <span class="nl">stringFromNumber:</span><span class="n">somatorioGastos</span><span class="p">];</span>
<span class="lineno">15</span> <span class="p">}</span>
</code></pre>
</div>
<p>A novidade aí está na <strong><em>linha 9</em></strong> onde criamos um objeto <a href="https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSNumberFormatter_Class/Reference/Reference.html">NSNumberFormatter</a>. Esta classe fornece uma séria de configurações para formatarmos números: separadores decimais, separadores de milhar, porcentagem, códigos monetários, formatos, etc.</p>
<p>Na <strong><em>linha 10</em></strong> configuramos este formatador como um formatador monetário.
Nas <strong><em>linhas 11 e 12</em></strong> é que está nosso segredo: criamos um objeto <a href="https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSLocale_Class/Reference/Reference.html">NSLocale</a> utilizando um locale identifier, no nosso caso pt-BR. Depois de criado nosso objeto nós configuramos o locale no nosso formatter.</p>
<p>Feito isso na <strong><em>linha 14</em></strong> apenas obtemos o número formatado passando a mensagem <em>stringFromNumber</em> para nosso formatador e colocamos o mesmo em nosso label, como vemos abaixo:</p>
<p><img src="/images_posts/exibindo-valor-formatado-em-reais-ios.png" class="post_img" /></p>
<h2>Resumo</h2>
<p>A formatação de valores é algo que sempre consome um pouco, mas não é nenhum bicho de set cabeças nesse caso. Se encapsularmos isso em um método que recebe um valor e retorna uma string formatada fica tudo bastante simples (no código completo do github isso está em um método separado).</p>
<p>Como internacionalização é um assunto mais abrangente preferi deixar para o futuro :P</p>
<p>Como sempre o código do projeto está no github: <a href="https://github.com/vquaiato/ios-blog-samples/tree/master/somatorioDeContasLocale">https://github.com/vquaiato/ios-blog-samples/tree/master/somatorioDeContasLocale</a></p>
Criando classes e usando models em Objective-C e iOS2012-05-21T00:00:00-07:00http://viniciusquaiato.com/blog/criando-classes-em-objective-c<p>Antes de irmos para o próximo passo dentro do desenvolvimento iOS vamos começar a trabalhar um pouco o objective-c.
<em><a href="http://viniciusquaiato.com/tags/ios/">(confira todos os posts sobre iOS)</a></em></p>
<p>Vamos criar uma classe para servir como model para nossa aplicação.</p>
<h2>Criando nossas classes em Objective-c</h2>
<p>Criar uma classe em objective-c não é nada diferente do que já vimos aqui nos outros projetos. Vamos criar os nossos dois arquivos .h e .m assim como nos outros projetos.</p>
<p>Para efeito de estudos vamos criar uma aplicação para computar os gastos que fazemos na rua (o cafezinho, o almoço, o jornal, etc, etc).</p>
<p>Depois de criar um projeto(Single View Application mesmo), vamos adicionar um novo arquivo ao projeto, uma classe objective-c:
<img src="/images_posts/objc-class.jpg" class="post_img" /></p>
<p>Essa nossa classe vai ser algo parecido com:</p>
<div class="highlight"><pre><code class="objc"><span class="lineno"> 1</span> <span class="cp">#import <Foundation/Foundation.h></span>
<span class="lineno"> 2</span> <span class="cp">#import <UIKit/UIKit.h></span>
<span class="lineno"> 3</span>
<span class="lineno"> 4</span> <span class="k">@interface</span> <span class="nc">Gastos</span> : <span class="nc">NSObject</span>
<span class="lineno"> 5</span> <span class="p">{</span>
<span class="lineno"> 6</span> <span class="n">NSMutableArray</span><span class="o">*</span> <span class="n">gastos</span><span class="p">;</span>
<span class="lineno"> 7</span> <span class="p">}</span>
<span class="lineno"> 8</span>
<span class="lineno"> 9</span> <span class="o">-</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nl">addGastoFromString:</span> <span class="p">(</span><span class="n">NSString</span><span class="o">*</span><span class="p">)</span> <span class="n">valorGasto</span><span class="p">;</span>
<span class="lineno">10</span> <span class="k">-</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="nf">totalDeGastos</span><span class="p">;</span>
<span class="lineno">11</span> <span class="k">-</span><span class="p">(</span><span class="n">NSDecimalNumber</span><span class="o">*</span><span class="p">)</span> <span class="nf">somaDosGastos</span><span class="p">;</span>
<span class="lineno">12</span> <span class="k">@end</span>
</code></pre>
</div>
<p>O que essa classe vai fazer? Ela possui um array que nada mais é que um array dos valores dos gastos. Repare que este é um <a href="https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSMutableArray_Class/Reference/Reference.html">NSMutableArray</a>, ou seja conseguiremos adicionar valores independente do tamanho do array.</p>
<p>Reparem que assim como em .NET tudo "herda" de Object aqui nossa classe herda de <a href="https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsobject_Class/Reference/Reference.html">NSObject</a>. Por ser a classe base da maioria das classes em objective-c ela provê uma série de comportamentos aos objetos (muito além do ToString, GetType e GetHashCode no .NET). <a href="https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsobject_Class/Reference/Reference.html">Confira a documentação de NSObject aqui</a>. É de NSObject por exemplo que vem o método <a href="https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/nsobject_Class/Reference/Reference.html#//apple_ref/doc/uid/20000050-alloc">alloc que utilizamos na maioria das nossas classes</a>.</p>
<p>Temos 3 métodos um que iremos implementar:
Na <strong><em>linha 9</em></strong> é um método que irá adicionar um gasto a partir de uma string. Na <strong><em>linha 10</em></strong> é apenas um método para obtermos quantos gastos foram realizados e na <strong><em>linha 11</em></strong> uma soma dos gastos realizados.</p>
<p>A implementação da nossa classe é bastante simples também:</p>
<div class="highlight"><pre><code class="objc"><span class="lineno"> 1</span> <span class="cp">#import "Gastos.h"</span>
<span class="lineno"> 2</span>
<span class="lineno"> 3</span> <span class="k">@implementation</span> <span class="nc">Gastos</span>
<span class="lineno"> 4</span>
<span class="lineno"> 5</span> <span class="k">-</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="nf">init</span><span class="p">{</span>
<span class="lineno"> 6</span> <span class="n">gastos</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSMutableArray</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">];</span>
<span class="lineno"> 7</span>
<span class="lineno"> 8</span> <span class="k">return</span> <span class="n">self</span><span class="p">;</span>
<span class="lineno"> 9</span> <span class="p">}</span>
<span class="lineno">10</span> <span class="k">-</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">addGastoFromString:</span><span class="p">(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">valorGasto</span><span class="p">{</span>
<span class="lineno">11</span> <span class="n">NSDecimalNumber</span><span class="o">*</span> <span class="n">valor</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSDecimalNumber</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithFloat:</span> <span class="p">[</span><span class="n">valorGasto</span> <span class="n">floatValue</span><span class="p">]];</span>
<span class="lineno">12</span>
<span class="lineno">13</span> <span class="p">[</span><span class="n">gastos</span> <span class="nl">addObject:</span><span class="n">valor</span><span class="p">];</span>
<span class="lineno">14</span> <span class="p">}</span>
<span class="lineno">15</span> <span class="k">-</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="nf">totalDeGastos</span><span class="p">{</span>
<span class="lineno">16</span> <span class="k">return</span> <span class="n">gastos</span><span class="p">.</span><span class="n">count</span><span class="p">;</span>
<span class="lineno">17</span> <span class="p">}</span>
<span class="lineno">18</span> <span class="k">-</span><span class="p">(</span><span class="n">NSDecimalNumber</span><span class="o">*</span><span class="p">)</span> <span class="nf">somaDosGastos</span><span class="p">{</span>
<span class="lineno">19</span> <span class="n">NSDecimalNumber</span> <span class="o">*</span><span class="n">sum</span> <span class="o">=</span> <span class="p">[</span><span class="n">gastos</span> <span class="nl">valueForKeyPath:</span><span class="s">@"@sum.floatValue"</span><span class="p">];</span>
<span class="lineno">20</span>
<span class="lineno">21</span> <span class="k">return</span> <span class="n">sum</span><span class="p">;</span>
<span class="lineno">22</span> <span class="p">}</span>
<span class="lineno">23</span> <span class="k">@end</span>
</code></pre>
</div>
<p>Vamos lá: nas <strong><em>linhas 5 até 9</em></strong> temos o "construtor" da nossa classe. O que fazemos é alocar e iniciar nosso <a href="https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSMutableArray_Class/Reference/Reference.html">NSMutableArray</a>. Retornamos o próprio objeto no "construtor".
Nas linhas 10 a 14 temos o método que recebe uma string (vinda da interface gráfica) e criamos um <a href="https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSDecimalNumber_Class/Reference/Reference.html">NSDecimalNumber</a>, iniciando com o valor como float.</p>
<p><em>(confesso que eu fiz algumas pesquisas e não encontrei uma forma muito canônica de manipular valores decimais e monetários, então estou usando assim a princípio)</em></p>
<p>Nas <strong><em>linhas 18 até 22</em></strong> temos o método que faz a soma dos nossos gastos. Esse método é bastante curioso e interessante. Ele faz uso de um recurso chamado <a href="http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/KeyValueCoding/Articles/CollectionOperators.html">Collection operators</a>. Basicamente usa-se um operador: @sum, @avg, @max, @min, @count <a href="http://developer.apple.com/library/ios/documentation/cocoa/conceptual/KeyValueCoding/Articles/CollectionOperators.html#//apple_ref/doc/uid/20002176-SW6">e outros(veja todos)</a>.
O que fazemos então é somar o floatValue de cada um dos elementos e retornamos isso em um <a href="https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSDecimalNumber_Class/Reference/Reference.html">NSDecimalNumber</a>.</p>
<h2>Criando nossa interface</h2>
<p>A interface desta nossa app será bastante simples (iremos evoluí-la em posts futuros). Vamos criar algo parecido com isso:</p>
<p><img src="/images_posts/interface-gastos-ios-app.png" class="post_img" /></p>
<p>Para que o botão fique parecido com isso selecione a propriedade <em>type</em> do nosso UIButton:</p>
<p><img src="/images_posts/add-contact-button-ios.jpg" class="post_img" /></p>
<p>A implementação disso é bastante tranquila também, já que a lógica toda está na classe Gastos. Veja o .h do nosso ViewController como ficou:</p>
<div class="highlight"><pre><code class="objc"><span class="lineno"> 1</span> <span class="cp">#import <UIKit/UIKit.h></span>
<span class="lineno"> 2</span> <span class="cp">#import "Gastos.h"</span>
<span class="lineno"> 3</span>
<span class="lineno"> 4</span> <span class="k">@interface</span> <span class="nc">ViewController</span> : <span class="nc">UIViewController</span>
<span class="lineno"> 5</span> <span class="p">{</span>
<span class="lineno"> 6</span> <span class="n">Gastos</span><span class="o">*</span> <span class="n">gastos</span><span class="p">;</span>
<span class="lineno"> 7</span> <span class="p">}</span>
<span class="lineno"> 8</span>
<span class="lineno"> 9</span> <span class="o">-</span><span class="p">(</span><span class="kt">IBAction</span><span class="p">)</span><span class="nl">addGasto:</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="n">sender</span><span class="p">;</span>
<span class="lineno">10</span>
<span class="lineno">11</span> <span class="k">@property</span> <span class="p">(</span><span class="n">nonatomic</span><span class="p">,</span><span class="n">retain</span><span class="p">)</span> <span class="kt">IBOutlet</span> <span class="n">UILabel</span><span class="o">*</span> <span class="n">totalDosGastos</span><span class="p">;</span>
<span class="lineno">12</span> <span class="k">@property</span> <span class="p">(</span><span class="n">nonatomic</span><span class="p">,</span><span class="n">retain</span><span class="p">)</span> <span class="kt">IBOutlet</span> <span class="n">UILabel</span><span class="o">*</span> <span class="n">numeroDeGastos</span><span class="p">;</span>
<span class="lineno">13</span> <span class="k">@property</span> <span class="p">(</span><span class="n">nonatomic</span><span class="p">,</span><span class="n">retain</span><span class="p">)</span> <span class="kt">IBOutlet</span> <span class="n">UITextField</span><span class="o">*</span> <span class="n">valorDoGasto</span><span class="p">;</span>
<span class="lineno">14</span> <span class="k">@end</span>
</code></pre>
</div>
<p>Tranquilo né? Uma action que será disparada pelo botão e três outlets que serão ligados aos elementos da nossa ui: UITextfield e os dois UILabel.</p>
<p>E a implementação do nosso ViewController fica assim:</p>
<div class="highlight"><pre><code class="objc"><span class="lineno"> 1</span> <span class="cp">#import "ViewController.h"</span>
<span class="lineno"> 2</span> <span class="cp">#import "Gastos.h"</span>
<span class="lineno"> 3</span>
<span class="lineno"> 4</span> <span class="k">@interface</span> <span class="nc">ViewController</span> <span class="p">()</span>
<span class="lineno"> 5</span> <span class="k">@end</span>
<span class="lineno"> 6</span>
<span class="lineno"> 7</span> <span class="err">@</span><span class="n">implementation</span> <span class="n">ViewController</span>
<span class="lineno"> 8</span>
<span class="lineno"> 9</span> <span class="k">@synthesize</span> <span class="n">valorDoGasto</span><span class="p">;</span>
<span class="lineno">10</span> <span class="k">@synthesize</span> <span class="n">numeroDeGastos</span><span class="p">;</span>
<span class="lineno">11</span> <span class="k">@synthesize</span> <span class="n">totalDosGastos</span><span class="p">;</span>
<span class="lineno">12</span>
<span class="lineno">13</span> <span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">viewDidLoad</span><span class="p">{</span>
<span class="lineno">14</span> <span class="p">[</span><span class="n">super</span> <span class="n">viewDidLoad</span><span class="p">];</span>
<span class="lineno">15</span>
<span class="lineno">16</span> <span class="n">gastos</span> <span class="o">=</span> <span class="p">[[</span><span class="n">Gastos</span> <span class="n">alloc</span><span class="p">]</span><span class="n">init</span><span class="p">];</span>
<span class="lineno">17</span> <span class="p">}</span>
<span class="lineno">18</span>
<span class="lineno">19</span> <span class="k">-</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">addGasto:</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="nv">sender</span><span class="p">{</span>
<span class="lineno">20</span> <span class="p">[</span><span class="n">gastos</span> <span class="nl">addGastoFromString:</span> <span class="n">valorDoGasto</span><span class="p">.</span><span class="n">text</span><span class="p">];</span>
<span class="lineno">21</span> <span class="n">valorDoGasto</span><span class="p">.</span><span class="n">text</span> <span class="o">=</span> <span class="s">@""</span><span class="p">;</span>
<span class="lineno">22</span>
<span class="lineno">23</span> <span class="n">numeroDeGastos</span><span class="p">.</span><span class="n">text</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSString</span> <span class="nl">stringWithFormat:</span><span class="s">@"%i"</span><span class="p">,</span> <span class="p">[</span><span class="n">gastos</span> <span class="n">totalDeGastos</span><span class="p">]];</span>
<span class="lineno">24</span>
<span class="lineno">25</span> <span class="n">totalDosGastos</span><span class="p">.</span><span class="n">text</span> <span class="o">=</span> <span class="p">[[</span><span class="n">gastos</span> <span class="n">somaDosGastos</span><span class="p">]</span><span class="n">stringValue</span><span class="p">];</span>
<span class="lineno">26</span> <span class="p">}</span>
<span class="lineno">27</span>
<span class="lineno">28</span> <span class="c1">//MÉTODOS GERADOS</span>
<span class="lineno">29</span> <span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">viewDidUnload</span><span class="p">{</span>
<span class="lineno">30</span> <span class="p">[</span><span class="n">super</span> <span class="n">viewDidUnload</span><span class="p">];</span>
<span class="lineno">31</span> <span class="p">}</span>
<span class="lineno">32</span> <span class="k">-</span> <span class="p">(</span><span class="kt">BOOL</span><span class="p">)</span><span class="nf">shouldAutorotateToInterfaceOrientation:</span><span class="p">(</span><span class="n">UIInterfaceOrientation</span><span class="p">)</span><span class="nv">interfaceOrientation</span><span class="p">{</span>
<span class="lineno">33</span> <span class="k">return</span> <span class="p">(</span><span class="n">interfaceOrientation</span> <span class="o">!=</span> <span class="n">UIInterfaceOrientationPortraitUpsideDown</span><span class="p">);</span>
<span class="lineno">34</span> <span class="p">}</span>
<span class="lineno">35</span> <span class="k">@end</span>
</code></pre>
</div>
<p>Nas <strong><em>linhas 9 até 11</em></strong> sintetizamos nossas propriedades, ou seja, os outlets que declaramos.
Na <strong><em>linha 16</em></strong> nós iniciamos nosso variável gastos. Fazemos isso da maneira padrão com alloc e init.
Nas <strong><em>linhas 19 até 26</em></strong> temos nosso addConta onde realizamos toda lógica do nosso controller: <strong><em>linha 20</em></strong> adicionamos o valor do campo de texto aos gastos, <strong><em>linha 21</em></strong> limpamos o nosso campo texto. obtemos o número de gastos que já adicionamos para exibir no label. <strong><em>Linha 23</em></strong> formatamos a string com o total de gastos. E na <strong><em>linha 25</em></strong> obtemos o somatório dos gastos e colocamos no label da interface.</p>
<p>Rodando nossa app teremos:</p>
<p><img src="/images_posts/controle-gastos-rua-ios-app.png" class="post_img" /></p>
<p><img src="/images_posts/controle-gastos-rua-ios-app-2.png" class="post_img" /></p>
<h2>Resumo</h2>
<p>Estamos avançando a bons passos no conhecimento do iOS. Com essa nossa classe já podemos imaginar implementar algum tipo de persistência para estes dados(Core Data, alguma API de serviço externo, etc) e com isso tornar nossa aplicação mais usável.
Também abrimos uma brecha para a necessidade de começar a criar navegações, formatações e até internacionalização de nossas aplicações.</p>
<p>Começamos a ver coisas interessantes que é a manipulação de valores financeiros (e percebemos que temos muito mais para explorar nesse sentido).</p>
<p>A idéia é começar a avançar em nevegação nos próximos posts, mas pode ser que façamos uma pausa para internacionalizar, formatar e tratar erros e detalhes de interface :D</p>
<p>Não sei se alguém que lê isso aqui está de fato brincando com iOS, mas a cada momento fico mais confortável com a plataforma com o um todo (e olhem que não estou fazendo nada além do que um estagiário faria :P)</p>
<p>O código deste projeto já está no github também: <a href="https://github.com/vquaiato/ios-blog-samples/tree/master/somatorioDeContas">https://github.com/vquaiato/ios-blog-samples/tree/master/somatorioDeContas</a></p>
<p>Abração,
Vinicius Quaiato.</p>
IBAction e IBOutlets: eventos e manipulação de views no iOS2012-05-18T00:00:00-07:00http://viniciusquaiato.com/blog/ibaction-iboutlet-eventos-manipualcao-views-no-ios<p>Na nossa <a href="http://viniciusquaiato.com/blog/primeiro-projeto-ios-single-view-application/">aplicação Hello World</a>, dentre as muitas coisas novas e diferentes que vimos uma das mais estranhas foi a vinculação de um método com o toque do botão.
<em><a href="http://viniciusquaiato.com/tags/ios/">(confira todos os posts sobre iOS)</a></em></p>
<h2>IBAction e Target-Action</h2>
<p>Target-Action é o nome do "padrão" ou mecanismo que o iOS utiliza para lidar com eventos.</p>
<p>Na verdade os eventos são disparados, ou gerados, mas alguém que esteja interessado em receber mensagens destes eventos precisa ser avisado disso. Neste caso quem vai receber a mensagem é o que é chamado de <strong>target</strong>, no nosso projeto <a href="http://viniciusquaiato.com/blog/primeiro-projeto-ios-single-view-application/">Hello World</a> por exemplo a classe ViewController era o target.</p>
<p><strong>Action</strong> é a mensagem que o controle enviará para o target. Então basicamente um controle dispara uma mensagem, notificando que algo aconteceu.</p>
<p>No nosso <a href="http://viniciusquaiato.com/blog/primeiro-projeto-ios-single-view-application/">Hello World</a> declaramos nosso método action assim:</p>
<div class="highlight"><pre><code class="objc"><span class="lineno">1</span> <span class="cp">#import <UIKit/UIKit.h></span>
<span class="lineno">2</span>
<span class="lineno">3</span> <span class="k">@interface</span> <span class="nc">ViewController</span> : <span class="nc">UIViewController</span>
<span class="lineno">4</span>
<span class="lineno">5</span> <span class="k">-</span><span class="p">(</span><span class="kt">IBAction</span><span class="p">)</span><span class="nf">showMessage:</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="nv">sender</span><span class="p">;</span>
<span class="lineno">6</span> <span class="k">@end</span>
</code></pre>
</div>
<p>Repare que usamos o tipo <a href="http://developer.apple.com/library/ios/#documentation/uikit/reference/UIKitConstantsReference/Reference/reference.html">IBAction ao invés de void</a>. Isso acontece pois, apesar de uma action não retornar nada o IBAction diz para o Interface Builder que isso é uma action e desta forma conseguimos linkar a mesma com nossos controles.</p>
<h2>IBOutlet</h2>
<p>Um outlet nada mais é do que uma conexão entre dois objetos. É uma variável em um objeto que guarda uma referência para outro objeto, simples assim.</p>
<p>Novamente o <a href="http://developer.apple.com/library/ios/#documentation/uikit/reference/UIKitConstantsReference/Reference/reference.html">IBOutlet serve mais para o INterface Builder</a>, para identificarmos esse tipo de variável de instância e deixarmos o Interface Builder a par disso.</p>
<p>Então usamos um IBOutlet para vincular um controle da nossa view de modo que alguém possa "manipular" este controle.</p>
<h2>Evoluindo nosso Hello World</h2>
<p>Como todo bom Hello World precisamos perguntar o nome do nosso "visitante" então vamos alterar a interface da nossa app adicionando um <a href="https://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UITextField_Class/Reference/UITextField.html">UITextField</a> e um <a href="https://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UITextField_Class/Reference/UITextField.html">UILabel</a>:</p>
<p><img src="/images_posts/mudando-interface-hello-world-ios.png" class="post_img"/></p>
<p>Feito isso vamos criar dois IBOutlets para manipularmos o label e o textfield de dentro do nosso ViewController. Mude o arquivo ViewController.h assim:</p>
<div class="highlight"><pre><code class="objc"><span class="lineno">1</span> <span class="cp">#import <UIKit/UIKit.h></span>
<span class="lineno">2</span> <span class="k">@interface</span> <span class="nc">ViewController</span> : <span class="nc">UIViewController</span>
<span class="lineno">3</span>
<span class="lineno">4</span> <span class="k">-</span><span class="p">(</span><span class="kt">IBAction</span><span class="p">)</span><span class="nf">showMessage:</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="nv">sender</span><span class="p">;</span>
<span class="lineno">5</span>
<span class="lineno">6</span> <span class="k">@property</span> <span class="p">(</span><span class="n">nonatomic</span><span class="p">,</span> <span class="n">retain</span><span class="p">)</span> <span class="kt">IBOutlet</span> <span class="n">UILabel</span> <span class="o">*</span><span class="n">showName</span><span class="p">;</span>
<span class="lineno">7</span> <span class="k">@property</span> <span class="p">(</span><span class="n">nonatomic</span><span class="p">,</span> <span class="n">retain</span><span class="p">)</span> <span class="kt">IBOutlet</span> <span class="n">UITextField</span> <span class="o">*</span><span class="n">name</span><span class="p">;</span>
<span class="lineno">8</span>
<span class="lineno">9</span> <span class="k">@end</span>
</code></pre>
</div>
<p><em>(depois falaremos mais sobre o nonatomic e o retain utilizados ali, por enquanto apenas assuma que isso é o default a ser feito)</em></p>
<p>Note que criamos os outlets com o tipo dos controles da nossa view. É desta forma que teremos uma referência para os objetos da view e poderemos manipulá-los.</p>
<p>Vamos mudar nosso ViewController.m, criando as duas propriedades (lembrando que o .h contém apenas a interface).</p>
<p>Devemos alterar o ViewController da seguinte forma:</p>
<div class="highlight"><pre><code class="objc"><span class="lineno"> 1</span> <span class="cp">#import "ViewController.h"</span>
<span class="lineno"> 2</span>
<span class="lineno"> 3</span> <span class="k">@interface</span> <span class="nc">ViewController</span> <span class="p">()</span>
<span class="lineno"> 4</span>
<span class="lineno"> 5</span> <span class="k">@end</span>
<span class="lineno"> 6</span>
<span class="lineno"> 7</span> <span class="err">@</span><span class="n">implementation</span> <span class="n">ViewController</span>
<span class="lineno"> 8</span>
<span class="lineno"> 9</span> <span class="k">@synthesize</span> <span class="n">name</span><span class="p">;</span>
<span class="lineno">10</span> <span class="k">@synthesize</span> <span class="n">showName</span><span class="p">;</span>
</code></pre>
</div>
<p>Repare que até a <strong><em>linha 7</em></strong> não fizemos nada. O que fizemos foi adicionar as <strong><em>linhas 9 e 10</em></strong>. Isso é basicamente um gerador de getter e setter para as variáveis de instância que declaramos no .h</p>
<p>Vamos agora mudar o método showMessage para que ele manipule o input e o label:</p>
<div class="highlight"><pre><code class="objc"><span class="lineno">1</span> <span class="k">-</span><span class="p">(</span><span class="kt">IBAction</span><span class="p">)</span><span class="nf">showMessage:</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="nv">sender</span><span class="p">{</span>
<span class="lineno">2</span> <span class="n">showName</span><span class="p">.</span><span class="n">text</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSString</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithFormat:</span><span class="s">@"Hello %@"</span><span class="p">,</span> <span class="n">name</span><span class="p">.</span><span class="n">text</span><span class="p">];</span>
<span class="lineno">3</span> <span class="p">}</span>
</code></pre>
</div>
<p>Bem simples né? O que estamos fazendo agora é dizendo que a propriedade <em>text</em> do nosso outlet showName é uma string formada por Hello + propriedade <em>text</em> do nosso outlet name.</p>
<h2>Conectando os outlets</h2>
<p>Está quase tudo pronto, agora só precisamos conectar os outlets aos nossos controles.</p>
<p>Uma outra forma de fazer essa conexão é também pressionando a tecla <strong><em>ctrl</em></strong> mas ao invés de arrastar para o File's Owner, podemos arrastar direto para a declaração do outlet:</p>
<p><img src="/images_posts/vinculando-outlet-com-codigo.png" class="post_img"/></p>
<p><em>(neste caso repare que cliquei no botão no canto superior direito da imagem, na seção editor, o botão do meio - Show the Assistant Editor)</em></p>
<p>Ou se preferir faça como fizemos da primeira vez (<a href="http://viniciusquaiato.com/blog/primeiro-projeto-ios-single-view-application/">veja aqui</a>).</p>
<p>Com isso quando executarmos nossa app, preencher o texto e clicarmos no botão teremos isso:</p>
<p><img src="/images_posts/digitando-nome-app-ios.png" class="post_img"/></p>
<p><img src="/images_posts/exibindo-nome-app-ios.png" class="post_img"/></p>
<h2>Resumo</h2>
<p>Estamos avançando um pouco mais no entendimento de alguns conceitos do iOS. Agora já sabemos como manipular controles e exibir dados nas nossas views.</p>
<p>Se você quiser saber mais sobre os padrões de comunicaçào, delegates, outlets, actions, etc veja aqui: <a href="https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaFundamentals/CommunicatingWithObjects/CommunicateWithObjects.html#//apple_ref/doc/uid/TP40002974-CH7-SW14">Cocoa Fundamentals</a></p>
<p>Para dar uma lida nos design patterns usados pelo cocoa veja aqui: <a href="https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaDesignPatterns/CocoaDesignPatterns.html#//apple_ref/doc/uid/TP40002974-CH6-SW6">Cocoa Design Patterns</a></p>
<p>Bom acho que por hoje é isso. O código dessas alterações já está no github: <a href="https://github.com/vquaiato/ios-blog-samples/tree/master/HelloWorldEvolution">https://github.com/vquaiato/ios-blog-samples/tree/master/HelloWorldEvolution</a></p>
<p>Abraços, e até a próxima.</p>
<p>Vinicius Quaiato.</p>
Primeiro projeto iOS: Single View Application2012-05-16T00:00:00-07:00http://viniciusquaiato.com/blog/primeiro-projeto-ios-single-view-application<p>Vamos começar e criar nossa primeira aplicação, como sempre um <strong><em>Hello World</em></strong>. O bom é que conseguiremos ver diversas coisas novas com este <em>simples</em> exemplo e com isso vamos começar a nos acostumar/aprofundar no iOS.
<em><a href="http://viniciusquaiato.com/tags/ios/">(confira todos os posts sobre iOS)</a></em></p>
<h2>Criando o projeto</h2>
<p>Assumo que você já instalou o XCode (no momento estou usando o 4.3.2). Abra o mesmo e crie um novo projeto. Para iniciarmos vamos começar um um dos templates que o XCode já fornece, neste caso o <em>Single View Application</em> para iOS.</p>
<p><img src="/images_posts/criar-projeto-xcode.png" class="post_img"/></p>
<p><img src="/images_posts/criando-single-view-application.png" class="post_img"/></p>
<p><img src="/images_posts/dando-nome-ao-projeto.png" class="post_img"/></p>
<p>Após termos o projeto criado vamos nos deparar com uma tela como esta:</p>
<p><img src="/images_posts/projeto-criado.png" class="post_img"/></p>
<p>Não se desespere. Nesta tela temos algumas informações sobre o projeto como por exemplo: <em>Supported Device Orientations</em> e outras. Futuramente investigaremos isso melhor.</p>
<p>Do lado esquerdo temos os arquivos que fazem parte do nosso projeto e aqui já podemos perceber uma coisa: <em>para toda classe teremos 2 arquivos: um .h e um .m</em></p>
<ul>
<li>.h são Header Files. Eles contém classes, tipos, funções e constantes.</li>
<li>.m são Source Files. Nestes arquivos temos a maioria do nosso código objective-c ou mesmo c.</li>
</ul>
<p>Esse é um conceito bastante simples: a interface de uma classe é separada de sua implementação. A interface da classe (no arquivo .h) contém as variáveis e métodos que essa classe possui. A implementação da classe, o corpo dos métodos, etc, está contido nos arquivos .m</p>
<p>Vejamos um simples exemplo de declaração de uma classe em um arquivo .h que a Apple disponibiliza <a href="https://developer.apple.com/library/mac/#referencelibrary/GettingStarted/Learning_Objective-C_A_Primer/_index.html">aqui</a>:</p>
<p><img src="/images_posts/class-declaration.jpg" class="post_img"/></p>
<h2>AppDelegate</h2>
<p>Voltando para o nosso projeto vamos primeiro ver os arquivos <em>AppDelegate.h</em> e <em>AppDelegate.m</em></p>
<p>Este AppDelegate servirá para a função <em>main</em> da nossa aplicação. Um objeto deste tipo será utilizado para controlar algumas coisas do ciclo de vida da nossa aplicação.</p>
<p>Este delegare é informado sobre eventos de inicialização, término (e outros) dentro da nossa aplicação. <a href="https://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIApplicationDelegate_Protocol/Reference/Reference.html">Confira a referência completa de UIApplicationDelegate</a></p>
<p>O ponto principal aqui é o método abaixo (dentro de AppDelegate.m):</p>
<div class="highlight"><pre><code class="objc"><span class="lineno"> 1</span> <span class="k">-</span> <span class="p">(</span><span class="kt">BOOL</span><span class="p">)</span><span class="nf">application:</span><span class="p">(</span><span class="n">UIApplication</span> <span class="o">*</span><span class="p">)</span><span class="nv">application</span> <span class="nf">didFinishLaunchingWithOptions:</span><span class="p">(</span><span class="n">NSDictionary</span> <span class="o">*</span><span class="p">)</span><span class="nv">launchOptions</span>
<span class="lineno"> 2</span> <span class="p">{</span>
<span class="lineno"> 3</span> <span class="n">self</span><span class="p">.</span><span class="n">window</span> <span class="o">=</span> <span class="p">[[</span><span class="n">UIWindow</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithFrame:</span><span class="p">[[</span><span class="n">UIScreen</span> <span class="n">mainScreen</span><span class="p">]</span> <span class="n">bounds</span><span class="p">]];</span>
<span class="lineno"> 4</span>
<span class="lineno"> 5</span> <span class="c1">// Override point for customization after application launch.</span>
<span class="lineno"> 6</span> <span class="n">self</span><span class="p">.</span><span class="n">viewController</span> <span class="o">=</span> <span class="p">[[</span><span class="n">ViewController</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithNibName:</span><span class="s">@"ViewController"</span> <span class="nl">bundle:</span><span class="nb">nil</span><span class="p">];</span>
<span class="lineno"> 7</span> <span class="n">self</span><span class="p">.</span><span class="n">window</span><span class="p">.</span><span class="n">rootViewController</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">viewController</span><span class="p">;</span>
<span class="lineno"> 8</span> <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">window</span> <span class="n">makeKeyAndVisible</span><span class="p">];</span>
<span class="lineno"> 9</span>
<span class="lineno">10</span> <span class="k">return</span> <span class="n">YES</span><span class="p">;</span>
<span class="lineno">11</span> <span class="p">}</span>
</code></pre>
</div>
<p>Este método na <strong><em>linha 3</em></strong> está criando uma <em>window</em> para nossa aplicação. Na <strong><em>linha 6</em></strong> está criando um ViewController (que está na nossa lista de arquivos) e informando que a view deste ViewController é uma view com o mesmo nome.
Na <strong><em>linha 7</em></strong> é informado que o rootViewController é o ViewController que acabou de ser criado. E na <strong><em>linha 8</em></strong> tudo é exibido :D
Este código todo foi gerado pelo template do XCode e com o tempo vamos compreender melhor cada um dos pontos aí.</p>
<h2>UIViewController</h2>
<p>UIViewController é o tipo base que a classe ViewController (.h e .m) implementa. UIViewController fornece um mecanismo base para a manipulação de views no iOS.
Uma classe que herda de UIViewController manipulará uma ou mais views e estas views irão compor a interface da sua aplicação iOS. Desta forma essas classes ViewController manipulam views, models e se comunicam também com outros view controllers.
(<a href="http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIViewController_Class/Reference/Reference.html">Veja a referência completa para UIViewController</a>)</p>
<p>Na nossa aplicação temos um view controller chamado ViewController (nos arquivos ViewController.h e ViewController.m).</p>
<h2>Arquivos nib(.xib)</h2>
<p>O arquivo ViewController.xib é a nossa view. Ela poderia ter qualquer outro nome, como por exemplo "TelaInicial".
Estes arquivos é que contém nossa interface gráfica. Se você clicar sobre ele, verá algo parecido com isso:</p>
<p><img src="/images_posts/editando-views-no-xcode.png" class="post_img"/></p>
<p>Se observarmos lá do lado direito, na parte inferior temos uma lista com os controles que podemos colocar na nossa view. Vamos então começar a brincar e fazer nosso hello world. Vamos adicionar um label e um botão, como abaixo:</p>
<p><img src="/images_posts/adicionando-componentes-na-view.jpg" class="post_img"/></p>
<p><a href="https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html">Mais sobre Nib/.xib files veja aqui</a></p>
<h2>Executando a aplicação</h2>
<p>Já podemos executar nossa aplicação, clique no botão <strong><em>Play/Run</em></strong> ou ⌘+R. O simulador do iOS iniciará e veremos nossa primeira app rodando:</p>
<p><img src="/images_posts/hello-world-ios.png" class="post_img"/></p>
<p>Se você reparou clicar no botão não faz nada, então vamos exibir um alerta quando o botão for tocado (lembre que não são cliques e sim toques).</p>
<h2>Exibindo um alert no toque do botão</h2>
<p>Para isso vamos adicionar um método no nosso ViewController.h que ficará como abaixo:</p>
<div class="highlight"><pre><code class="objc"><span class="lineno">1</span> <span class="cp">#import <UIKit/UIKit.h></span>
<span class="lineno">2</span>
<span class="lineno">3</span> <span class="k">@interface</span> <span class="nc">ViewController</span> : <span class="nc">UIViewController</span>
<span class="lineno">4</span>
<span class="lineno">5</span> <span class="k">-</span><span class="p">(</span><span class="kt">IBAction</span><span class="p">)</span><span class="nf">showMessage:</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="nv">sender</span><span class="p">;</span>
<span class="lineno">6</span> <span class="k">@end</span>
</code></pre>
</div>
<p>Adicionamos a <strong><em>linha 5</em></strong> (não se preocupe com tudo neste momento, falaremos sobre Actions e Outlets futuramente). Apenas precisamos entender que nossa view controller agora possui um método. Vamos então implementar este método no ViewController.m:</p>
<div class="highlight"><pre><code class="objc"><span class="lineno"> 1</span> <span class="k">-</span><span class="p">(</span><span class="kt">IBAction</span><span class="p">)</span><span class="nf">showMessage:</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="nv">sender</span><span class="p">{</span>
<span class="lineno"> 2</span> <span class="n">UIAlertView</span> <span class="o">*</span><span class="n">alert</span> <span class="o">=</span> <span class="p">[[</span><span class="n">UIAlertView</span> <span class="n">alloc</span><span class="p">]</span>
<span class="lineno"> 3</span> <span class="nl">initWithTitle:</span> <span class="s">@"Hi iOS folks!"</span>
<span class="lineno"> 4</span> <span class="nl">message:</span> <span class="s">@"oh... Hello World!"</span>
<span class="lineno"> 5</span> <span class="nl">delegate:</span><span class="nb">nil</span>
<span class="lineno"> 6</span> <span class="nl">cancelButtonTitle:</span> <span class="s">@"Bye!"</span>
<span class="lineno"> 7</span> <span class="nl">otherButtonTitles:</span><span class="nb">nil</span><span class="p">];</span>
<span class="lineno"> 8</span>
<span class="lineno"> 9</span> <span class="p">[</span><span class="n">alert</span> <span class="n">show</span><span class="p">];</span>
<span class="lineno">10</span> <span class="p">}</span>
</code></pre>
</div>
<p>Bem tranquilo esse código né? Criamos um objeto do tipo <a href="http://developer.apple.com/library/ios/#documentation/uikit/reference/UIAlertView_Class/UIAlertView/UIAlertView.html">UIAlertView</a>, iniciamos o objeto com seus valores e depois enviamos a mensagem <em>show</em> para ele.</p>
<p>Agora precisamos vincular esse método com o botão. Isso é um pouco estranho a princípio, mas começaremos fazendo desta forma: clique no botão, segure a tecla control e arraste até o File's Owner como mostra a imagem abaixo:</p>
<p><img src="/images_posts/vinculando-botao-com-action.png" class="post_img"/></p>
<p>Feito isso uma lista com as actions disponíveis aparecerá, clique na nossa action <em>showMessage</em>.</p>
<p><img src="/images_posts/selecionando-action-para-botao.png" class="post_img"/></p>
<p>Pronto! Rode a aplicação novamente e teremos nosso botão exibindo um alerta:</p>
<p><img src="/images_posts/hello-world-ios-usando-alert.png" class="post_img"/></p>
<p>Bacana hein?</p>
<h2>Resumo</h2>
<p>Há um monte de coisas novas que precisamos estudar mais e nos aprofundar, mas sem dúvida fizemos algo bacana (ainda que simples) com praticamente nenhum esforço.</p>
<p>Tudo que precisamos nesse momento é manter a calma e entender cada um dos passos que estamos dando. Alguns conceitos eu deixei para explicar depois pois acredito que se eu despejar mais um monte de informações aqui mais vou atrapalhar do que ajudar.</p>
<p>Tente criar uma outra applicação, simples como essa, mas do zero, sem seguir o blog. Veja o quão longe você consegue ir e vá se acostumando :)</p>
<p>O código completo deste exemplo você encontra aqui: <a href="https://github.com/vquaiato/ios-blog-samples/tree/master/HelloWorld">https://github.com/vquaiato/ios-blog-samples/tree/master/HelloWorld</a></p>
<p>Abraços e até o próximo.</p>
<p>Vinicius Quaiato.</p>
iOS desenvolvimento para iPhone: primeiros passos2012-05-15T00:00:00-07:00http://viniciusquaiato.com/blog/ios-desenvolvimento-para-iphone-primeiros-passos<p>Parte da minha <a href="http://viniciusquaiato.com/blog/por-que-nao-troquei-o-net-pelo-ruby/">motivação em mudar meu mundo para OSX</a> é a possibilidade de desenvolver para iOS (iPhone e também iPad). Apenas uma motivação curiosa: conhecer uma nova plataforma, nova linguagem, novo framework, etc, etc…
<em><a href="http://viniciusquaiato.com/tags/ios/">(confira todos os posts sobre iOS)</a></em></p>
<p>Há um ano eu comecei a brincar e estudar mas parei. E há uma semana retomei os estudos. Como eu acredito que escrevendo/compartilhando eu consigo absorver melhor as idéias cá estou.</p>
<h2>Um mundo totalmente novo</h2>
<h3>Objective-C</h3>
<p>Não dá para dizer que <a href="http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Introduction/introObjectiveC.html">objective-c</a> é algo lindo, mas hoje eu também não o acho feio. Acabamos nos acostumando e entendendo as coisas. Nem vou comparar objective-c com C#, ou Ruby, nem nada: é apenas mais uma linguagem e pronto.</p>
<p>Assim como toda linguagem nova que vamos aprender demoramos um pouco para entender alguns conceitos, práticas, sintaxe, etc. Mas <a href="http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Introduction/introObjectiveC.html">objective-c</a> não é nada de outro mundo.</p>
<div class="highlight"><pre><code class="objc"><span class="c1">//instanciando um objeto</span>
<span class="n">NSString</span> <span class="o">*</span><span class="n">hello</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSString</span> <span class="nl">stringWithString:</span><span class="s">@"iOS World!"</span><span class="p">];</span>
</code></pre>
</div>
<p>(o código acima não é importante, é apenas para vocês verem o conceito de <em>mensagens</em> presente no objective-c)</p>
<p>Para mim agora é necessário estudar mais essa linguagem. Eu poderia simplesmente desenvolver usando <a href="http://xamarin.com/monotouch">Monotouch</a>? Sim poderia, mas eu tenho vontade de aprender coisas novas. Me sentirei muito mais seguro para usar Monotouch quando eu dominar <a href="http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Introduction/introObjectiveC.html">objective-c</a> e <a href="https://developer.apple.com/technologies/ios/cocoa-touch.html">Cocoa Touch</a>.</p>
<h3>Cocoa Touch</h3>
<p><a href="https://developer.apple.com/technologies/ios/cocoa-touch.html">Cocoa Touch</a> é o framework sobre o qual criamos nossas aplicações iOS. Ele é a aplicação de vários padrões utilizados no desenvolvimento para Mac com este "apelativo" de interfaces touch.</p>
<p>Desenvolvido utilizando Objective-C é possível trabalhar nele também com C ou até mesmo C++ (tudo depende do seu grau de loucura).</p>
<p>É nele que estão contidas as principais bibliotecas e frameworks que utilizaremos ao criar aplicações iOS:</p>
<ul>
<li><a href="https://developer.apple.com/technologies/ios/data-management.html">Core Data</a></li>
<li><a href="https://developer.apple.com/technologies/ios/graphics-and-animation.html">Core Animation</a></li>
<li><a href="https://developer.apple.com/technologies/ios/audio-and-video.html">Core Audio/Video</a></li>
</ul>
<p>(não vamos aprofundar nisso agora, é muito material. Conforme eu for fazendo algo que toque nesses pontos tentarei compartilhar minhas impressões sobre eles)</p>
<h3>XCode</h3>
<p><a href="https://developer.apple.com/xcode/">XCode</a> é a IDE da Apple para o desenvolvimento para iOS e OSX. No XCode temos os SDKs necessário tanto para iOS quando para OSX.
Tem simulador para iPad e iPhone e confesso que é uma IDE tão completa quanto as outras que existem por aí(o que não quer dizer que eu ache que as IDEs que existem por aí maravilhosas). No começo a gente estranha muita coisa, mas com o tempo vai se acostumando, assim como tudo novo na vida.</p>
<p>Para ser sincero é uma IDE bem agradável: a forma como os erros/alerts aparecem conforme vamos escrevendo o código, o "intellisense" funciona muito bem e assim como tudo no Mac/OSX é de muito bom gosto :P</p>
<p>Para instalar o <a href="https://developer.apple.com/xcode/">XCode</a> basta entrar na App Store no seu mac:</p>
<p><img src="/images_posts/xcode-appstore.png" class="post_img" /></p>
<h2>Começando a estudar</h2>
<p>A Apple disponibiliza uma série de materiais e documentação acerca dos tópicos de desenvolvimento para suas plataformas, e podemos conferir tudo aqui: <a href="https://developer.apple.com/devcenter/ios/index.action">https://developer.apple.com/devcenter/ios/index.action</a>.</p>
<p>Lá podemos encontrar artigos, códigos de exemplo, vídeos, guias, etc. Vale a pena dar uma conferida antes de iniciar suas aventuras.</p>
<p>Confira alguns links:</p>
<ul>
<li><a href="https://developer.apple.com/library/ios/navigation/index.html#section=Topics&topic=Tools%20%26amp%3B%20Languages">Tools and Languages Documentation(iOS)</a></li>
<li><a href="https://developer.apple.com/library/mac/#recipes/xcode_help-general/">XCode basics</a></li>
<li><a href="https://developer.apple.com/library/ios/#documentation/ToolsLanguages/Conceptual/Xcode4UserGuide/Introduction/Introduction.html">Xcode 4 user guide</a></li>
<li><a href="https://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Introduction/Introduction.html">iOS app programming guide</a></li>
<li><a href="https://developer.apple.com/library/ios/#documentation/Xcode/Conceptual/ios_development_workflow/00-About_the_iOS_Application_Development_Workflow/introduction.html">Tools workflow guide for iOS</a></li>
</ul>
<h2>Resumindo</h2>
<p>Estou começando a brincadeira e cá estarei compartilhando com vocês. Amanhã já começo a colocar os básicos para criar uma app (simples) e explicar alguns conceitos e paradigmas novos que temos pela frente.</p>
<p>Uma série de amigos oriundos do mundo Microsoft/.NET está usando Mac agora (ao menos como uma segunda plataforma) então acho que vai ser bem útil para muita gente.</p>
<p>Bora trocar figurinhas então.</p>
<p>Abraços,</p>
<p>Vinicius Quaiato.</p>
ASP.NET MVC upload de imagens + JCrop + Resize + progressbar + tudo assíncrono2012-05-04T00:00:00-07:00http://viniciusquaiato.com/blog/upload-imagens-jcrop-resize-progressbar-assincrono<p>Essa é uma das features que qualquer sistema web público precisa:</p>
<blockquote><p>Usuário precisa fazer upload de uma foto para o seu perfil</p></blockquote>
<p>Até aí tudo bem, tudo simples. O problema é que o layout das aplicações exigem uma foto de perfil quadrada. Até aí tudo bem também. Mas o que acontece quando o usuário faz upload de uma imagem que não é quadrada? Vamos simplesmente redimensionar? Eu não acho essa uma boa solução: as imagens retangulares ficam feias demais se simplesmente redimensionadas para um quadrado. Não dá para simplesmente fazer um resize proporcional, afinal é um retângulo.</p>
<p>Para "complicar" um pouco mais as coisas eu quero que tudo seja feito de forma assíncrona e que tenhamos uma barra de progresso.</p>
<h1>Os plugins</h1>
<p>Para fazer esse trabalho sujo, client side, vamos usar alguns plugins para facilitar nossa vida.</p>
<p>Juntar estes plugins para essa solução é algo bastante simples e com pouco código podemos realizar o trabalho. <em>(por favor atentem que estou blogando isso exatamente em seguida de ter terminado de implementar isso, então nenhum código recebeu refatoração, é preciso melhorá-lo, claro)</em></p>
<h2>Jquery.Form</h2>
<p>Para <em>simplificar</em> tudo quero fazer, quero que todo esse processo seja realizado de forma assíncrona. Ou seja o usuário faz o upload de uma foto inicial, consegue realizar o crop e então submete novamente para que o crop seja salvo.</p>
<p>Pesquisando encontrei o <a href="http://jquery.malsup.com/form/">Jquery.Form</a>.</p>
<p>Este plugin é bastante simples e nos permite trabalhar com formulários de maneira assíncrona. <em><sarcasm>É quase um UpdatePanel</sarcasm></em></p>
<p>É também este o plugin responsável pela barra de progresso :D</p>
<p><a href="http://jquery.malsup.com/form/#download">Vamos baixar o Jquery.Form plugin aqua no site do plugin</a></p>
<h2>JCrop</h2>
<p>Acho que é o <a href="http://deepliquid.com/content/Jcrop.html">JCrop</a> é o plugin <a href="http://jquery.com">JQuery</a> mais famoso para crop de imagens. É bastante simples de utilizar. Esse eu conheço já de longa data, então eu nem pesquisei alternativas.</p>
<p><a href="http://deepliquid.com/content/Jcrop_Download.html">Vamos baixar o JCrop aqui</a></p>
<h1>Passo 1 - Realizar o upload da imagem</h1>
<p>O primeiro passo então para nosso upload com crop e resize assíncrono lindo de morrer é conseguir uma imagem quadrada que nos possibilite um resize sem deformações medonhas.</p>
<p>Para fazer isso precisamos realizar o upload de uma imagem e permitir que o usuário selecione uma parte quadrada desta imagem. Após o upload precisamos exibir a imagem para que o mesmo possa selecionar uma área dentro dessa e então realizar o <em>crop</em>(recorte).</p>
<h2>O HTML inicial</h2>
<p>Vamos criar um form e aplicar o jquery-form nele:</p>
<div class="highlight"><pre><code class="html"><span class="lineno">1</span> <span class="nt"><form</span> <span class="na">action=</span><span class="s">'@Url.Action("Upload")'</span> <span class="na">method=</span><span class="s">"post"</span> <span class="na">enctype=</span><span class="s">"multipart/form-data"</span> <span class="na">name=</span><span class="s">"imagem_original"</span><span class="nt">></span>
<span class="lineno">2</span> <span class="nt"><input</span> <span class="na">type=</span><span class="s">"file"</span> <span class="na">name=</span><span class="s">"imagem"</span> <span class="nt">/></span>
<span class="lineno">3</span> <span class="nt"><input</span> <span class="na">type=</span><span class="s">"submit"</span> <span class="na">value=</span><span class="s">"upload to server"</span> <span class="na">class=</span><span class="s">"hidden"</span> <span class="na">id=</span><span class="s">"upload"</span> <span class="nt">/></span>
<span class="lineno">4</span> <span class="nt"></form></span>
<span class="lineno">5</span> <span class="nt"><div</span> <span class="na">class=</span><span class="s">"progress"</span><span class="nt">></span>
<span class="lineno">6</span> <span class="nt"><div</span> <span class="na">class=</span><span class="s">"bar"</span><span class="nt">></div></span>
<span class="lineno">7</span> <span class="nt"><div</span> <span class="na">class=</span><span class="s">"percent"</span><span class="nt">></span>0%<span class="nt"></div></span>
<span class="lineno">8</span> <span class="nt"></div></span>
<span class="lineno">9</span> <span class="nt"><img</span> <span class="na">src=</span><span class="s">""</span> <span class="na">class=</span><span class="s">"hidden"</span> <span class="na">id=</span><span class="s">"imagem_crop"</span> <span class="nt">/></span>
</code></pre>
</div>
<p>Esse form por si só não faz nada assíncrono, então vamos adicionar o seguinte em nossa página. Reparem apenas que na <strong><em>linha 5</em></strong> eu adiciono um div que funcionará como progress bar.
Na <strong><em>linha 9</em></strong> eu coloquei uma imagem escondida. Será nesta tag %lt;img que exibiremos a imagem após o upload, para realizar o crop.</p>
<div class="highlight"><pre><code class="html"><span class="lineno"> 1</span> <span class="nt"><script </span><span class="na">src=</span><span class="s">'@Url.Content("~/Scripts/jquery-1.7.2.min.js")'</span> <span class="na">type=</span><span class="s">"text/javascript"</span><span class="nt">></script></span>
<span class="lineno"> 2</span> <span class="nt"><script </span><span class="na">src=</span><span class="s">'@Url.Content("~/Scripts/jquery.form.js")'</span> <span class="na">type=</span><span class="s">"text/javascript"</span><span class="nt">></script></span>
<span class="lineno"> 3</span> <span class="nt"><script></span>
<span class="lineno"> 4</span> <span class="p">(</span><span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="lineno"> 5</span> <span class="kd">var</span> <span class="nx">bar</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="s1">'.bar'</span><span class="p">);</span>
<span class="lineno"> 6</span> <span class="kd">var</span> <span class="nx">percent</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="s1">'.percent'</span><span class="p">);</span>
<span class="lineno"> 7</span> <span class="kd">var</span> <span class="nx">status</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="s1">'#status'</span><span class="p">);</span>
<span class="lineno"> 8</span>
<span class="lineno"> 9</span> <span class="nx">$</span><span class="p">(</span><span class="s1">'input[name=imagem]'</span><span class="p">).</span><span class="nx">live</span><span class="p">(</span><span class="s1">'change'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="lineno">10</span> <span class="nx">$</span><span class="p">(</span><span class="s2">"#upload"</span><span class="p">).</span><span class="nx">click</span><span class="p">();</span>
<span class="lineno">11</span> <span class="p">});</span>
<span class="lineno">12</span>
<span class="lineno">13</span> <span class="nx">$</span><span class="p">(</span><span class="s1">'form[name=imagem_original]'</span><span class="p">).</span><span class="nx">ajaxForm</span><span class="p">({</span>
<span class="lineno">14</span> <span class="nx">dataType</span><span class="o">:</span> <span class="s1">'json'</span><span class="p">,</span>
<span class="lineno">15</span> <span class="nx">beforeSend</span><span class="o">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="lineno">16</span> <span class="nx">status</span><span class="p">.</span><span class="nx">empty</span><span class="p">();</span>
<span class="lineno">17</span> <span class="kd">var</span> <span class="nx">percentVal</span> <span class="o">=</span> <span class="s1">'0%'</span><span class="p">;</span>
<span class="lineno">18</span> <span class="nx">bar</span><span class="p">.</span><span class="nx">width</span><span class="p">(</span><span class="nx">percentVal</span><span class="p">);</span>
<span class="lineno">19</span> <span class="nx">percent</span><span class="p">.</span><span class="nx">html</span><span class="p">(</span><span class="nx">percentVal</span><span class="p">);</span>
<span class="lineno">20</span> <span class="p">},</span>
<span class="lineno">21</span> <span class="nx">uploadProgress</span><span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">event</span><span class="p">,</span> <span class="nx">position</span><span class="p">,</span> <span class="nx">total</span><span class="p">,</span> <span class="nx">percentComplete</span><span class="p">)</span> <span class="p">{</span>
<span class="lineno">22</span> <span class="kd">var</span> <span class="nx">percentVal</span> <span class="o">=</span> <span class="nx">percentComplete</span> <span class="o">+</span> <span class="s1">'%'</span><span class="p">;</span>
<span class="lineno">23</span> <span class="nx">bar</span><span class="p">.</span><span class="nx">width</span><span class="p">(</span><span class="nx">percentVal</span><span class="p">);</span>
<span class="lineno">24</span> <span class="nx">percent</span><span class="p">.</span><span class="nx">html</span><span class="p">(</span><span class="nx">percentVal</span><span class="p">);</span>
<span class="lineno">25</span> <span class="p">},</span>
<span class="lineno">26</span> <span class="nx">success</span><span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
<span class="lineno">27</span> <span class="nx">$</span><span class="p">(</span><span class="s1">'input[name=url]'</span><span class="p">).</span><span class="nx">val</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">url</span><span class="p">);</span>
<span class="lineno">28</span> <span class="nx">$</span><span class="p">(</span><span class="s2">"#imagem_crop"</span><span class="p">).</span><span class="nx">attr</span><span class="p">(</span><span class="s2">"src"</span><span class="p">,</span> <span class="nx">data</span><span class="p">.</span><span class="nx">url</span><span class="p">);</span>
<span class="lineno">29</span> <span class="nx">$</span><span class="p">(</span><span class="s2">"#imagem_crop"</span><span class="p">).</span><span class="nx">removeClass</span><span class="p">(</span><span class="s2">"hidden"</span><span class="p">);</span>
<span class="lineno">30</span> <span class="p">}</span>
<span class="lineno">31</span> <span class="p">});</span>
<span class="lineno">32</span> <span class="p">})();</span>
<span class="lineno">33</span> <span class="nt"></script></span>
</code></pre>
</div>
<p>Esse código não possui nenhum mistério.
Nas <strong><em>linhas 5, 6 e 7</em></strong> apenas obtenho alguns elementos e coloco em variáveis para reutilizarmos depois.</p>
<p>Nas <strong><em>linhas 9, 10 e 11</em></strong> disparamos o submit do form automaticamente sempre que um arquivo novo é selecionado, por isso mantive o botão de upload escondido no formulário, mas poderia nem ter o botão lá.</p>
<p>Na sequência, nas <strong><em>linhas 13 e 14</em></strong> o jquery-form configura nosso formulário como um formulário ajax, utilizando o retorno do servidor como json.</p>
<p>A função <strong><em>beforeSend</em></strong> na <strong><em>linha 15</em></strong> é executada antes mesmo que o envio dos dados ocorra (dãr!) e o que ela faz é apenas zerar uma barra de progesso (100% feita em html).</p>
<p>A função <strong><em>uploadProgress</em></strong> na <strong><em>linha 21</em></strong> é chamada de tempos em tempos com o status de progresso do upload e com isso conseguimos atualizar a barra de progresso.</p>
<p>Já a função <strong><em>success</em></strong> na <strong><em>linha 26</em></strong> é chamada com o retorno do servidor, neste caso um objeto json contendo a url de onde a imagem foi salva.
Nesta função eu já preparo algumas coisas para iniciarmos o crop: na <strong><em>linha 27</em></strong> eu coloco a url da imagem em um input hidden, pois não faremos o upload da imagem novamente, vamos carregá-la no servidor direto da url. Também coloco a url da imagem no atributo src de uma tag <img e deixo esta imagem visível na tela pois será nela que faremos o crop.</p>
<p>O código server no ASP.NET MVC para isso é algo como:</p>
<div class="highlight"><pre><code class="csharp"><span class="lineno">1</span> <span class="na">[HttpPost]</span>
<span class="lineno">2</span> <span class="k">public</span> <span class="n">ActionResult</span> <span class="nf">Upload</span><span class="p">()</span> <span class="p">{</span>
<span class="lineno">3</span> <span class="kt">var</span> <span class="n">nomeOriginal</span> <span class="p">=</span> <span class="n">Request</span><span class="p">.</span><span class="n">Files</span><span class="p">[</span><span class="m">0</span><span class="p">].</span><span class="n">FileName</span><span class="p">;</span>
<span class="lineno">4</span> <span class="kt">var</span> <span class="n">nomeFinal</span> <span class="p">=</span> <span class="s">"../uploads/imagem"</span> <span class="p">+</span> <span class="n">Path</span><span class="p">.</span><span class="n">GetExtension</span><span class="p">(</span><span class="n">nomeOriginal</span><span class="p">);</span>
<span class="lineno">5</span> <span class="kt">var</span> <span class="n">pathFinal</span> <span class="p">=</span> <span class="n">Server</span><span class="p">.</span><span class="n">MapPath</span><span class="p">(</span><span class="n">nomeFinal</span><span class="p">);</span>
<span class="lineno">6</span>
<span class="lineno">7</span> <span class="n">Request</span><span class="p">.</span><span class="n">Files</span><span class="p">[</span><span class="m">0</span><span class="p">].</span><span class="n">SaveAs</span><span class="p">(</span><span class="n">pathFinal</span><span class="p">);</span>
<span class="lineno">8</span> <span class="k">return</span> <span class="nf">Json</span><span class="p">(</span><span class="k">new</span> <span class="p">{</span> <span class="n">url</span> <span class="p">=</span> <span class="n">nomeFinal</span> <span class="p">});</span>
<span class="lineno">9</span> <span class="p">}</span>
</code></pre>
</div>
<p>Nada anormal (removi uma série de tratamentos, validações, etc, para manter o código breve e acho que ele ainda está funcionando :P).</p>
<p>Feito tudo isso devemos ter uma página capaz de realizar um upload assíncrono, com barra de progresso e exibindo o resultado do upload em uma tag <img mais ou menos como a imagem abaixo:</p>
<p><img src="/images_posts/upload-progressbar-assincrono-1.png" class="post_img" alt="ubber elegant"/>
<img src="/images_posts/upload-progressbar-assincrono-2.png" class="post_img" alt="ubber elegant"/></p>
<h1>Resumindo</h1>
<p>No próximo post mostrarei como colocarmos o JCrop para funcionar e realizar o upload das informações para recortar a imagem no server side.</p>
<p>Abraços,</p>
<p>Vinicius Quaiato.</p>
UbberElegant: Sinatra, Redis e Social Coding2012-02-27T00:00:00-08:00http://viniciusquaiato.com/blog/ubberelegant-sinatra-redis-e-social-coding<p>Uma das coisas mais bacanas de trabalhar com software é que é possível compartilhar seu trabalho de forma muito simples com outros colegas de profissão.</p>
<p>Não sei se advogados, médicos, dentistas, construtores, etc, conseguem compartilhar seu trabalho da forma como fazemos. Nós não simplesmente comentamos sobre o que estamos fazendo: nós mostramos e temos ferramentas/meios para permitir que outros participem.</p>
<p>Eu entendo que essa facilidade de compartilhar código e ver código alheio é uma forma muito eficiente para o crescimento profissional. Afinal se você está isolado, não mostra o que faz e não vê o que os outros fazem, como é possível evoluir? Como é possível aprender? Fica difícil...</p>
<h2>Github</h2>
<p>Desde minha entrada no mundo Ruby passei a utilizar mais o Github. Passei a utilizá-lo não apenas como um repositório de código para os meus posts e palestras, mas como ma ferramenta de <strong><em>social coding</em></strong>: passei a ver e navegar por mais projetos, passei a colaborar (ainda que de forma bem discreta) com outros projetos, passei a publicar mais coisas sem medo de ser julgado e/ou criticado.</p>
<p>E é somente deixando esse medo de lado que podemos evoluir. Não estou dizendo que todos precisem usar o Github, mas seria muito saudável que o fizessem.</p>
<p><strong><em>DISCLAIMER</em></strong>: utilizar o Github não tem nada a ver com estar no mundo Microsoft. Não tem nada a ver com ser um fã do TFS (<a href="http://bit.ly/9MLYg8">http://bit.ly/9MLYg8</a>), etc.</p>
<h2>Rivalidade em código</h2>
<p>Durante o carnaval o amigo <a href="http://twitter.com/leandronet">@leandronet</a> resolveu começar um pequeno projeto <em>de tiração de sarro</em> que ele chamou de <strong><em><a href="http://elegantcodemaker.apphb.com">Elegant Code Maker</a></em></strong>. Como ele é um arquiteto e está longe do código fonte acabou que eu ajudei a ele com este projeto utilizando ASP.NET MVC, Jquery, git, Github e App Harbor. (<a href="http://reverb.leandrodaniel.com/post/Como-assim-codigo-elegante.aspx">post de <del>mimimi</del> motivação dele sobre o Elegant Code Maker</a>)</p>
<p>Após 1 dia no ar o <em>invejoso</em> <a href="http://twitter.com/juanplopes">@juanplopes</a> criou uma nova versão da mesma aplicação. Porém o que o Juan fez foi desenvolver uma aplicação semelhante usando apenas HTML + Javascript, sem nenhum código server side. E é aí que a brincadeira começa a ficar interessante: um projeto simples, de curtição, movimentando amigos em torno de código e colaboração.</p>
<p>Neste momento pensei em criar algo também. Pensei em criar uma aplicação rival das duas(não melhor, mas apenas alternativa) e me arrisquei utilizando Ruby. Como eu não estava afim de usar Rails resolvi desenvolver utilizando Sinatra<a href="http://www.sinatrarb.com/">sinatra</a>.</p>
<h2>UbberElegant</h2>
<p>Já que a aplicação do Juan se chama <a href="http://juanlopes.net/elegant/">Elegant</a> resolvi chamar a minha de <a href="http://ubberelegant.heroku.com">UbberElegant</a>.
O processo de construção da mesma foi bem trivial. Na verdade a aplicação não possui muitas linhas de código.
Para deixar a brincadeira um pouco mais interessante resolvi adicionar um esquema de <em>permalinks</em>.</p>
<p><img src="/images_posts/ubber_elegant_min.jpg" class="post_img" alt="ubber elegant"/></p>
<p>Para fazer isso decidi usar o <a href="http://redis.io">Redis</a> como storage para os meus permalinks (sim eu poderia não ter usado nada e simplesmente pego o id do gist e ir novamente ao github, mas eu entendi que se fizesse isso estaria deixando de conhecer algo novo).</p>
<p>Redis é um storage do tipo key-value e foi muito simples integrá-lo. Poderia ser um MySQL, Postgres, MongoDB? Sim, poderia, mas novamente deixaria de aprender algo.</p>
<h2>Resumo da ópera</h2>
<p>Resumindo tudo - (<strong>spoiler</strong>) e aproveitando o que dissemos no VoidPodcast sobre esse assunto - se você é programador e não faz uso de social coding e ao invés disso está apenas usando facebook, orkut, etc: <strong><em>reveja suas crenças e sua profissão</em></strong>.</p>
<p>Todo o código dessas 3 apps está no Github:</p>
<p>UbberElegant: <a href="http://github.com/vquaiato/ubberelegant">http://github.com/vquaiato/ubberelegant</a></p>
<p>Elegant: <a href="http://github.com/juanplopes/elegant">http://github.com/juanplopes/elegant</a></p>
<p>Elegant Code Maker: <a href="http://github.com/ldaniel/ElegantCodeMaker">http://github.com/ldaniel/ElegantCodeMaker</a></p>
Usando TestCase com NUnit2012-02-18T00:00:00-08:00http://viniciusquaiato.com/blog/usando_test_case_com_nunit<p>Fala galera, beleza? Essa é uma dica rápida e eu nem me lembro se já falei sobre isso aqui no blog.</p>
<h2>TestCase com NUnit</h2>
<p>Em algumas ocasiões queremos testar algo com diversos valores diferentes. Podemos escrver diversos testes diferentes ou então podemos usar (no caso do <a href="http://nunit.org/index.php?p=home">NUnit</a>) o <a href="http://nunit.org/?p=testCase&r=2.5">TestCase</a>.</p>
<p>TestCase é um atributo que é colocado sobre o método de testes com valores a serem passados para o método. Na verdade este atributo marca o método como sendo um método de testes.</p>
<p>Vamos a um exemplo simples de como isso pode ser utilizado:</p>
<div class="highlight"><pre><code class="csharp"><span class="na">[Test]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">email_invalido_deve_retornar_false</span><span class="p">(){</span>
<span class="kt">var</span> <span class="n">validador</span> <span class="p">=</span> <span class="k">new</span> <span class="n">ValidadorDeEmails</span><span class="p">();</span>
<span class="n">validador</span><span class="p">.</span><span class="n">Validar</span><span class="p">(</span><span class="s">"email invalido"</span><span class="p">).</span><span class="n">Should</span><span class="p">().</span><span class="n">Be</span><span class="p">.</span><span class="n">False</span><span class="p">();</span>
<span class="p">}</span>
</code></pre>
</div>
<p>Vocês concordam que em um cenário assim eu posso ter uma massa muito grande de emails inválidos para testar? Ao invés de eu escrever um método de teste para cada opção inválida de email eu posso fazer isso:</p>
<div class="highlight"><pre><code class="csharp"><span class="na">[TestCase("inválido")]</span>
<span class="na">[TestCase("foo@bar")]</span>
<span class="na">[TestCase("foo@")]</span>
<span class="na">[TestCase("foo.bar.baz")]</span>
<span class="na">[TestCase("foo bar@baz.com")]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">email_invalido_deve_retornar_false</span><span class="p">(</span><span class="kt">string</span> <span class="n">email</span><span class="p">){</span>
<span class="kt">var</span> <span class="n">validador</span> <span class="p">=</span> <span class="k">new</span> <span class="n">ValidadorDeEmails</span><span class="p">();</span>
<span class="n">validador</span><span class="p">.</span><span class="n">Validar</span><span class="p">(</span><span class="n">email</span><span class="p">).</span><span class="n">Should</span><span class="p">().</span><span class="n">Be</span><span class="p">.</span><span class="n">False</span><span class="p">();</span>
<span class="p">}</span>
</code></pre>
</div>
<p>Desta forma este meu método de teste será invocado uma vez para cada TestCase que eu colocar.</p>
<p>É isso galera! Espero que a dica seja válida, é algo bem simples mas eficiente quando precisamos.</p>
<p>Abraços,</p>
<p>Vinicius Quaiato.</p>
Por uma web melhor2012-01-19T00:00:00-08:00http://viniciusquaiato.com/blog/por-uma-web-melhor<p>Fala galera, beleza?</p>
<p>Há algum tempo eu tenho parado de ler posts e blogs técnicos. Não por que eu ache que eu já sei tudo sobre muita coisa, justamente pelo contrário.</p>
<h2>Uma boa web</h2>
<p>Eu tenho estudado e lido bastante sobre markup, semântica, HTML, CSS, web performance, layout, cores, tipografia, e coisas relacionadas.</p>
<p>Tenho estudado isso pois entendo que é algo fundamental no nosso dia-a-dia enquanto <strong><em>desenvolvedores de produtos pra web</em></strong> e é algo que eu ainda preciso melhorar muito.</p>
<p>Nesses, sei lá, 5 anos de atividade eu dediquei pouquíssimo tempo a isso. Com sorte e alguma mágica eu consegui aproveitar bastante do pouco que estudei e decidi que chegou o momento de aprofundar, melhorar, e ser mais responsável com estas questões.</p>
<p><strong>DISCLAIMER:</strong> <em>se você não trabalha com produtos web, ou possui profissionais que façam toda interface em seus sistemas, ou por algum motivo você só tenha que ser bom em código server side talvez este texto não lhe faça sentido. Ainda assim recomendo que leia.</em></p>
<h2>Não somos designers</h2>
<p>Criar um bom markup: leve, semântico, agradável de ler e fazer este markup ter uma boa aparência quando renderizado não é uma simples tarefa de designer. É claro que criar um layout é algo difícil para nós, não estamos acostumados com isso e julgamos não ter o talento.</p>
<p>O mais interessante é que quando passamos a estudar e observar o design de sites/produtos com um olhar mais crítico/interessado passamos a ver que nem tudo é tão complexo de ser feito/criado. Não estou dizendo que vamos nos tornar designers (embora isso não seja impossível), estou apenas dizendo que nem tudo é tão complexo quanto imaginamos.</p>
<p>É preciso bastante estudo para conseguir criar coisas boas. Seguem alguns links introdutórios sobre o assunto:</p>
<p><a href="http://www.w3.org/2001/sw/">W3C Semantic Web Activity</a></p>
<p><a href="http://blogs.msdn.com/b/jennifer/archive/2011/08/01/html5-part-1-semantic-markup-and-page-layout.aspx">Semantic Markup</a></p>
<p><a href="http://microformats.org/wiki/posh">Plain Old Semantic HTML</a></p>
<h2>Entendendo CSS</h2>
<p>É bem comum vermos ótimos devs que não conhecem nada de CSS e HTML. Acho que isso não é vergonha: temos tanto para estudar que acabamos deixando isso com uma prioridade menor (<em>assim como deixamos outras coisas/linguagens/técnicas com prioridade menor também</em>).</p>
<p>O ponto é que talvez já seja hora de dedicar um pouco mais de tempo para isso. Quantas vezes você já não quis fazer algo <em>bacana</em> em uma página e passou várias horas <em>"hackeando"</em> html e css para tentar (e não conseguiu)? Isso é fruto de desconhecimento e falta de prática.</p>
<p>CSS não é simplesmente uma forma de atribuir cores e tamanho de fonte para elementos. Existe uma série de regras, padrões e detalhes (assim como em uma linguagem de programação) que precisamos conhecer e entender para tirar o melhor proveito (isso sem falar da guerra dos browsers!). E convenhamos que comparado com uma linguagem de programação é bem simples aprender CSS.</p>
<p>Eu diria que 90% do tempo que perdemos com HTML se dá pelo desperdício decorrente da falta de conhecimento em CSS. Então a nossa meta tem que ser transoformar esses 90% em tempo produtivo (abraços aos <a href="http://twitter.com/leandronet">Leandro Daniel</a> que adora as minhas estatísticas).</p>
<p>Como eu não quero ensinar CSS para ninguém aqui seguem alguns links e sites que tenho visto para me inspirar e estudar:</p>
<p><a href="http://css-tricks.com/">CSS Tricks</a></p>
<p><a href="http://www.smashingmagazine.com/">Smashing Magazine</a></p>
<p><a href="http://peepcode.com/blog">Peep Code</a></p>
<p><a href="http://www.css3.info/">CSS3 Info</a></p>
<p><a href="http://www.w3.org/Style/CSS/">W3C CSS</a></p>
<h2>Entendendo o HTML</h2>
<p>Final de semana passado eu decidi abrir meu novo blog em diferentes browsers (até então tinha feito tudo no Chrome/Canary). Para minha surpresa tudo funcionou bem no Safari, Opera e Firefox… mas claro que não funcionou no Internet Explorer.</p>
<p>Tentando validar o site no W3C encontrei algumas inconsistências que de fato eram culpa minha: não bastava culpar o IE.</p>
<p>Depois de corrigir os problemas as coisas magicamente passaram a funcionar nos IE 7, 8 e 9. E na real foram coisas bem simples, pequenos detalhes mesmo.
É claro que algumas coisas de não funcionam ainda no IE mas isso é detalhe, não quebra o layout (mas é importante saber o que o IE renderiza e o que não renderiza também).</p>
<p><a href="http://validator.w3.org/">W3C Validator</a></p>
<p><a href="http://developer.yahoo.com/performance/rules.html">Yahoo - Best Practices for Speeding Up Your Web Site</a></p>
<h2>Tipografia</h2>
<p>É normal ver sites por aí com alguns textos em formatos de imagem, ou então utilizando as <em>boas e velhas Verdana e Arial</em> em toda sua composição.</p>
<p>O ponto é que estudar um pouco de tipografia e usar algumas fonts externas não é algo tão ruim. O Google oferece um serviço com ótimas fonts (algumas bem leves) e que podem fazer uma grande diferença na leitura e visualização do seu conteúdo (às vezes uma boa fonte é tudo que você precisa).</p>
<p>Trabalhar com algum espaçamento nos textos é algo que pode fazer diferença também: margens nos headings, altura das linhas nos parágrafos, espaçamento entre as letras. Tudo isso pode fazer uma enorme diferença se bem aplicado e coeso, bem como entender as diferenças entre Serif, Sans-Serif, Monospace, etc. Estes são aspectos muito importantes e deveras negligenciados por uma enorme massa de desenvolvedores web (eu também ignorava isso).</p>
<p>Vale dar uma olhada em alguns materiais sobre o assunto pois isso pode mudar completamente a experiência em seu produto:</p>
<p><a href="www.smashingmagazine.com/tag/typography/">Smashing Magazine Typography</a></p>
<p><a href="http://webdesignledger.com/inspiration/55-examples-of-huge-typography-in-web-design">55 Typography samples</a></p>
<p><a href="http://mashable.com/2011/11/03/web-typography-101/">Web Typography 101</a></p>
<p><a href="http://www.designzzz.com/typography-basics-serif-vs-sans-serif/">Serif vs Sans-Serif</a></p>
<p><a href="http://www.google.com/webfonts#ChoosePlace:select">Google Web Fonts</a></p>
<h2>Resumindo</h2>
<p>Essa não é uma aula sobre web semântica, HTML, CSS, design, nem nada do tipo. É só um breve relato de como eu tenho enxergado as coisas e absorvido essa experiência. Um pouco do que eu tenho lido e estudado.</p>
<p>Acho que a grande dica é começar a acompanhar quem faz coisas boas nesse sentido, entender como elas são feitas, comparar com outras coisas que julgamos boas também. Aproveitar que na web é possível ficar vasculhando o css e html dos sites e usar isso como forma de compreender mais e mais sobre o tema.</p>
<p>É isso galera.</p>
<p>Abraços,</p>
<p>Vinicius Quaiato.</p>
Raquing Jekyll, Github, Regex e Wordpress2012-01-18T00:00:00-08:00http://viniciusquaiato.com/blog/raquing-jekyll-github-regex-e-wordpress<p>Fala galera, beleza?</p>
<p>Pois bem, depois de decidir sobre como funcionaria o meu novo blog eu tive que pesquisar um pouco sobre como colocar tudo isso para funcionar. (<a href="http://viniciusquaiato.com/tags/jekyll">Veja mais na tag Jekyll</a>)</p>
<h2>Migrando os posts do Wordpress para markdown</h2>
<p>A minha maior preocupação foi entender se era possível e como era possível migrar os posts do Wordpress para o Jekyll.</p>
<p>Dando rápida olhada na documentação do <a href="https://github.com/mojombo/jekyll/wiki/blog-migrations">Jekyll e vemos que ele possui uma série de migrators</a> para importar posts existentes de alguns engines. E como é de se esperar o Wordpress está entre eles.</p>
<p>Das formas de fazer isso com o wordpress a que eu escolhi foi:</p>
<ul>
<li>conectar no mysql do meu blog e fazer um dump</li>
<li>conectar no mysql local e fazer um import</li>
</ul>
<p>Feito isso precisamos rodar o migrator do Jekyll. Antes de rodarmos vamos instalar algumas dependências que ele possui:</p>
<div class="highlight"><pre><code class="sh">sudo gem install mysqlplus
sudo gem install sequel
</code></pre>
</div>
<p>Terminadas as instalações precisamos fazer uma configuração:</p>
<div class="highlight"><pre><code class="sh"><span class="nb">export </span><span class="nv">DYLD_LIBRARY_PATH</span><span class="o">=</span><span class="s2">"/usr/local/mysql/lib/:$DYLD_LIBRARY_PATH"</span>
</code></pre>
</div>
<p>Pronto! Basta convertermos tudo:</p>
<div class="highlight"><pre><code class="sh">ruby -rubygems -e <span class="s1">'require "jekyll/migrators/wordpress"; Jekyll::WordPress.process("database", "user", "pass")'</span>
</code></pre>
</div>
<h3>Tratando os posts com regex</h3>
<p>Depois de realizar a migração eu precisei tratar os posts migrados pois o html dos posts não ficou 100% como eu queria após convertido para markdown.</p>
<p>Estes ajustes até poderiam ser feitos manualmente, post por post. Eu até estava com paciência para isso. O problema é que eu tenho 280 posts que foram migrados e isso acabou com a idéia de fazer manualmente.</p>
<p>Foi então que comecei a me divertir com regex em Ruby. Muita gente diz que Regex é um grande problema, e eu até concordo com isso. Mas acho que neste cenário era o ideal. Eu não estou colocando uma dúzia de regex dentro de um sistema, estou apenas utilizando-as para tarefas pontuais que eu não repetirei mais.</p>
<p>Essa foi uma experiência bem interessante. Regex é meio que um mito/tabu. Muitos nunca as estudaram, não as compreendem e se aproveitam desse papo de que <em>"elas são um problema"</em> para nunca estudá-las e nem utilizá-las. Falácia né…
Algumas das regex que utilizei seguem abaixo:</p>
<div class="highlight"><pre><code class="ruby"><span class="c1">#code format</span>
<span class="n">replace</span><span class="o">.</span><span class="n">gsub!</span> <span class="sr">/{[^\s?\.]/</span><span class="p">,</span> <span class="s2">"{</span><span class="se">\n</span><span class="s2">"</span>
<span class="n">replace</span><span class="o">.</span><span class="n">gsub!</span> <span class="sr">/;(\s*)/</span><span class="p">,</span> <span class="s2">";</span><span class="se">\n</span><span class="s2"> "</span>
<span class="n">replace</span><span class="o">.</span><span class="n">gsub!</span> <span class="sr">/(\s\s+)(var|double|string|decimal|int|bool|void|List<.*>|IEnumerable<.*>)\s/</span><span class="p">,</span> <span class="s2">"</span><span class="se">\n\\</span><span class="s2">2</span><span class="se">\s</span><span class="s2">"</span>
<span class="n">replace</span><span class="o">.</span><span class="n">gsub!</span> <span class="sr">/^(public|private|protected|internal|static)\s/</span><span class="p">,</span> <span class="s2">"</span><span class="se">\n\\</span><span class="s2">1</span><span class="se">\s</span><span class="s2">"</span>
<span class="n">replace</span><span class="o">.</span><span class="n">gsub!</span> <span class="sr">/\s+(if|for|foreach|do|while)\s?({|\()/</span><span class="p">,</span> <span class="s2">"</span><span class="se">\n\\</span><span class="s2">1</span><span class="se">\\</span><span class="s2">2"</span>
<span class="n">replace</span><span class="o">.</span><span class="n">gsub!</span> <span class="sr">/\s+(return)(\s.*);/</span><span class="p">,</span> <span class="s2">"</span><span class="se">\n\\</span><span class="s2">1</span><span class="se">\\</span><span class="s2">2;"</span>
</code></pre>
</div>
<p>A lista completa está aqui: <a href="https://github.com/vquaiato/vquaiato.github.com/blob/master/_raquer_scripts/regex_raque.rb">regex_raque.rb</a></p>
<p><strong>Disclaimer:</strong> <em>As regex que utilizei não tem nada a ver com o Jekyll. Foi apenas uma forma que eu encontrei de ajustar alguns posts. Isso tudo está em um arquivo separado que eu rodei manualmente isolado do Jekyll.</em></p>
<h2>Importando as imagens</h2>
<p>Terminada essa minha fase de migração e ajustes (que ainda necessitam de retoques manuais) eu parti para algumas outras migrações como por exemplo as imagens.</p>
<p>Eu já não queria mais a estrutura de pastas do wordpress para manter as imagens dos meus posts então resolvi jogar todas as imagens dos posts em um diretório só.</p>
<p>Isso foi bastante simples visto que eu já tinha todos os posts em arquivos locais. Bastaria eu percorrer todos estes arquivos, procurar as urls de imagens e então baixá-las do servidor. É óbvio que eu não faria isso na unha, então criei um script Ruby que me ajudou:</p>
<div class="highlight"><pre><code class="ruby"><span class="no">Dir</span><span class="o">.</span><span class="n">foreach</span><span class="p">(</span><span class="s2">"../_posts/"</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">file</span><span class="o">|</span>
<span class="k">begin</span>
<span class="n">content</span> <span class="o">=</span> <span class="no">File</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="s2">"../_posts/</span><span class="si">#{</span><span class="n">file</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
<span class="n">images_found</span> <span class="o">=</span> <span class="n">content</span><span class="o">.</span><span class="n">scan</span> <span class="sr">/http\S*\.[jpg|gif|png]+/i</span>
<span class="n">images_found</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">img</span><span class="o">|</span>
<span class="nb">system</span> <span class="s2">"curl </span><span class="si">#{</span><span class="n">img</span><span class="si">}</span><span class="s2"> -O"</span>
<span class="k">end</span>
<span class="k">rescue</span>
<span class="nb">p</span> <span class="s2">"shit </span><span class="si">#{</span><span class="n">file</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
</div>
<p><strong>Disclaimer:</strong> <em>Não sei se essa é a melhor regex do mundo (provavelmente não pois eu tinha medo delas antes dessa brincadeira) mas ela funcionou bem para baixar minhas mais de 900 imagens.</em></p>
<h2>Alguns ajustes finais</h2>
<h3>Syntax highlight</h3>
<p>O Jekyll faz uso da biblioteca pygments para syntax highlight. <a href="http://pygments.org/demo/">Aqui podemos ver uma lista de linguagens que ele coloriza e uma série de arquivos de estilo para estas linguagens</a>.</p>
<h3>Biblioteca markdown</h3>
<p>Além disso a biblioteca padrão para markdown do Jekyll é o Makuru. Pelo que andei lendo o RDiscount é melhor e mais rápido que ele, então eu preferi usá-lo.
Para isso basta adicionarmos uma linha ao arquivo <em>_config.yml</em></p>
<div class="highlight"><pre><code class="ruby"><span class="n">markdown</span><span class="p">:</span> <span class="n">rdiscount</span>
</code></pre>
</div>
<p>E instalarmos essa gem:</p>
<div class="highlight"><pre><code class="sh"><span class="nv">$ </span><span class="o">[</span>sudo<span class="o">]</span> gem install rdiscount -s http://gemcutter.org
</code></pre>
</div>
<h3>Gerando as tags</h3>
<p>Todas as tags dos posts no Jekyll vão em uma espécie de header YAML. Para gerar as páginas de tags (que listam todos os posts de uma tag) eu utilizei uma rake task, desta forma eu faço no console algo como</p>
<div class="highlight"><pre><code class="sh">rake tags:generate
</code></pre>
</div>
<p>E pronto! Minhas pastas e arquivos estão gerado, tudo estático :D
<a href="https://github.com/vquaiato/vquaiato.github.com/blob/master/Rakefile">Essa rake task pode ser encontrada aqui</a>.</p>
<h2>Resumindo</h2>
<p>Desta forma fica bem claro como é simples fazer uma migração e algumas configurações para iniciar o uso do Jekyll a partir de um blog já existente.</p>
<p>Essa brincadeira toda de script e regex se torna bastante divertida quando estamos brincando com Ruby. Basta escrever meu script em um arquivo texto e executar com um simples <em>ruby nome_do_arquivo.rb</em> e pronto! A coisa se torna bastante rápida e produtiva.</p>
Como funciona o Jekyll2012-01-16T00:00:00-08:00http://viniciusquaiato.com/blog/como-funciona-o-jekyll<p>Fala galera, jóia?</p>
<p>Estou devendo um pouco de explicação sobre o funcionamento do <a href="https://github.com/mojombo/jekyll/wiki">Jekyll</a> (que é o novo blog engine que estou utilizando). Então de uma maneira bem simples vamos lá.</p>
<h2>O que é o Jekyll</h2>
<p>Jekyll nada mais é do que um transformador de textos para blogs. Simples assim. Ele é capaz de transformar texto em um incrível post de blog.</p>
<h2>Como o Jekyll funciona</h2>
<p>O Jekyll trabalha com textos em formato <a href="http://pt.wikipedia.org/wiki/Markdown">Markdown</a> ou <a href="http://en.wikipedia.org/wiki/Textile_(markup_language)">Textile</a>. Além disso usa <a href="http://liquidmarkup.org/">Liquid</a> para quando é necessário algum tipo de código para templating.</p>
<p>Escrever com Markdown nos dá a possibilidade de escrever posts quase que puramente em formato texto. Uma vez que nossos layouts estão prontos o Jekyll se encarrega de transformar o texto em HTML com o devido layout.</p>
<p>O Jekyll trabalha com um mecanismo muito simples: Você informa qual o layout o post utilizará e ponto ele transforma seu texto em um HTML com o layout especificado. Isso é tão bacana que é possível ter diferentes layouts por posts. Com o mínimo de esforço. É realmente muito bom.</p>
<p>Um layout nada mais é do que um arquivo HTML que fica na pasta <em>_layouts</em> do Jekyll.</p>
<p>Todos os posts ficam na pasta <em>_posts</em> e então quando o Jekyll começa a executar ele transforma tudo da pasta <em>_posts</em> e joga para uma pasta chamada <em>_site</em>.</p>
<p>Como ele faz isso? Bem simples:</p>
<pre><code>jekyll --server --auto
</code></pre>
<p>Com isso o Jekyll começa a executar e então faz a geração de qualquer arquivo novo/alterado automaticamente.</p>
<p><em>Veja a estrutura do Jekyll <a href="https://github.com/vquaiato/vquaiato.github.com">aqui no fonte do meu blog</a></em></p>
<h2>Jekyll é só para rubistas?</h2>
<p>Eu diria que Jekyll é muito menos sobre Ruby e muito mais sobre o prazer de ter um blog simples, leve e com foco no conteúdo.</p>
<p>É mais sobre gostar de escrever e fazer isso de uma forma simples e prática do que sobre uma linguagem ou plataforma.</p>
<p>Existem alguns ports do Jekyll para outras linguagens/plataformas: <a href="https://github.com/jaspervdj/hakyll">Hakyll em Haskell</a>, <a href="https://github.com/christiansmith/hekyll">Hekyll em Notch/Node.js</a>, etc. É mais para quem curte escrever textos de maneira simples e direta mesmo. Mas o mais incrível disso tudo é que é simples trabalhar com ele. Você não sente em nenhum momento o <strong>peso</strong> de estar usando o Jekyll.</p>
<p>Não ter/precisar de uma interface de adminsitração é incrível. Eu controlo tudo via repositório Git e isso é sensacional. É exatamente o que precisamos quando estamos escrevendo textos/códigos/documentos. E esse é o mais incrível modo de fazer versionamento. Sem a complicação de versionar tudo em um banco de dados <em>blergh</em>.</p>
<h2>Resumindo</h2>
<p>O Jekyll é uma forma simples de transformar texto em blog. O blog será tão simples quanto sua criatividade e vontade. Hoje eu não preciso mais lidar com chatos uploads de imagens: eu trabalho tudo na pasta <em>imagens_posts</em> e pronto um simples <em>git add . && git commit -m</em> resolvem tudo pra mim.</p>
<p>É claro que há quem prefira criar e manter um blog de outras formas, e isso é absolutamente normal. Mas é muito bom saber se novas formas. Mas eu fico feliz em dizer que agora não preciso mais me preocupar com atualizações do engine constantes, atualizações de plugins, configurações de bancos de dados, servidor, etc. Apenas escrevo :D</p>
<p>Abraços,</p>
<p>Vinicius Quaiato.</p>
Like a Raquer: Blogando com Jekyll e Github Pages2012-01-07T00:00:00-08:00http://viniciusquaiato.com/blog/like-a-raquer-blogando-com-jekyll-e-github-pages<p>Fala galera! Ano novo, vida velha e <strong>blog novo!</strong></p>
<h2>Saí do Wordpress</h2>
<p>Desde que comecei com o meu blog eu estive usando o Wordpress em um servidor meu.
O Wordpress é uma ferramenta incrível: fácil de usar, zillions of buzzions of plugins, temas pra dar e (literalmente) vender, etc, etc, isso que todo mundo já sabe.</p>
<p>Não vou dizer que a ferramenta é ruim pois ela não é. Simplesmente já não servia bem ao meu estilo de trabalho :P</p>
<h2>Como eu gosto de trabalhar</h2>
<p>Um dos motivos pelos quais há algum tempo eu vinha pensando em largar o Wordpress é que eu gosto de escrever: formatar, colocar código fonte, quotes, listas, etc, e eu sempre fiz(e preferi) isso na mão, ou seja, como HTML mesmo.
Eu gosto bastante de estar no editor de textos mas o editor do Wordpress é meio complicado: se eu usasse o editor visual o HTML ficava horrível, se eu usasse o editor HTML… bem… eu tinha que escrever em HTML (que é quase tão sacal quanto XML né…)
Eu nunca gostei de ferramentas de publicação exatamente pelo mesmo motivo.</p>
<h2>Estendendo, adptando, modificando</h2>
<p>Quem conhece o Wordpress e já precisou customizar algo sabe que isto não é o melhor dos mundos. Ainda que as coisas estejam documentadas isso se torna meio complexo, afinal é um sistema grande e para ter certeza sobre o que se está fazendo leva tempo: não é divertido e nem fácil.
Existem muitos plugins sim, mas quando você começa a usar vários deles eles começam a conflitar e é um Deus nos acuda. Mas ainda assim a ferramenta é muito boa para quem precisa disso.</p>
<h2>Jekyll</h2>
<p>Pensando nisso tudo foi que aceitei a sugestão do <a href="http://github.com/juanplopes">Juan Lopes</a> e <a href="http://twitter.com/rs_felix">Rafael Felix</a> que recomendaram o <a href="https://github.com/mojombo/jekyll">Jekyll</a>. A grosso modo o Jekyll é um gerador de site estático. Isso mesmo: um gerador de site estático.</p>
<p>Pequeno e facilmente customizável ele gera arquivos HTML a partir de arquivos markdown e/ou textile.
Com isso eu consigo agora escrever todos os meus posts utilizando <a href="http://pt.wikipedia.org/wiki/Markdown">markdown</a> que é algo bem mais simples e amigável do que HTML (e sim ele gera HTML válido!)</p>
<p>O Jekyll é escrito em Ruby e trabalha com um sistema de layouts para os arquivos. É possível customizar cada um dos posts para usar um layout diferente. A coisa toda fica muito simples de usar, configurar e estender.</p>
<h2>Github</h2>
<p>O <a href="http://github.com">Github</a> como todos sabem é algo muito bacana. Já está muito além de um simples repositório de código: é uma plataforma social para developers e projetos.
O Github possui um serviço chamado <a href="http://pages.github.com/">Github Pages</a> que nos permite publicar conteúdo na web a partir de um repositório de código.
E quem já conhece o <a href="http://github.github.com/github-flavored-markdown/">Github sabe que ele se dá muito bem com markdown</a> e além de se dar bem com markdown o Github Pages consegue subir um site usando Jekyll.</p>
<p>Somando tudo isso então quer dizer que eu posso escrever meu blog praticamente em texto puro, utilizando um repositório Git (isto é meu blog está versionado de forma simples, eficiente e aberto), publicando com um simples <em>git push</em>.</p>
<p>No próximo post eu darei os detalhes técnicos de como é criar, subir e customizar a app Jekyll no Github, como migrar os posts do Wordpress, os problemas que encontrei, regex que utilizei para limpar os posts vindos do Wordpress, dicas e algo mais.</p>
<h2>Resumindo</h2>
<p>Estou contente por poder escolher novas tecnologias, olhar para coisas que não são consideradas <em>mainstream</em>, poder experimentar tecnologias novas sem medo de que não são as mais usadas, ou as melhores, etc.
Minha escolha foi por algo que me desafiasse, que me desse conforto na forma como estou trabalhando.
Quero que fique bem claro que não quero convencer ninguém a largar o Wordpress. Estou apenas apresentando uma alternativa (dentre muitas) e que tem me satisfeito :)</p>
<p>Todo o código deste blog, posts, layout, imagens estão no github e podem ser forkados, fuçados, comentados, etc, neste repositório: <a href="http://github.com/vquaiato/vquaiato.github.com">http://github.com/vquaiato/vquaiato.github.com</a></p>
<p>Abraços,</p>
<p>Vinicius Quaiato.</p>
Por que não troquei o .NET pelo Ruby?2011-10-29T00:00:00-07:00http://viniciusquaiato.com/blog/por-que-nao-troquei-o-net-pelo-ruby<p><a href="http://viniciusquaiato.com/images_posts/REM-Losing-My-Religion.jpg"><img src="http://viniciusquaiato.com/images_posts/REM-Losing-My-Religion-300x225.jpg" title="REM - Losing My Religion" alt="" /></a></p>
<p>Fala galera. Estou sumido hein? Vamos lá...Como alguns devem saber é comum vermos posts do tipo <a href="http://whatupdave.com/post/1170718843/leaving-net">"por que troquei o .NET pelo Ruby"</a>, <a href="http://osherove.com/blog/2010/12/30/hire-me-as-your-ruby-intern-for-a-year.html">aqui</a> e <a href="http://just3ws.posterous.com/why-are-altnet-developers-moving-towards-ruby">aqui</a>. Mas hoje eu quero dizer o <strong>por que eu não estou deixando o .NET/C#</strong>.</p>
<h2>Trabalhando com Ruby</h2>
<p>Como alguns de vocês devem saber eu sempre gostei de <a href="http://www.ruby-lang.org/en/">Ruby</a>. É uma linguagem bonita. É expressiva. É poderosa. É simples. E não, ela não é perfeita.Estou na Crafters há uns 5 meses e na <a href="http://crafters.com.br">Crafters</a> não temos uma linguagem como "lema", criamos software, independente da linguagem/plataforma. Temos vários projetos em Ruby/Rails é verdade, mas também temos projetos em Java, Groovy/Grails, fizemos coisas em Scala, e fizemos sim coisas em .NET/C# para Windows Phone, Windows Azure, ASP.NET MVC, etc.Tenho trabalhado muito com Ruby. Tem sido a linguagem/tecnologia na qual passo maior parte do meu tempo. Mas eu percebi que isso não quer dizer que eu "larguei o .NET". Na verdade isso quer dizer que hoje eu sei quando e por que usar o .NET.</p>
<h2>Losing my religion</h2>
<p>Hoje eu posso, com muito orgulho, dizer que deixei totalmente as linguagem e plataformas de lado enquanto religiões.Muita gente gosta de dizer que "é developer pois é apaixonado por código" <del datetime="2011-10-29T00:30:48+00:00">(bullshit, em 90% dos casos)</del> mas trata código como literatura sagrada, e se não estiver em sua "língua materna" é coisa do <a href="http://www.youtube.com/watch?v=GeP6l3JDBrw">"demônio"</a>.Acho que além de sermos "poliglotas" devemos buscar ser <a href="http://pt.wikipedia.org/wiki/Ecumenismo">ecumênicos</a>.Muitas <del datetime="2011-10-29T00:30:48+00:00">verdades</del> coisas que eu achava serem verdades não passavam de uma falsa percepção de realidade. Quando contamos uma mentira várias vezes passamos a acreditar nela como verdade.Muito do que eu acreditava ser "o jeito certo de fazer" já não existe mais. Muito sobre isso eu falei na <a href="http://viniciusquaiato.com/blog/yagni-no-dnad11-videos-da-palestra/">minha palestra no DNAD 11</a>.</p>
<h2>Deixei o Windows e o .NET de lado</h2>
<p>Há uns 7 meses eu deixei de usar Windows como meu sistema operacional padrão. Sim, hoje eu uso um Mac até mesmo quando preciso usar Windows. Esta mudança me fez um grande bem. Colaborou muito para conhecer <ins datetime="2011-12-27T14:28:20+00:00">e fazer (<a href="https://github.com/vquaiato/hubot-scripts" title="Hubot">isso</a>, <a href="https://github.com/vquaiato/memish" title="Memish">isso</a> e <a href="https://github.com/vquaiato/better-fifa-raquer/blob/master/raquering.rb" title="Raquer">mais isso</a>)</ins> coisas novas. Olhar para coisas que eu fazia de uma maneira por um outro prisma. Eu não estou dizendo que Windows é ruim: não é possível dizer isso. Mas eu estou dizendo que só conhecer e só usar Windows me fazia <del datetime="2011-10-29T00:30:48+00:00">uma pessoa pior</del> um desenvolvedor não tão bom.Hoje eu conheço mais tecnologias do que antes. Mesmo no Windows eu buscava fugir do mundo .NET padrão: eu brinquei com <a href="http://viniciusquaiato.com/blog/tag/ironruby/">IronRuby</a> e IronPython, conheci Ruby/Rails no Windows. Eu já brincava com <a href="http://viniciusquaiato.com/blog/tag/boo/">Boo</a> e <a href="http://viniciusquaiato.com/blog/tag/mono/">Mono</a>. Usei Java e conheço PHP. Trabalhava com MySQL, SQL Server, e já usava <a href="http://viniciusquaiato.com/blog/tag/nosql/">NoSQL</a> no Windows. <del datetime="2011-10-29T00:30:48+00:00">Mexia</del> Brincava com <a href="http://viniciusquaiato.com/blog/tag/nodejs/">Node.Js</a>. Depois de conhecer o <a href="http://viniciusquaiato.com/blog/tag/git/">Git</a> não parei de usar. E por aí vai.Mas o fato de não poder rodar o Visual Studio nativamente no OSX me fez buscar maneiras diferentes de fazer coisas antigas: eu quebrei meus próprios paradigmas, eu ignorei meus próprios dogmas.</p>
<h2>Conheci pessoas apaixonadas</h2>
<p>Quando comecei, há bastante tempo, conviver com outras comunidades que não apenas as comunidades Microsoft/.NET passei a conhecer gente apaixonada pelo que faz. Apaixonada por suas linguagens e tecnologias. Mas mais do que isso passei a conhecer gente que faz coisas. Passei a conhecer gente que é apaixonada por algo não por que é feito por uma empresa, mas sim por que várias características nessas tecnologias os deixavam assim. Passei a conhecer pessoas que não tinham medo de perder a paixão simplesmente por trabalhar com algo diferente.Infelizmente no mundo Microsoft/.NET esse tipo de pessoa é minoria, mas uma minoria muito, muito, muito rara de encontrar. O que sempre vemos são pessoas que "usam o que vem da Microsoft". Sem saber os por ques. E falo isso com conhecimento de quem vive há mais de 4 anos entre estas pessoas (e se considera uma delas). Poucas pessoas no mundo .NET são como o <a href="http://twitter.com/juanplopes">Juan Lopes</a> que sabe exatamente por que gosta de C#. (você sabe por que você gosta de C#?).</p>
<h2>Quem só conhece martelo só dá marteladas</h2>
<p>Quem só conhece uma forma de resolver todos os problemas na verdade não resolve nada. Hoje eu sei que estou muito mais apto a resolver diferentes problemas do que estava há 6 meses.Hoje eu consigo ter uma visão de produto e consigo decidir, com propriedade, entre diversas tecnologias/plataformas para atender a esta visão de produto. Hoje é minha necessidade quem dita as regras e não minha tecnologia que <del datetime="2011-10-29T00:30:48+00:00">esquarteja</del> molda minhas necessidades.E hoje eu posso afirmar: ler meia dúzia de posts, ter visto meia dúzia de gists, e lido meia dúzia de tutoriais não te fazem conhecer de uma linguagem/tecnologia/plataforma a ponto de poder considerá-la boa ou ruim. E o pior: só conhecer uma tecnologia, mesmo que a fundo, também não te faz apto a isso.</p>
<h2>Por que o .NET é bacana?</h2>
<p>Hoje eu acho o modelo de desenvolvimento para o novo Windows Phone sensacional. Eu gosto muito da forma como posso criar apps incríveis para estes devices.Eu acho a plataforma de cloud computing da <a href="http://viniciusquaiato.com/blog/tag/windows-azure/">Microsoft, o Azure</a>, muito boa, acessível e eficiente.É simplesmente formidável fazer algo em .NET: você abre o Visual Studio e pronto!Isso não existe em outros mundos: não existe em Ruby, Rails, Java, Grails, PHP, Ruby, etc. É sempre <del datetime="2011-10-29T00:30:48+00:00">um parto</del> um pouco mais complicado que isso :P (estou falando em bootstrap de ambiente hein!).Em .NET é simples fazer algumas coisas que em outras tecnologias são chatas/complexas. É uma plataforma muito <del datetime="2011-10-29T00:30:48+00:00">animal</del> boa (e é uma pena que nem todos enxerguem isso, ainda tem gente que confunde tudo).Do Windows eu não sinto saudades mesmo. Hoje eu tenho um ambiente virtualizado e tento sempre usar as coisas em modo seamless, então eu mal o vejo ;)</p>
<h2>Deixar o blá blá blá de lado</h2>
<p>Aquele papo de aprender um nova linguagem por ano. Eu conheço várias linguagens, etc, etc. Isso é história para boi dormir. Fazer meia dúzia de "Hello World", participar de alguns dojos, etc, não te faz um poliglota: pare de se enganar.Aprender uma nova linguagem só te fará melhor quando você sair da zona de conforto. Quando você passar um bom tempo progamando (mesmo!).</p>
<h2>Por que escrever tudo isso?</h2>
<p>Não há motivos. Talvez por que exista muito potencial reprimido por aí. Sei lá.</p>
Escrever código em inglês ou português?2011-10-01T00:00:00-07:00http://viniciusquaiato.com/blog/escrever-codigo-em-ingles-ou-portugues<p><a href="http://viniciusquaiato.com/images_posts/atrito.jpg"><img src="http://viniciusquaiato.com/images_posts/atrito-300x229.jpg" title="atrito" alt="" /></a></p>
<p>Fala galera, beleza? Essa semana tive uma discussão no twitter com alguns amigos (<a href="http://twitter.com/porcelli">@porcelli</a>, <a href="http://twitter.com/felipero">@felipero</a>, <a href="http://twitter.com/scaphe">@scaphe</a>, <a href="http://twitter.com/elemarjr">@elemarjr</a>, <a href="http://twitter.com/lucabastos">@lucabastos</a> e mais um monte) onde discutimos <strong><em>a necessidade de escrever código em inglês ou em português</em></strong>.Eu defendi <strong>a escrita do código de negócio na linguagem do cliente</strong>, ou seja, na linguagem do próprio negócio. E pretendo explicar algumas razões desta minha preferência.</p>
<h2>O especialista no problema</h2>
<p>Quando eu vou para uma reunião tentar compreender o problema que preciso resolver geralmente o cliente(quem nos pede para resolver um problema) possui uma série de termos específicos sobre seu negócio. Estes termos não podem ser diretamente mapeados para "classes" dentro do nosso sistema. Muitas vezes estes termos designam processos e operações que vão vir a ser escritos como um grupos de classes/objetos interagindo.Por mais que você ache que seu cliente "não sabe o que quer" ele é o especialista no assunto. Ele definitivamente não sabe e não precisa saber nada sobre software mas ele sabe tudo sobre o problema a ser resolvido. Então é importante ficar atento aos termos dele, mapear as interações, relações, especialidades, processos e atribuições de cada pedaço do negócio que ele nos conta.<blockquote>Quando um usuário finaliza um pedido então uma compra é gerada no sistema com todas as informações inclusive o pagamento</blockquote></p>
<h2>Traduzir o problema</h2>
<p>Dado que não somos os especialistas no problema por que motivos saímos de uma reunião onde acabamos de escutar um monte de coisas novas e complexas e traduzimos isso para uma língua que não é a nossa língua nativa?Temos dois pontos para observar aqui:1. Ainda não entendemos o problema por completo. Uma ou duas reuniões não são suficientes para isso.
2. Pegamos um problema que não entendemos e o colocamos em uma língua que não é nossa especialidade
Qual o problema de traduzir as coisas para o inglês? Sejamos simples: você já pegou um texto em português e traduziu para o inglês? Quando você é <strong>muito bom</strong> em inglês você até consegue fazer isso mesmo sabendo que não ficou 100% como você queria, afinal o português é mais rico, possui peculiaridades, etc. Mas ainda assim você fica relendo o texto e vendo se está de acordo com o texto em português original.O seu cérebro fica fazendo esse mapeamento e esse "de-para" constantemente.</p>
<div class="highlight"><pre><code class="csharp"><span class="k">public</span> <span class="k">class</span> <span class="nc">User</span><span class="p">{</span>
<span class="k">public</span> <span class="n">Shop</span> <span class="nf">Finish</span><span class="p">(</span><span class="n">Request</span> <span class="n">aRequest</span><span class="p">){...}</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">Request</span><span class="p">{...}</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">Shop</span><span class="p">{...}</span>
</code></pre>
</div>
<p>Acima fica bem nítido que Request será constantemente mapeado mentalmente para Pedido. O termo se perde em meio ao código. Request não me faz pensar em Pedido por mais que eu mesmo tenha escrito isso.</p>
<h2>As dificuldades de comunicação</h2>
<p>Dado que agora você traduziu tudo isso, para o inglês por exemplo, as comunicações entre a equipe começam a ter <a href="http://pt.wikipedia.org/wiki/Atrito">atrito</a>. Todos no time vão começar a fazer um "de-para" dos termos de negócio para os termos do código. Quando ocorrem reuniões de entendimento com o especialista do problema a coisa é pior ainda. Pois o especialista entra em detalhes que você não domina e para tentar chegar até este ponto de entendimento você tenta mapear o que ele diz com o código mas o código está em outra língua, outros termos. O raciocínio começa a ficar prejudicado.<blockquote>Todas as compras possuem pelo menos um pedido e possuem pelo menos um pagamento. Quando o pagamento é à vista as compras só possuem um pagamento.</blockquote>Então o time fica pensando... :</p>
<div class="highlight"><pre><code class="csharp"><span class="c1">//pagamento à vista</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">InvoicePayment</span> <span class="p">:</span> <span class="n">Payment</span><span class="p">{...}</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">CreditCardPayment</span> <span class="p">:</span> <span class="n">Payment</span><span class="p">{...}</span>
</code></pre>
</div>
<p>É claro que o cerébro é poderoso e consegue fazer isso mas isso não quer dizer que ele não precise trabalhar muito para isso.</p>
<h2>Buscando uma melhor comunicação entre a equipe</h2>
<p>Em geral não é um time inteiro que tem reuniões com o especialista de domínio (embora possamos achar que isso seria o ideal). Quando uma parte da equipe possui informações sobre o domínio e então traduz isso da forma como acha melhor isso vai gerar um enorme <strong>ruído</strong> no projeto.Para quem não está com o cenário todo desenhado na cabeça e está convivendo apenas com as traduções o entendimento do problema como um todo fica comprometido e parece que estas pessoas apenas escrevem código, por escrever. Se em algum momento estas pessoas precisarem questionar o especialista de domínio sobre algo provavelmente o farão de forma rasa e sem entendimento da resposta.</p>
<div class="highlight"><pre><code class="csharp"><span class="k">public</span> <span class="k">class</span> <span class="nc">ShopService</span><span class="p">{</span>
<span class="k">private</span> <span class="n">StockAvailability</span> <span class="nf">VerifyAvaialability</span><span class="p">(</span><span class="n">ShopItemCollection</span> <span class="n">items</span><span class="p">){...}</span>
<span class="k">private</span> <span class="kt">bool</span> <span class="nf">AcceptsMultiplePayments</span><span class="p">(</span><span class="n">Request</span> <span class="n">aRequest</span><span class="p">){...}</span>
<span class="p">...}</span>
</code></pre>
</div>
<h2>Mescla de idiomas</h2>
<p>Quando o domínio está traduzido e poucas pessoas do time de fato possuem uma visão geral do problema é normal que os outros membros do time comecem a implementar novas funcionalidades em português. Isso acontece pois eles sentem que a parte traduzida está complicada e não é de simples entendimento. O código metade inglês e metade português é uma tentativa de torná-lo mais expressivo.</p>
<div class="highlight"><pre><code class="csharp"><span class="k">public</span> <span class="k">class</span> <span class="nc">ShopService</span><span class="p">{</span>
<span class="k">private</span> <span class="n">StockAvailability</span> <span class="nf">VerifyAvaialability</span><span class="p">(</span><span class="n">ShopItemCollection</span> <span class="n">items</span><span class="p">){...}</span>
<span class="k">private</span> <span class="kt">bool</span> <span class="nf">AcceptsMultiplePayments</span><span class="p">(</span><span class="n">Request</span> <span class="n">theRequest</span><span class="p">){...}</span>
<span class="k">private</span> <span class="kt">bool</span> <span class="nf">PossuiPagamentoAVista</span><span class="p">(</span><span class="n">Request</span> <span class="n">theRequest</span><span class="p">){...}</span>
<span class="p">...}</span>
</code></pre>
</div>
<h2>Mas a linguagem é inglês</h2>
<p>Não há como comparar as instruções da linguagem (class, for, foreach, while, if, else, public, private, etc) com operações e conceitos de domínio. Eles representam apenas infraestrutura e suporte para todo o problema a ser resolvido. Não fazem parte do vocabulário cotidiano do software. Quando temos código claro esses detalhes de infra passam desapercebidos.</p>
<div class="highlight"><pre><code class="csharp"><span class="kt">bool</span> <span class="n">PERMITE</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
<span class="kt">bool</span> <span class="n">NÃO_PERMITE</span> <span class="p">=</span> <span class="k">false</span><span class="p">;</span>
<span class="k">private</span> <span class="kt">bool</span> <span class="nf">PermiteMultiplasFormasDePagamento</span><span class="p">(</span><span class="n">Pedido</span> <span class="n">oPedido</span><span class="p">){</span>
<span class="k">if</span><span class="p">(</span><span class="n">oPedido</span><span class="p">.</span><span class="n">PossuiPagamentoAVista</span><span class="p">)</span>
<span class="k">return</span> <span class="n">NÃO_PERMITE</span><span class="p">;</span>
<span class="k">return</span> <span class="n">PERMITE</span><span class="p">;</span>
<span class="p">}</span>
</code></pre>
</div>
<h2>Domain Driven Design</h2>
<p>Na verdade eu <del datetime="2011-10-01T13:12:11+00:00">"estou me lixando" para o DDD neste caso</del> nem estou falando sobre DDD aqui. Não é por este motivo que eu tento escrever o código na linguagem do negócio. Isso pode me ajudar a ter uma "linguagem onipresente" em todo o projeto, mas essa não é a razão.</p>
<h2>Resumo</h2>
<p>Todos os motivos que citei acima, em principal o <strong>atrito na comunicação</strong> são problemas que eu vivenciei em diversos projetos. Sempre que passei por estas situações, por melhor que seja meu inglês e de outros membros do time, a conversa diária com o cliente não é em inglês e isso sempre se mostrou um problema. É importante ressaltar, porém, que esse problema não é fatal ele apenas gera dificuldade e demora no entendimento(principalmente quando é preciso explicar o domínio usando código para outros membros do time).No entanto se tivermos um domínio simples, ou que não seja extenso, esse atrito é menor ou pode passar a não existir (mas eu me arrisco a dizer que são poucos os sistemas que possuem domínios simples).No final das contas vai de cada um também. Escrever código em inglês é estética afinal ele não agrega estando em inglês. E mais importante que isso: <strong>escrever código em inglês não prova em nada que você sabe falar inglês ok?!</strong>Não é vergonha nenhuma preferir escrever código de domínio na língua natal. Não pense que fazer isso mostrará aos outros que você não sabe inglês. Escrever meia dúzia de palavra sem outro idioma não prova nada.É importante frisar também que o código será trabalhado por diversas pessoas e todas precisam estar confortáveis com a forma como ele está escrito. Todos precisam estar com pleno entendimento do domínio e ler código e ter reuniões no mesmo idioma auxiliam em muito nesta tarefa.Essa é apenas a minha opinião e experiência. Não é uma verdade para todos. E vocês o que acham? Como preferem? Por quais motivos?</p>
<p>Abraços,
Vinicius Quaiato.</p>
Void Podcast - um bate papo descontraído sobre TI2011-09-27T00:00:00-07:00http://viniciusquaiato.com/blog/void-podcast-um-bate-papo-descontraido-sobre-ti<p><a href="http://viniciusquaiato.com/images_posts/IMG_0874.jpg"><img src="http://viniciusquaiato.com/images_posts/IMG_0874-225x300.jpg" title="Void Podcast - @vquaiato, @leandrodaniel e @elemarjr" alt="Void Podcast - @vquaiato, @leandrodaniel e @elemarjr" /></a></p>
<p>Fala galera como alguns de vocês já devem saber há algum tempo eu e mais 2 senhores iniciamos um projeto de podcast: <a href="http://voidpodcast.com">Void Podcast</a>. E finalmente decidi escrever sobre ele.</p>
<h3>O nome</h3>
<p>O nome <a href="http://voidpodcast.com">Void Podcast</a> surgiu dentre diversos nomes, discutidos via DM no twitter :P A idéia é ter um podcast "vazio e que não retorne valor". Isso quer dizer que não temos pretensões e não que somos ruins :P</p>
<h3>Os envolvidos</h3>
<p>Os envolvidos neste projeto são: <a href="http://reverb.leandrodaniel.com">Leandro Daniel</a> (vulgo Barba), <a href="http://elemarjr.net">Elemar Júnior</a> (cujo nome é Eleonor) e <a href="http://viniciusquaiato.com">eu</a> (vulgo eu).</p>
<h3>A idéia</h3>
<p>O <a href="http://voidpodcast.com">Void Podcast</a> nasceu de/para ser uma conversa entre amigos, em um clima descontraído, assim como fazemos em happy hours. Às vezes discutindo sobre tecnologia, outras vezes não. O <a href="http://voidpodcast.com">Void Podcast</a> também nasceu sem pretensões: não esperamos ser um podcast famoso, não mantemos periodicidade, não definimos pautas, não convidamos outras pessoas... mas tudo isso não quer dizer que não podemos aspirar ser um podcast famoso, termos periodicidade, definirmos pautas e convidarmos outras pessoas.</p>
<h3>Os temas</h3>
<p>Geralmente falamos sobre temas agnósticos de tecnologia, ou seja, você não nos verá falando sobre GridView, ASP.NET MVC x WebForms, nem nada do tipo. Até o momento já falamos sobre comunidades, carreira, qualidade de vida, complexidade, etc. Já estamos no nosso 10º episódio, coisas bacanas já rolaram. Temos um backlog bem bacana com próximos temas <o/</p>
<h3>O convite</h3>
<p>Convido vocês então a escutar e ver o que acham. Geralmente adotamos um tom sarcástico, como se realmente estivéssemos em uma mesa de bar. O feedback que temos tido até o momento tem sido bastante positivo e cada vez mias pessoas estão escutando. Temos sido cada vez mais elogiamos pelas trilhas sonoras e edições do grande Leandro :P</p>
<h3>Como ouvir o Void Podcast?</h3>
<h1>#</h1>
<h3>Site</h3>
<p>Você pode ouvir/baixar o Void Podcast diretamente no site: <a href="http://voidpodcast.com">http://voidpodcast.com</a></p>
<h1>#</h1>
<h3>iTunes</h3>
<p>Você pode se inscrever para receber diretamente pelo iTunes: <a href="http://itunes.apple.com/br/podcast/void-podcast/id443186480">http://itunes.apple.com/br/podcast/void-podcast/id443186480</a></p>
<h1>#</h1>
<h3>Zune</h3>
<p>Dizem que dá para usar o Zune para gerenciar também. <a href="http://viniciusquaiato.com/images_posts/Void-Podcast.jpg"><img src="http://viniciusquaiato.com/images_posts/Void-Podcast-300x139.jpg" title="Void Podcast" alt="Void Podcast" /></a></p>
<p>Bom galera é isso. Espero que curtam, espero que gostem. E se quiserem dar algum feedback o Eleonor os adora.</p>
<p>Abraços,
Vinicius Quaiato.</p>
Arquitetura de Software e O Arquiteto2011-09-22T00:00:00-07:00http://viniciusquaiato.com/blog/arquitetura-de-software-e-o-arquiteto<p>Fala galera há alguns dias dei uma palestra muito bacana na UEL - Universidade Estadual de Londrina. Primeiro gostaria de dizer que o SECOMP foi o evento universitário com melhor nível técnico e grade qu já participei. A organização está de parabéns. Além disso os alunos de lá são fantásticos.Esta palestra não é algo comum para mim e exigiu muito para prepará-la. O feedback foi bastante positivo: as dúvidas/questões levantadas foram muito interessantes, pertinentes e inteligentes.Abaixo seguem os slides (sim dessa vez eu me empolguei). Acredito que dê para compreender a história toda apenas por eles, quaisquer dúvidas, críticas e/ou sugestões estou às ordens. Espero poder apresentar essa palestra (melhorada) em outros eventos e oportunidades.<div style="width:510px" id="__ss_9271548"> <strong><a href="http://www.slideshare.net/viniciusquaiato/arquitetura-de-software-9271548" title="Arquitetura de Software e o Arquiteto - Secomp Londrina - Vinicius Quaiato">Arquitetura de Software e o Arquiteto - Secomp Londrina - Vinicius Quaiato</a></strong> <object id="__sse9271548" width="510" height="426"> <param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=arquiteturadesoftware-110915112836-phpapp02&stripped_title=arquitetura-de-software-9271548&userName=viniciusquaiato" /> <param name="allowFullScreen" value="true" /> <param name="allowScriptAccess" value="always" /> <embed name="__sse9271548" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=arquiteturadesoftware-110915112836-phpapp02&stripped_title=arquitetura-de-software-9271548&userName=viniciusquaiato" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="510" height="426"></embed> </object> <div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/viniciusquaiato">Vinicius Quaiato</a> </div> </div>Abraços,Vinicius Quaiato.</p>