<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Apple | AkitaOnRails.com</title><link>https://akitaonrails.github.io/tags/apple/</link><description>Blog do Fabio Akita do Canal do YouTube 'Akitando' falando sobre tecnologia, carreira e coisas geek.</description><generator>Hugo -- gohugo.io</generator><language>pt-BR</language><lastBuildDate>Mon, 19 Oct 2026 23:20:48 +0000</lastBuildDate><atom:link href="https://akitaonrails.github.io/tags/apple/index.xml" rel="self" type="application/rss+xml"/><item><title>[Akitando] #56 - Falando um pouco de MAC, LINUX e WINDOWS | Qual eu devo escolher?</title><link>https://akitaonrails.github.io/2019/07/24/akitando-56-falando-um-pouco-de-mac-linux-e-windows-qual-eu-devo-escolher/</link><guid isPermaLink="true">https://akitaonrails.github.io/2019/07/24/akitando-56-falando-um-pouco-de-mac-linux-e-windows-qual-eu-devo-escolher/</guid><pubDate>Wed, 24 Jul 2019 17:00:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/brIQSA8FtDo"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;No episódio de hoje, pegando carona que eu fiz um vídeo sobre instalar ambiente de desenvolvimento em Ubuntu (&lt;a href="https://www.youtube.com/watch?v=epiyExCyb2s"target="_blank" rel="noopener"&gt;https://www.youtube.com/watch?v=epiyExCyb2s&lt;/a&gt;) eu queria aproveitar pra contar vários pequenos momentos e conceitos sobre sistemas operacionais que eu gosto de ficar discutindo.&lt;/p&gt;
&lt;p&gt;No geral eu poderia dizer que é um vídeo “comparando” Linux, Mac e Windows mas a idéia não é escolher um no final mas sim delinear o que aconteceu nos últimos 20 e tantos anos que me fez ficar mudando de sistemas e hardware ao longo do tempo e porque existem algumas opiniões formadas hoje que quem está só começando não consegue entender porque as recomendações são extremas em muitos casos.&lt;/p&gt;</description><content:encoded><![CDATA[

<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/brIQSA8FtDo"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>No episódio de hoje, pegando carona que eu fiz um vídeo sobre instalar ambiente de desenvolvimento em Ubuntu (<a href="https://www.youtube.com/watch?v=epiyExCyb2s"target="_blank" rel="noopener">https://www.youtube.com/watch?v=epiyExCyb2s</a>) eu queria aproveitar pra contar vários pequenos momentos e conceitos sobre sistemas operacionais que eu gosto de ficar discutindo.</p>
<p>No geral eu poderia dizer que é um vídeo “comparando” Linux, Mac e Windows mas a idéia não é escolher um no final mas sim delinear o que aconteceu nos últimos 20 e tantos anos que me fez ficar mudando de sistemas e hardware ao longo do tempo e porque existem algumas opiniões formadas hoje que quem está só começando não consegue entender porque as recomendações são extremas em muitos casos.</p>
<p>Antigamente a gente pedia “pelamor” pros desenvolvedores darem uma chance pros Macs. Hoje em dia o povo não entende porque tem tanta gente ainda recomendando Macs tão veementemente. E no fim, qual é a melhor escolha pra desenvolvedores de software? Vamos descobrir isso hoje.</p>
<p>== Errata</p>
<p>Eu falei que Fedora usa Yum, mas não é verdade, eu esqueci que agora ele usam DNF.</p>
<p>== Seções:</p>
<p>03:03 - Linux
14:00 - Mac
32:45 - Windows</p>
<p>== Links:</p>
<ul>
<li>
<p>How eSports became mainstream (<a href="https://www.diggitmagazine.com/papers/esports-mainstream"target="_blank" rel="noopener">https://www.diggitmagazine.com/papers/esports-mainstream</a>)</p>
</li>
<li>
<p>Why the 64-bit Version of Windows is More Secure (<a href="https://www.howtogeek.com/165535/why-the-64-bit-version-of-windows-is-more-secure/"target="_blank" rel="noopener">https://www.howtogeek.com/165535/why-the-64-bit-version-of-windows-is-more-secure/</a>)</p>
</li>
<li>
<p>Steve Jobs changed the future of laptops 10 years ago today (<a href="https://www.theverge.com/2018/1/15/16892792/apple-macbook-air-steve-jobs-anniversary"target="_blank" rel="noopener">https://www.theverge.com/2018/1/15/16892792/apple-macbook-air-steve-jobs-anniversary</a>)</p>
</li>
<li>
<p>WWDC 2005 Keynote (<a href="https://www.youtube.com/watch?v=B6iF6yTiNlw"target="_blank" rel="noopener">https://www.youtube.com/watch?v=B6iF6yTiNlw</a>)</p>
</li>
<li>
<p>Steam Proton (<a href="https://www.protondb.com"target="_blank" rel="noopener">https://www.protondb.com</a>)</p>
</li>
<li>
<p>Puppy Linux (<a href="http://puppylinux.com"target="_blank" rel="noopener">http://puppylinux.com</a>)</p>
</li>
<li>
<p>DDR5 | O que sabemos desse novo padrão de memória até agora (<a href="https://canaltech.com.br/hardware/tudo-sobre-memoria-ddr5-134725/"target="_blank" rel="noopener">https://canaltech.com.br/hardware/tudo-sobre-memoria-ddr5-134725/</a>)</p>
</li>
<li>
<p>What Is PCIe? (<a href="https://www.lifewire.com/pci-express-pcie-2625962"target="_blank" rel="noopener">https://www.lifewire.com/pci-express-pcie-2625962</a>)</p>
</li>
<li>
<p>NVMe SSDs: Everything you need to know about this insanely fast storage (<a href="https://www.pcworld.com/article/2899351/everything-you-need-to-know-about-nvme.html"target="_blank" rel="noopener">https://www.pcworld.com/article/2899351/everything-you-need-to-know-about-nvme.html</a>)</p>
</li>
<li>
<p>A ZFS developer’s analysis of the good and bad in Apple’s new APFS file system (<a href="https://arstechnica.com/gadgets/2016/06/a-zfs-developers-analysis-of-the-good-and-bad-in-apples-new-apfs-file-system/"target="_blank" rel="noopener">https://arstechnica.com/gadgets/2016/06/a-zfs-developers-analysis-of-the-good-and-bad-in-apples-new-apfs-file-system/</a>)</p>
</li>
<li>
<p>Why John Carmack Chose NeXT For Developing &lsquo;Doom&rsquo; And Other Favorites (<a href="https://www.forbes.com/sites/quora/2016/09/01/why-john-carmack-chose-next-for-developing-doom-and-other-favorites/#6fb22dbb14d1"target="_blank" rel="noopener">https://www.forbes.com/sites/quora/2016/09/01/why-john-carmack-chose-next-for-developing-doom-and-other-favorites/#6fb22dbb14d1</a>)</p>
</li>
<li>
<p>Picking up the pieces: John Siracusa mourns the Power PC (<a href="https://arstechnica.com/gadgets/2005/06/mac-20050607/"target="_blank" rel="noopener">https://arstechnica.com/gadgets/2005/06/mac-20050607/</a>)</p>
</li>
<li>
<p>NextSpace (<a href="https://trunkmaster.github.io"target="_blank" rel="noopener">https://trunkmaster.github.io</a>)</p>
</li>
<li>
<p>Scaling from 2,000 to 25,000 engineers on GitHub at Microsoft (<a href="https://jeffwilcox.blog/2019/06/scaling-25k/"target="_blank" rel="noopener">https://jeffwilcox.blog/2019/06/scaling-25k/</a>)</p>
</li>
<li>
<p>Rocketz Workstations (<a href="https://rocketz.com.br/workstation"target="_blank" rel="noopener">https://rocketz.com.br/workstation</a>)</p>
</li>
<li>
<p>AkitaOnRails - Optimizing Linux for Slow Computers (<a href="https://www.akitaonrails.com/2017/01/17/otimizando-o-linux-para-computadores-lentos"target="_blank" rel="noopener">https://www.akitaonrails.com/2017/01/17/otimizando-o-linux-para-computadores-lentos</a>)</p>
</li>
</ul>
<p>=== Script</p>
<p>Olá pessoal, Fabio Akita</p>
<p>Seguindo na discussão sobre instalação de ambiente de desenvolvimento de software, eu acho que preciso responder, por que diabos eu uso Windows 10? E na realidade a resposta é bem menos interessante do que parece.</p>
<p>A resposta mais simples é porque na prática não faz quase nenhuma diferença se você estiver usando hardwares como o meu. O episódio de hoje vai ser longo, porque eu comecei a escrever e fui jogando vários assuntos aleatórios na mistura. Quando começamos a falar de sistemas operacionais eu tenho vários conceitos e histórias que acho importante dar contexto. A idéia foi trazer vários pontos que eu considero interessantes e falar tudo de uma vez do que tentar diluir em múltiplos episódios. Mas no final eu acredito que vocês vão sair com um entendimento maior do que simplesmente diferenciar um sistema de outro pelo visual, então tenham um pouco de paciência hoje.</p>
<p>(&hellip;)</p>
<p>Desde pelo menos 2013 eu não uso computadores com menos de 16GB de RAM. E recentemente meus dois computadores principais, um Lenovo Thinkpad Extreme e um PC torre que comprei da Rocketz ano passado, tem 32GB de RAM. Ambos tem placas NVIDIA, o primeiro com um GTX 1050 que é mais que suficiente pra um notebook, e o segundo com um bom GTX 1070Ti do ano passado que não é topo de linha, mas até pra gaming 1080p a mais de 100fps é bem suficiente.</p>
<p>Meu primeiro Mac foi um Mac Mini G4 de 2003 com processador Power PC G4 de 1.25Ghz, não lembro se tinha 2GB de RAM, HD mecânico de 40GB, mas praquela época já tinha USB-2 e Firewire 400. Eu lembro que brinquei muito de editar vídeos com iMovie e gravar em DVD. Eu tive depois o primeiro Macbook branco de 13&quot; com processador Intel Core Duo. E meu último Mac foi um Macbook Pro 15&quot; de 2014 com tela retina display, Core i7, 16GB de DDR3, 512GB de SSD e vinha com a GeForce GT 750M com 2GB de GDDR5. Na minha opinião a última série de Macbook Pro ainda à frente do seu tempo, quando o teclado ainda era bom, quando não tinha touchbar, quando havia Magsafe pro cabo de força.</p>
<p>Mas, eu acho que a grande maioria das pessoas assistindo não está muito disposto a gastar mais que 1000 dólares numa máquina, de preferência menos. E eu concordo com vocês, especialmente se eu tivesse 25 anos eu não poderia comprar nada muito mais caro que 500 dólares, e parcelado, claro. Como eu já disse no episódio de Ubuntu, vocês não precisam de uma máquina tão topo de linha assim. Em desenvolvimento de software, a menos que você esteja programando apps Android e precisa subir aquele emulador lento, uma máquina Core i3 Skylake, com 4GB de RAM, e até com HD mecânico deve ser suficiente pra maioria dos casos. Daí com o tempo você troca o HD mecânico por um SSD de 256GB, um HD externo via USB-3, e mais 4 GB de RAM pra ficar com 8.</p>
<p>A idéia não é ser uma divisão perfeita, mas vamos começar essa conversa de hoje falando um pouco sobre Linux primeiro, depois vou falar de Mac e depois de Windows. Se você viu meus episódios da série de Back-end onde eu explico sobre threads e schedulers, já sabe que existem diferentes formas de estratégia pra threads. E os 3 sistemas operacionais principais: Windows 10, macOS e as várias distros Linux usam estratégias de schedulers diferentes. O melhor sendo o CFS do Linux. O MacOS e o Windows implementam multilevel feedback queue, pense em múltiplas filas com prioridades, mas por alguma razão a implementação do Windows continua sendo a piorzinha. É aquele momento que tudo dá uma engasgada, fica um pouco lento, daí volta. Ou você tá assistindo youtube ou netflix, deixa outra coisa rodando por trás e em algum momento seu vídeo perde frames, dá uma engasgada. É o tipo de coisa que acontece com frequência em máquinas fracas. Eu raramente vejo porque tenho máquina sobrando. Mas é uma coisa que em Linux e Mac não acontece nem de longe com tanta frequência mesmo em máquinas mais antigas.</p>
<p>Lembram a metáfora de threads tendo que esperar a vez e o scheduler mudando a thread de mesa às vezes e o custo relacionado a mover os dados de uma core pra outra? Até algumas versões atrás o Windows fazia algo muito burro, não lembro se já corrigiram. Se você tinha cores sem fazer muita coisa, ele pegava a thread em execução e mudava pra outro core. Do nada, em vez de simplesmente manter na core que ele tava. Ele tentava ser preemptivamente mais esperto e isso causava overhead desnecessário. É exatamente o tipo de coisa que raramente acontece no macOS ou Linux. Sendo honesto, eu não tenho visto acontecer no Windows também, mas ainda não sei o quanto é porque meu hardware tá compensando isso.</p>
<p>Falando em schedulers, além de schedulers de threads como o Completely Fair Scheduler ou CFS, também temos schedulers pra I/O como o Completely Fair Queue ou CFQ. Se você usa HD mecânico e muitos processos querem fazer coisas no disco ao mesmo tempo, dá pra imaginar que não dá, então você vai também precisar de algum tipo de queue ou fila pra gerenciar isso. E no Linux você pode trocar os schedulers de threads e os schedulers de I/O.</p>
<p>Numa máquina parruda, com muitos cores sobrando e SSD veloz, você sempre mantém o default que é CFS com CFQ ou noop pra não precisa gastar computação gerenciando filas pro I/O, já que SSDs são ordens de grandeza mais rápidos que HD mecânicos e conseguem lidar com muita concorrência. Se por outro lado você está numa máquina mais devagar, pode mudar do CFS pro MuQSS e do CFQ pro BFQ ou o Budget Fair Queue, além de configurar o swapiness da kernel pra evitar ao máximo usar swap de disco e criar mais gargalo no seu HD lento. São as coisas que explico no meu artigo sobre configurar Linux pra máquinas lentas que vou deixar de novo nas descrições abaixo.</p>
<p>Além disso você pode somar configurações assim com distros preparadas pra instalar componentes mais leves do que os Ubuntu da vida, e evitar que você precise manualmente ficar instalando vários pacotes. Exemplo disso seria um Lubuntu, ou Light Ubuntu, ou também um Puppy Linux que é baseado em Debian. Como parêntese alguns me falaram do Pop OS mas eu não gostei muito dele, é basicamente um Ubuntu pré-configurado e com repositórios extras pra facilitar instalar algumas coisas como tensorflow. Mas não vi grandes vantagens não. Primeiro quero ver se ele dura, já que foi criado e é mantido por uma pequena empresa tentando vender hardware customizado. Já vi isso acontecer antes com distros como Lindows, mas que sumiram. Um Mint ou Elementary pelo menos já existem faz alguns anos e continuam sendo suportados. Pra eu instalar como daily driver, precisa ter mais tempo de existência. Prefira escolher distros que já tem alguns anos de estrada.</p>
<p>Dentre as dezenas de distros que existem, eu acabo preferindo os mais maduros e com ecossistemas maiores, aqueles que todo tutorial que você abre tendem a ser os primeiros.  Nessa categoria você tem principalmente os derivados de Debian. Ubuntu é um fork de Debian. Mint e Elementary são customizações em cima do Ubuntu, todos usam pacotes DEB com gerenciador APT. Você tem os derivados de RedHat como Fedora pra desktop ou CentOS pra servidor, e tem o Suse que é meio primo deles também, todos usam pacotes RPM com gerenciador YUM. Você tem os derivados de Arch como o Manjaro que usam Pacman. E tem os mais de nicho antigos como Slackware e Gentoo.</p>
<p>Uma característica que pode ou não ser um problema pra você no caso de Debian é que a intenção dele é ser sempre uma distro estável e confiável, e isso significa que ele demora bem mais pra oferecer versões mais novas de softwares mais novos. E faz sentido, tudo que é novo e ainda não foi testado o suficiente sempre deve ser considerado potencialmente bugado ou instável. Mas como desenvolvedores a gente muitas vezes precisa das coisas instáveis também, e por isso tem forks como um Ubuntu da vida, que oferece versão um pouco mais estável que são os LTS ou Long Term Support como o atual 18.04, que a Canonical deve fornecer suporte por uns 5 anos pelo menos, e versões mais bleeding edge, ou instáveis com coisas mais novas pra testar, que é a versão ímpar 19.04, que vai ter suporte bem menor. Mais ou menos o mesmo princípio você tem com CentOS sendo mais estável do que Fedora que tem pacotes mais recentes. Arch é sempre mais instável porque ele vai atualizando pra frente como se não houvesse amanhã. Não quer dizer que ele tem problemas, só que tem mais chances de ter, ele é uma bicicleta sem rodinhas, você tem que saber andar sozinho sem apoio.</p>
<p>Eu disse que Arch você vai sofrer se for iniciante, mas minha recomendação teve um pingo de compaixão. Arch pode parecer um pouco complicado no começo, mas ele é um sistema moderno, com gerenciador de pacotes e dependências bem competente, e com um dos melhores Wikis disponíveis em qualquer distro. Tem ampla documentação e suporte. Agora se você quiser ir pra um nível mais hardcore, precisa tentar Slackware. É a distro mais antiga ainda sendo mantida, desde 1993. Ele é um dos mais simples e mais parecido com o UNIX original e sua filosofia de KISS (keep it simple, stupid). Ele nem tem um gerenciador de dependências propriamente dito. Seus pacotes são meros tarballs, tipo zip se você não sabe o que é um tarball.</p>
<p>Em algum momento acho interessante tentar Slackware, mesmo hoje em dia. O Slack foi minha primeira distro em 1995. Não vou dizer que tenho boas memórias dele. Mas se quiser ir ainda mais um nível hardcore, você precisa experimentar o Gentoo cuja filosofia é baixar só código fonte e compilar tudo, literalmente tudo, na sua própria máquina. O sistema Portage dele é meio inspirado no Ports do BSD. Essa é uma distro pra você que tem muita curiosidade, muito tempo e principalmente muita paciência.</p>
<p>A maioria das distros mais novas por alguma razão acabam derivando de Ubuntu, caso do Pop OS. Um dos mais promissores na linha de Mint ou Elementary hoje seria o Deepin, que eu acho que é um dos mais bonitos e mais próximos da usabilidade de um MacOS sem tentar ser um clone exato. E de bônus, pra quem gosta de Arch e Manjaro, também tem a versão Manjaro Deepin que você pode usar em vez do Manjaro GNOME. Aliás, tem isso também, muitas distros já trazem versões pré-configuradas com diferentes desktop managers, como GNOME, KDE, Cinnamon, XFCE, o do Deepin que usa kwin, que é derivado do KDE Plasma, e outros mais exóticos com o i3 que muitos adeptos de teclado estão adotando.</p>
<p>Isso tudo dito, em PCs mais fracos não tem o que pensar, eu definitivamente recomendo instalar um Linux pra tirar o máximo da máquina. Em PC mid-range ou topos de linha eu acabo ficando no Windows puramente pelo suporte. Veja bem, minha situação é diferente da maioria das pessoas: meu dia a dia hoje não é mais ser programador tempo integral. Independente dos meus motivos pessoais, a recomendação ainda é tentar se manter no Linux como máquina primária. No meu caso, na maior parte do tempo eu vou acabar ficando em web apps, gmail, twitter, reddit, calendar, dashboards de AWS ou Google Cloud, e é tudo web. Coisas que tem clientes nativos como Dropbox, Zoom, Skype, tudo funciona bem em todos os sistemas operacionais. Apesar de eu não me incomodar com Google Docs ou Google Spreadsheet, eu ainda não gosto do Slides e mesmo a versão online do PowerPoint eu não me vejo usando. Ainda prefiro as versões nativas de apps do Office. De novo, é um gosto pessoal.</p>
<p>E mesmo o PowerPoint, tem várias coisas que ele faz até melhor que todo mundo mas em termos de usabilidade e produtividade ainda não supera o lendário Keynote da Apple. Mas tudo bem, em termos de pacotes de produção de conteúdo, eu gosto de ter acesso ao Adobe Creative Cloud, que só tem pra Windows e Mac. Mesmo em Mac eu ainda não trocaria Photoshop por qualquer outro produto. De novo, tudo gosto pessoal aqui. Entenda que metade da minha preferência pessoal é o fato de eu ter anos de experiência em ferramentas Adobe ou Apple. Se você nunca usou essas ferramentas, não vai sentir falta, então se começar com LibreOffice Impress, Google Slides, Da Vinci Resolve, Gimp, Inkspace, vai se acostumar. Em trabalhos criativos a ferramenta tem menos importância do que o treino artístico do profissional.</p>
<p>Se você não precisa de pacotes Microsoft, ou Adobe, ou não tem necessidade de desenvolver pra iOS, qualquer PC com qualquer boa distro Linux deve mesmo ser a primeira escolha. Você não está perdendo nada. Como muitos me lembraram depois, o Steam tem a opção do Proton e com isso a maioria dos games roda bem hoje em dia em Linux também. Dota 2, CS Go, Rocket League, Skyrim, Fallout, vai rodar. Se você joga Pubg vai ter problemas. Por baixo dos panos ele usar Wine e DXVK mas você não precisa ficar configurando manualmente jogo por jogo, por isso tá bem mais viável com o suporte da Valve hoje em dia.</p>
<p>Ou seja, numa máquina boa, o Windows funciona bem o suficiente pra eu esquecer que estou usando ele. E se você precisa de produtividade, realmente não quer ficar deixando sua máquina principal com risco de ficar instável, e nesse sentido não há nenhum grande problema em ficar no Windows. Mas na realidade, enquanto estou escrevendo este script eu estou muito tentado a voltar pro Linux como sistema primário. Entrei no Arch Wiki e vi que meu Lenovo Thinkpad X1 Extreme funciona perfeitamente com exceção do leitor de impressão digital, que não faço tanta questão de usar. Então eu acho que depois de editar este video vou instalar o bom e velho Manjaro, talvez o Deepin. Acompanhem minhas redes sociais pra ver como vai ficar.</p>
<p>Agora vamos pra parte 2, sobre Mac, o que eu realmente gosto é a consistência. Em Linux você tem diferentes desktop managers como GNOME, KDE, e por aí vai. Com diferentes toolkits gráficos como GTK, Qt, Tcl/tk, e isso faz com que cada aplicativo fique com sensação de &ldquo;fora do lugar&rdquo; se rodar misturado. Pegue um Kdenlive, que é feito com o toolkit Qt pra KDE,  ele fica fora do lugar rodando num GNOME. Ou um Gimp rodando num KDE. A interface gráfica de Linux é uma zona. Aliás, parece que estou falando mal, mas calma, a nova interface do Gimp, por exemplo, ficou sensacional se comparado como era antes, e inclusive recomendo que dêem uma olhada. Isoladamente, cada aplicativo é muito bom, especialmente com os refinamentos de hoje em dia, mas como um conjunto eles são muito inconsistentes em usabilidade.</p>
<p>No mundo Windows é um pouco parecido porque a Microsoft não se compromete numa única linguagem de design. Desde o Windows Vista eles vem tentando modernizar a interface, mas aí mesmo entre os aplicativos da própria Microsoft você tem aberrações como o aplicativo principal de Settings pra maioria das configurações da máquina, mas ainda tem o antigo Control Panel pras coisas que ele ainda não modernizou. Coisas simples como botões, tem o estilo pseudo-3D em apps velhas, tem botão cinza, tem botão translúcido. Cada hora é de um jeito. Coisas bestas como o console ou o Notepad, só começaram a ser modernizados agora. Olha como o Notepad contrasta ao lado da Calculadora. Eu abro muitas coisas e parece que voltei pro Windows XP. Especialmente se pegar programas mais antigos de terceiros que não se atualizaram.</p>
<p>A Apple iniciou a idéia de um Human Interface Guideline ou HIG décadas atrás, literalmente um guia de usabilidade e design visual de todos os elementos do sistema operacional. A forma com que eles conseguiram manter esse HIG consistente e sempre se atualizando é que os aplicativos que a própria Apple desenvolve usam o HIG e os aplicativos feitos pela própria Apple tendem a ser muito bem feitos, e todos os usuários querem os mesmos elementos em todos os outros aplicativos. Eles são tão bem feitos, que até usuários de fora do Mac gostariam que seus apps em Linux e Windows ficassem parecidos. Olha esse dialog box pra escolhe arquivos do MacOS e veja o do Deepin que falei antes, ou o Finder no Mac e o file manager do Deepin. Está bem claro que o Deepin gosta da estética do MacOS também. Então sempre existiu tentativas assim de se criar temas e skins pra Linux e Windows ficarem mais parecidos com Macs. Quando você viu um usuário de Mac tentando tematizar o Mac pra ficar com cara de Linux ou Windows?</p>
<p>No Mac é tudo mais consistente. Manter consistente foi um risco que se pagou. Eles determinaram e cumpriram linhas de corte drásticos que na época deixou muita gente descontente, mas hoje o resultado se paga. Quando Steve Jobs voltou pra Apple ele trouxe o lendário NEXTStep que é o desktop manager e os frameworks de desenvolvimento de aplicações feitos em Objective-C. Quando eles evoluíram o NEXTStep pra virar o OS X eles fizeram uma camada de compatibilidade binária com o Mac classic. Então se você executasse um binário de Mac antigo ele conseguia rodar. Facilitou que o OS X rodava no mesmo processador dos Macs antigos, o IBM Power PC e foi assim de 2000 até 2006.</p>
<p>O NextStep foi a parte da Next que sobreviveu. Muitos talvez reconheçam a Next por causa da workstation Cube onde Tim Berners Lee desenvolveu o primeiro protótipo de um navegador web e o protocolo HTTP. Ou onde John Carmack desenvolveu o lendário Doom. As capacidades de desenvolvimento num Next eram reconhecidas como de fato as melhores da época. Se você abrir um Interface Builder do Xcode de hoje, é algo muito parecido com que eles usavam no fim dos anos 80 num Next.</p>
<p>Enquanto a linha de hardware morreu, o NextStep foi padronizado como OpenStep junto com a Sun. No mundo Linux surgiu o desktop manager chamado WindowMaker que tinha o look and feel do NextStep mas na verdade foi feito em C. E teve o GNU Step que era uma tentativa de implementação dos frameworks em Objective-C. A idéia é que um dia um app de NextStep podia ser compilado em GNU Step e rodar em Linux. Recentemente descobri um projeto que está incompleto e eu não testei ainda mas que se chama NextSpace e é uma tentativa mais moderna de ter um ambiente NextStep em Linux. Ele tem a cara do antigo WindowMaker mas implementando da forma certa os frameworks todos em Objective-C. Se ele for bem sucedido, seria até possível pegar códigos fonte de aplicativos simples feitos pra Mac e recompilar em Linux usando esse framework. Ele está fazendo o caminho certo: em vez de tentar reimplementar os frameworks e o visual de um Mac moderno, ele está fazendo o mesmo caminho que a Next fez pra dentro da Apple em 1998.</p>
<p>Voltando pra história, quando anunciaram o beta do novo sistema operacional, codenome Rhapsody, a idéia era um NextStep onde você podia rodar só aplicativos novos feitos em Objective-C e os apps antigos do Mac classic rodariam num Yellow Box que era basicamente uma camada de emulação. Claro, os desenvolvedores ficaram muito bravos. Eles queriam que os aplicativos deles funcionassem nativamente no novo sistema operacional, mas ninguém estava muito a fim de reescrever tudo que se tinha antes em Object Pascal ou C pra Objective-C. Por isso a Apple resolveu desenvolver um framework intermediário, mais compatível com a API do Mac classic. Esse conjunto de APIs intermediários foi chamado de Carbon. Você precisava modificar algumas partes do seu código antigo e recompilar usando o framework novo que dava acesso aos recursos modernos do OS X, como permitir multi tarefa preemptiva e modo de memória protegido. Era o processo de carbonização.</p>
<p>Daí em 2006 eles fizeram um dos movimentos mais interessantes que eu vi no mundo de tecnologia até então: mudar os Macs dos processadores Power PC pra Intel. Eu lembro quando assisti o Keynote e fiquei muito impressionado com a estratégia. Mais ainda porque desde 2001 nós ouvíamos mesmo rumores de que o OS X, por ter a estrutura UNIX e tudo mais, não deveria ser tão difícil de recompilar em Intel. E Jobs anunciou exatamente assim, foi sensacional. Na prática, a IBM provavelmente estava mais interessada nos processadores que estava vendendo simultaneamente pra Sony nos PS2, pra Microsoft nos Xbox originais e pra Nintendo nos GameCubes. A promessa que eles fizeram de um processador G5 de 3Ghz passou 2 anos e eles não entregaram pra Apple, e isso obviamente fez Steve Jobs ficar com cara de bobo por ter prometido isso 2 anos atrás. E um Jobs bravo não é exatamente fácil de negociar.</p>
<p>Frigir dos ovos, fora IBM, olá Intel. Alguém na IBM deve ter pensado pfff foda-se, duvido que eles nos abandonem, vão fazer o que, ter a dor de cabeça de migrar tudo pra Intel? É exatamente o que um Jobs bravo faria, e fez. Pra isso funcionar eles fizeram uma estratégia em etapas. Binários antigos de Power PC rodariam sobre uma camada de emulação chamada Rosetta, de uma pequena empresa que a Apple comprou. Essa camada traduzia as instruções RISC de PowerPC em instruções x86 em tempo real. Óbvio que era mais lento, mas era muito impressionante.</p>
<p>Toda aplicação mais nova, já desenvolvida no framework derivado do NextStep, que a essa altura tinha sido renomeado de Cocoa, só precisava assinalar um checkbox na IDE XCode. Fizeram uma apresentação de como pediram o código fonte do lendário Mathematica que rodava em Power PC e com algumas horas de tweaks no código e assinalando o tal checkbox, já se tinha um binário pronto pra rodar nativo em Intel. Aliás, esse keynote inteiro é de longe uma das melhores apresentações de transição de roadmap de produto que eu já vi, é uma aula que eu recomendo que vocês assistam. Vou deixar linkado o keynote nas descrições abaixo.</p>
<p>Até esse ponto muita gente preferia desenvolver no antigo CodeWarrior da MetroWerks, que era o que se usava pra escrever código pra Mac classic. Pra migrar pra Intel era preciso compilar via o novo XCode 2 e foi assim que o CodeWarrior morreu e todo mundo passou a adotar XCode. Ironicamente o CodeWarrior ganhou notoriedade quando a Apple migrou dos processadores Motorola 68000 pra PowerPC, e agora perdeu o bonde na segunda transição.</p>
<p>Todo aplicativo antigo que já tinha sido carbonizado também era praticamente só recompilar. Ao recompilar eles trouxeram outra tecnologia do NextStep: os Fat Binaries que foram renomeados como Universal Binaries. Um dos recursos mais interessantes pra mim no OS X e NextStep era o conceito de bundles. Tecnicamente em vez de você dar duplo clique em cima de um binário executável, você manda executar um bundle, que é simplesmente uma pasta especial com um arquivo de manifesto e algumas convenções de subpastas e nomes. Daí o OS X procura dentro dessa pasta o binário pra Power PC ou pra Intel dependendo de onde está rodando e executa o certo. Daí quando precisou migrar de 32-bits pra 64-bits foi a mesma coisa: recompilar e gerar os binários e fica tudo no mesmo bundle. Esse conceito de universal binary foi outra coisa inteligente na época que me deixou impressionado, porque eu estava vendo no Windows começar a aparecer coisas como o diretório Program Files (x86) ao lado do diretório Program Files, que é um troço que ainda existe no Windows até hoje. Isso sem contar o buraco negro radioativo que são os diretórios System32 e WOW64.</p>
<p>A Apple só conseguiu fazer isso porque a quantidade de pessoas usando Macs era muito pequena, só alguns poucos milhões. Então não tinha tanto problema se uma porcentagem pequena dos usuários ficasse alienada sem conseguir atualizar por conta de aplicativos legados que não iriam mais rodar. O ideal era todo novo aplicativo ser feito já usando os frameworks do Cocoa, em Objective-C, com XCode. E pra facilitar mais ainda, 2 anos depois desse anúncio eles lançam o iPhone, e nem 2 anos depois o Xcode passa a suportar compilar pra processadores ARM, usando frameworks derivados de Cocoa, em Objective-C, então mesmo se a maioria das pessoas não fosse adotar XCode e Objective-C, a urgência de querer desenvolver pra iPhone automaticamente criou essa necessidade e foi assim que Objective-C passou de uma linguagem obscura que quase ninguém usava além de desenvolvedor de Mac pra uma das linguagens mais reconhecidas nos anos 2010. E aqui eles demonstraram novamente, que não importa se você acha que uma linguagem é bonita ou feia, o que trás adoção pra linguagem é um killer app, no caso o iPhone e sua App Store. Sem um killer app, uma boa linguagem está morta.</p>
<p>Nesse sentido, acabou dando tudo certo pra Apple. Eles tiveram a possibilidade de começar praticamente do zero com o OS X, migrar os principais aplicativos aos poucos via carbonização ou reescrever direto em Cocoa. Ajudou que a fundação era baseada em UNIX então havia muito código aberto que podia ser reusado no processo, vindo tanto dos ecossistemas de BSD e de Linux. Vocês podem ver que esse processo de nascimento e evolução do OS X foi extremamente fascinante de se ver, e com os novos hardwares, qualquer programador antenado queria muito entrar nesse ecossistema o quanto antes, e por isso eu migrei pra Mac em 2004 e me senti ainda mais justificado com tudo isso que aconteceu.</p>
<p>Quando a adoção de iPhone aumentou a adoção de Macs, ao mesmo tempo comunidades web como Ruby on Rails já haviam entrado nesse vagão. O fato de Ruby vir pré-instalado em Macs ajudou muito. O fato de muitos aplicativos de Linux serem compatíveis no nível do código fonte também ajudou. Daí nasceram muitas ferramentas que são usadas até hoje e são parte fundamental do desenvolvimento tanto Web como Mobile. No começo era muito chato usar ferramentas open source no OS X porque a gente precisava baixar os fontes e compilar tudo na mão e torcer pra compilar. Aos poucos surgiram ferramentas automatizadas como o antigo Fink que tentava imitar o apt-get do Debian pra ser um repositório pra baixar pacotes em formato DEB, mas teve muito pouca adoção e suporte e morreu. Outra tentativa foi o MacPorts que tentava simular o Ports do BSD pra baixar pacotes de código fonte e compilar toda vez que baixava. Esse até durou alguns anos mas morreu também.</p>
<p>O que sobreviveu e existe até hoje é o Homebrew que é o gerenciador de pacotes que todo desenvolvedor de Mac usa e é feito em Ruby. No mundo mobile mesma coisa, a gente precisava organizar dependências ou manualmente usando coisas como submódulos de git, ou baixando as bibliotecas manualmente e jogando em pastas no projeto. Mas então surgiu o CocoaPods pra gerenciar dependência de projetos pra iOS, e ele também foi feito em Ruby. Outro dia vou falar mais de Ruby, mas os rubistas foram os que começaram a ajeitar o Mac pra ficar boa pra ser usada por qualquer desenvolvedor. O pacote Oh-my-ZSH pra trocar Bash por ZSH, de novo, foi feita por outro rubista.</p>
<p>Eu falei no começo que no mundo Linux e Windows a linguagem visual dos aplicativos é toda misturada. No mundo Mac, essas transições meio que forçaram o desenvolvimento de novos aplicativos usando os frameworks mais modernos e os guias HIG da Apple. E com a adoção de parte do mundo open source, e o desenvolvimento acelerado de apps iOS, a gente tinha um app bom atrás do outro surgindo. Editores de texto como o TextMate 2 que nós da comunidade Ruby começamos a usar dita a linguagem de todo novo editor de texto até hoje. A idéia de um editor rápido e simples que pode ser extendido via plugins, com recursos pra fazer pesquisa fuzzy em nome de arquivos, diversos shortcuts e macros pra expandir templates de código.</p>
<p>Se você usa Sublime Text, ou Atom ou Visual Studio Code e abrir o TextMate 2 com os diversos plugins instalados, vai ver como a gente tinha exatamente a mesma coisa que se tem hoje só que em 2004. Nenhum outro sistema operacional tinha um TextMate. E foi assim que surgiu a nova geração de plugins de Vim e Emacs que elevaram esses editores ao que eles são hoje também. O renascimento de vim como editor mais moderno veio muito dos plugins feitos pra Rails por outro rubista, o Tim Pope. Pela primeira vez as tendências principais de desenvolvimento de software estavam iniciando primeiro nos Macs e sendo levados pra Linux e Windows depois. Só considere que quase toda ferramenta que você usa hoje, de GitHub a Heroku, foi feito por desenvolvedores usando Macs.</p>
<p>A estética da Apple influenciou a web moderna, começando com o visual do Aqua original com seus elementos parecendo plástico translúcido, como os iMacs antigos, e depois se tornando mais metalizado como os PowerMac Titanium, e finalmente se tornando mais minimalista seguindo a identidade de aplicativos de iPhone. Hoje eu diria que o design e estrutura de apps e sites meio que convergiu e está mais estável, mas não havia lugar melhor pra estar entre 2006 a 2010 se você fosse desenvolvedor de software. E se você assistiu meu video da Apple e GPL que vou deixar linkado aqui em cima, também sabe que nesse período foi quando eles contrataram o Chris Lattner que evoluiu o LLVM até o clang substituir o GCC e desenhou a nova linguagem Swift. Desenvolvimento de software no mundo Apple era realmente empolgante com tudo isso.</p>
<p>Você tinha um pacote muito atraente: na época os Macs tinham preços até que competitivos mesmo se comparado aos PCs. Com a vantagem que os PCs eram objetivamente piores. O design industrial era desastroso pra dizer o mínimo. As configurações padrão eram fracas. Iniciativas como netbooks foram um fracasso. O Windows Vista da época não estava exatamente atraindo novos usuários. Pensa que o Windows 7 só veio a sair em 2009, ano que todo mundo queria Mac pra desenvolver apps pra iPhone. E pensa que só um ano antes tinha acabado de sair o Macbook Air que obliterou a imagem que a gente tinha de notebooks e iniciou a categoria de ultrabooks.</p>
<p>Sério, os PCs de antes de 2011 eram ruinzinhos, e muito feios. Os da Apple por outro lado, era um modelo melhor que o outro saindo frequentemente. Dava vergonha abrir um notebook PC do lado de um Macbook. Mas foi a partir de 2012 que as coisas começaram a virar. Steve Jobs estava mais ou menos certo: as tecnologias da Apple estavam uma média de 5 anos à frente do mercado. Incluindo I/O mais veloz com coisas como Lightning e Thunderbolt, o conceito de unibody enclosure, tecnologia de baterias, as telas Retina num mundo que ainda vendia monitores 720p todas descalibradas, o melhor trackpad até hoje ainda, e os melhores teclados em notebooks.</p>
<p>Mas, Steve Jobs morreu em 2011, e com ele foi enterrado também a visão e estratégia da Apple. O Mac Pro trashcan em 2013 iniciou um período de idade média dos hardwares Pro da Apple. A bolha de apps pra iPhone já estava estabilizando por 2014, então isso não ia mais acelerar venda de novos Macs. E pra piorar a partir de 2015 eles começaram a errar a mão nos Macbooks. Os teclados com switches butterfly são a pior construção que eu já vi, além de na prática serem rasos e desagradáveis pra longos períodos de digitação. O touchbar removendo teclas que são úteis pra desenvolvedores não ajudou em nada. Manter o mesmo unibody enclosure e ir entuxando CPUs que esquentam mais e mais como os Core i7 e os Core i9 causando thermal throttling não ajudou também. Eles esqueceram como em 2005 eles decidiram até mudar de CPU porque os G5 esquentavam demais pros produtos que a Apple queria fazer.</p>
<p>A Apple foi aumentando os preços e entregando menos. E nesse vácuo todos os outros fabricantes foram ficando melhores, em todos os segmentos, tanto em smartphones, como notebooks, como desktops. A Dell veio lançando um XPS melhor que outro faz uns 4 ou 5 anos já. A Lenovo veio lançando Thinkpads cada vez melhores e retornando à antiga glória. Mesma coisa com HP, Acer e outras marcas tradicionais. As marcas chinesas começaram a aparecer mais e mais com Xioami, Huawei e novas marcas começaram a pegar nichos mais premium com os notebooks da Razer. Chegou a hora de explorar a 3a parte deste episódio e pisar no mundo PC um pouco.</p>
<p>O mundo gamer explodiu por conta das iniciativas do governo da Coréia do Sul desde o ano 2000. Os torneios de eSports foram crescendo de meros 10 torneios no início do século pra 260 em 2010 a quase 700 em 2012. O Twitch foi lançado em 2011 e em 2015 já tinha mais de 4.5 milhões de visualizações únicas. Foi quando começou a sair as principais franquias de hoje como LOL, Dota 2, CS:Go, cada um atraindo milhões de novas pessoas a eSports. A Nvidia estava com placas ficando cada vez melhores como a GeForce 600 na arquitetura Kepler. A AMD que a Apple adotou como padrão entrou num vácuo até recentemente. A Apple perdeu o bonde do mundo gamer.</p>
<p>Se você não for gamer pode não parecer, mas a profissionalização de eSports ajudou em muito a evoluir mais rápido todos os componentes de PC. Antigamente era de fato fácil montar um PC equivalente mais barato que um Mac, mas eu sempre tive a sensação de que o resultado final não chegava perto. Por exemplo, não era comum montar PCs com porta Firewire 800. Mas hoje é comum PCs com Thunderbolt 3. Hoje eu diria que existem configurações de hardware superiores e não parece mais que eu estou perdendo alguma coisa. Pelo contrário, agora parece que ficando no Mac eu estou perdendo muita coisa boa no mundo PC.</p>
<p>Pra facilitar, o Windows 10 apareceu pra limpar a zona que foi do Vista até o 8. Conseguiram consertar o start menu, tiraram a porcaria da barra de Charms, otimizaram o suficiente pra não ficar pesado em máquinas mais fracas. E pra completar a partir de 2012 a própria Microsoft começou a entrar no nicho de tablets e ultrabooks com a linha Surface. E aqui eles acertaram bastante. E de fato, fazer o próprio hardware definitivamente ajuda a Microsoft tanto a ter uma linha de referência pros parceiros quanto a otimizar melhor o sistema pra um hardware de verdade em vez de depender só do feedback dos OEMs.</p>
<p>Uma nova geração de desenvolvedores começou a entrar na Microsoft. Foi recente que eles pularam de um headcount de aproximadamente 2 mil desenvolvedores pra 20 mil. Isso trouxe um exército de jovens programadores que cresceram sem o viés de achar que tudo que não é Windows é inimigo. Ajudou muito que eles resolveram se aventurar no mercado de infraestrutura como serviço pra competir com a AWS e fizeram o Azure. O Azure expôs todas as fraquezas do Windows como servidor. E eles se viram na necessidade de aprender com o que o Linux já tinha conquistado até então. Tecnologias como Hyper-V evoluíram muito desde então, o suficiente pra se tornar úteis no mundo desktop também.</p>
<p>A migração de 32-bits pra 64-bits ajudou a Microsoft porque muitos novos dispositivos de segurança se tornaram possíveis com essa mudança, como ASLR ou Address Space Layout Randomization. Explicando de forma simples, eu ensinei no meu episódio sobre gerenciamento de memória sobre endereçamento. Se um hacker sabe em que endereço determinada função com bug de segurança é sempre carregado, fica fácil de atacar. Em 32-bits eu posso mudar de lugar, mas você lembra como tem poucos endereços no final pra aplicação. Então mesmo mudando de lugar, via força bruta, dá pra achar ainda. Em 64-bits a dificuldade aumentou exponencialmente. Esse é um dos recursos habilitados em Windows de 64-bits dentre outras e isso ajudou a diminuir muito a superfície de ataque dos hackers. Apesar de ainda existir centenas de vetores de ataque você pode ver como não é mais tão frequente ouvir falar de Windows 10 em 64-bits sendo atacado de forma tão vergonhosa como foi Windows XP.</p>
<p>E com Hyper-V se tornando componente padrão pra segurança criando coisas como secure enclosures em hypervisor, por exemplo, no novo Windows Defender. Não é difícil ver que as coisas realmente mudaram dentro da Microsoft. Hoje em dia eu tenho um Malwarebytes instalado mas me dá a impressão que só o Windows Defender é suficiente pra maioria dos casos. E pros casos mais exóticos eu ainda tenho a opção de abrir o Windows Sandbox, que é um Windows virtualizado em Hyper-V pra rodar coisas inseguras. Ele sobe um Windows vazio, eu posso instalar até um virus ali, e ele não tem acesso à máquina hospedeira. E quando eu fecho o sandbox, tudo dentro dele morre.</p>
<p>Esse tipo de uso de tecnologia me empolga bastante e, claro, eu posso fazer tudo isso num Mac ou Linux também. Mas de novo, eu gosto de coisas que vêm por padrão, oferecendo consistência. E falando nisso, uma coisa que o Windows nunca pôde fazer, foi começar do zero. Ele ainda é obrigado a trazer diversos binários antigos pra manter compatibilidade com programas velhos. Em seu mérito, é possível pegar um programa binário que rodava até em Windows 98, e provavelmente vai executar no Windows 10. Nenhum outro sistema operacional tem esse nível de retrocompatibilidade binária.</p>
<p>Porém isso também significa que existem muitos vetores inseguros pré-instalados. Muitos aplicativos que obviamente tem cara de que foram feitos nos anos 90. Claro que eu preferia que eles parassem de suportar e forçassem todo mundo a escrever em frameworks mais novos. Mas do tamanho que Windows já era no ano 2000 e o tamanho que é hoje, não seria realista. Ironicamente antigamente todo mundo só fazia apps pra Windows, mas hoje a Microsoft tem mais dificuldade em convencer desenvolvedores a fazer novos apps pra Windows. O Windows Store parece um deserto se comparado à Apple App Store. Mas dentro dessas restrições, eu diria que o Windows 10 está andando numa velocidade até razoável.</p>
<p>No caso do Mac, logo quando o OS X surgiu, eles fizeram três coisas muito importantes. Primeiro foi manter as parcerias originais. Trazer a Microsoft pra dentro pra eles fazerem uma versão do Office e do então Internet Explorer 5 foi muito importante. Com a demora da entrada da Adobe, a própria Apple se viu obrigada a cobrir o buraco. Primeiro com produtos da linha profissional como Final Cut e Logic Pro. Mas depois com o conceito de hub multimídia e os produtos da suíte iLife como iPhoto, iMovie e iDVD. Esses produtos ainda são bons hoje nas novas versões, mas naquela época eles eram imbatíveis. Sem exageros, muita gente comprava iMacs pra ter o iLife.</p>
<p>Muitos dos primeiros YouTubers aprenderam a lidar com multimídia via iMovie. No Windows tínhamos uma zona chamada Windows Movie Maker, um Windows Player que não decidia o que queria ser, se um jukebox ou um tocador. As tecnologias multimídia dos Mac sempre foram superiores. Nessa época os desktop managers do Linux também estavam babando pra interface Aqua dos novos OS X.</p>
<p>E isso foi outro fator que me interessava. Trazer o NextStep pra dentro da Apple como OS X trouxe outras tecnologias que ninguém mais tinha. Na década de 80 ex-funcionários da Apple fundaram a Adobe e inventaram o Postscript. Pense em Postscript como um HTML, com a intenção de possibilitar o famoso WYSIWYG ou What you see is what you get, ou seja, o que está aparecendo na tela ser igual o que vai aparecer quando mandar pra impressora. Isso foi revolucionário porque criou o mercado de desktop publishing.</p>
<p>Essa tecnologia evoluiria pra Display Postscript e depois Display PDF que virou o Quartz no OS X. O desktop manager do novo OS X, em vez de seguir a zona que é o X no mundo UNIX, foi criado do zero pra ser um monolítico que desenha todas as janelas de todos os programas como elementos de composição num PDF. Tudo que poderia ser acelerado via OpenGL em placa gráfica, que era novidade na época. Isso possibilita adicionar elementos de pós-produção, como transparências, sombras e animações fluidas. Em 2000 isso funcionava bem no iMacs, apesar de um pouco lento. Mas os processadores G3 da época conseguiam suportar.</p>
<p>Isso se pagaria poucos anos depois, quando processar esse tipo de coisa passou a ser barato pras novas placas gráficas. Eles tomaram a decisão de ser um pouco mais lentos no começo mas sabendo que em 1 ou 2 gerações estaria na velocidade correta, tanto por otimizações de software quanto pela própria evolução do hardware. Em 2000 qualquer um diria &ldquo;isso é desnecessário&rdquo;. Eu acho que o fato deles estarem no fundo do poço e desesperadamente precisando se recuperar fez a Apple de 1998 tomar muitos riscos que nenhuma empresa tomaria hoje em dia.</p>
<p>Se você não sabe o que é compositing. Pense num sistema primitivo. Você tem janelas de vários programas. Eles vão sendo desenhados por cada programa numa certa área de um buffer, tipo uma matrix, que chamamos de frame buffer. Em 1/60 avos de tempo o sistema operacional pega o que está nesse buffer e manda pro monitor mostrar. Se eu mexo uma janela na frente da outra, as duas precisam redesenhar tudo. E pra ficar fazendo sombra de uma janela na frente da outra, 60 vezes por segundo, custa muito tempo. Em vez disso pense agora organizar uma nova abstração, tipo um canvas virtual, onde cada janela fica em layers e a janela de cima não sobrescreve a imagem da janela de baixo. E como num photoshop podemos ir aplicando efeitos como sombra num layer de cima e dinamicamente ele vai aplicar a sombra nos layers de baixo. Mas tudo isso feito via OpenGL na época, falando com a GPU, que foi feito pra aplicar efeitos em quadros muito rápido, o suficiente pra renderizar 60 quadros por segundo, e sem precisar que a CPU se meta. Com isso ganhamos animação fluida usando a GPU em vez da CPU.</p>
<p>Fazer um desktop manager com compositing não é trivial, especialmente se você já tem um jeito legado de fazer e agora ter que mudar. A Apple teve a visão de implementar isso em 2000. Foi mais uma daquelas coisas que você não sabia que precisava até ter visto. Só que depois de ver as animações fluidas, sem engasgos, sem fritar sua CPU, você olhava pro seu Linux e Windows que ainda desenhavam do frame buffer direto pra tela via CPU, e não tinha como ter aqueles efeitos e animações sem fritar sua CPU que ia precisar processar 30 quadros por segundo pelo menos.</p>
<p>Eles precisavam delegar isso pra GPU como a Apple estava fazendo. Mas levou até 2005 pra surgir o Compiz e Kwin no Linux, depois de muita experimentação, e mesmo assim ainda não 100%. E levou até 2007 pra lançar o Windows Vista com o mesmo sistema de compositing, que só ficaria completo e passou a ser obrigatório no Windows 8. Ou seja, na prática, nessa primeira década, só num Mac você tinha visuais agradáveis e lisos. Hoje em dia felizmente tanto os novos Linux quanto Windows 10 já usam sistemas de compositing e até High DPI que é pra monitores com alta densidade de pixels escalar os elementos da tela da forma correta, coisa que a Apple até hoje ainda é a única que faz 100% direito.</p>
<p>O que a Apple fez entre 2000 e 2009 nenhuma outra conseguiu fazer. Eles conseguiram rebootar o ecossistema inteiro, começar do zero com uma plataforma realmente à frente do seu tempo, criando um novo ecossistema consistente de ponta a ponta, incluindo ao lançar novos produtos como o iPhone que manteve a programação muito consistente mesmo que os binários fossem executar em arquiteturas tão diferentes quanto ARM e x86.</p>
<p>Eles evoluíram o LLVM ao ponto de conseguir se desvincular do GCC como compilador, coisa que em Linux ainda não está 100%. E com isso mudar de linguagens de Objective-C pra Swift, sem perder compatibilidade binária. Como eles conseguiram manter uma API unificada com os frameworks Cocoa, fica muito mais fácil de manter as coisas. Do lado da Microsoft eles foram fazendo tentativa em cima de tentativa e cada tentativa errada foi gerando mais dependências que hoje estão todas acumuladas no Windows 10 ainda. A Apple foi cortando fora as coisas velhas. Por exemplo, o suporte a 32-bits no MacOS já acabou em 2017. No Windows isso ainda vai durar alguns bons anos porque tem milhões de pessoas ainda presas em máquinas velhas só de 32-bits.</p>
<p>Então dos anos 2000 até 2005 a Apple estava se recuperando, reconstruindo as fundações quase do zero. OS X novo, novos iMac e a sorte grande de terem conseguido fazer o iPod dar certo. De 2005 a 2007 eles tiveram o trabalho de migrar tudo de PowerPC pra Intel. E de 2009 a 2012 foi a consolidação graças ao boom do iPhone. De 2013 em diante foi sentar nos louros e seguir a receita.</p>
<p>Dos anos 2000 até 2010 o mundo PC ficou correndo atrás sem saber muito pra onde ir. Todo mundo foi afetado com o crash da bolha da internet em 2001. Mas com a presença da Apple tão claramente demonstrando porque tudo que eles faziam estava errado, demorou uma geração inteira até finalmente eles começarem a copiar e finalmente ultrapassar a Apple de novo. Em 2019 as diferenças são mais do tipo: a caixinha de som do Macbook ainda é melhor. O SSD da Apple realmente ainda é um pouco mais rápido. E a integração do sistema operacional com o hardware ainda é muito bom. Tirando isso, qualquer combinação de hardware PC com Windows ou Linux está praticamente igual pra todos os efeitos práticos.</p>
<p>A grande virada pra desenvolvedores eu acho que vai ser o lançamento do Windows Subsystem for Linux versão 2 daqui alguns meses. Eu estou usando hoje em versão alfa. Em resumo é uma máquina virtual Hyper-V mais leve do que o normal porque ele não vai precisar pré-reservar CPU ou RAM e parece que consegue gerenciar recursos sob demanda. Então o custo inicial é razoavelmente barato e com start rápido, especialmente pra rodar tudo em linha de comando. Então se você sobe Docker pra Windows hoje, que também usa Hyper-V por baixo, vai ficar melhor.</p>
<p>Na prática o Windows 10 com WSL2 vai se tornar um sistema operacional com duas cabeças. Mas a cabeça Linux ainda vai rodar isolado. No MacOS a fundação inteira foi trocada pra UNIX e ele vem colhendo os benefícios disso até hoje. Isso não vai acontecer no Windows, eu diria talvez nunca. Então rodar oficialmente virtualizado é a segunda melhor coisa. Por outro lado, como o MacOS é um UNIX não compatível com Linux, não tem como baixar um binário de Linux e rodar direto no Mac. Isso vai ser possível no WSL que é literalmente um kernel de Linux rodando virtualizado, então em termos práticos, o mundo Windows vai ter acesso a muito mais do mundo Linux do que o Mac tem hoje.</p>
<p>Graças à Apple hoje temos PCs e notebook muito melhores. São mais leves, construídos com materiais muito mais elegantes e sofisticados do que só plástico e ferro. A Apple introduziu alumínio ao mundo e todo mundo vem experimentando com novos materiais como magnésio ou fibra de carbono. Os fabricantes aprenderam que a gente paga mais pra não ter que ter plástico. Os componentes hoje funcionam muito melhor integrados. Os firmwares das placas mães ficaram mais inteligentes, PCI-express facilitou a vida de todo mundo. SSDs e RAM ficaram muito mais baratos e acessíveis. E até a porcaria da placa gráfica integrada da Intel já serve pra maioria das coisas que precisamos hoje como assistir Netflix em 4K.</p>
<p>Se você está começando agora deve ficar mesmo confuso porque desenvolvedores mais experientes como eu passaram por esses períodos que eu falei. Muito do que se fala mal de Windows hoje é porque a gente sofreu com Windows XP. Muito do que se fala bem dos Macs é a fase de ouro até o lançamento dos iPads. A mesma coisa dos Linux, muito desenvolvedor que hoje usa Mac não consegue se ver tendo que sofrer pra instalar e customizar um Linux até ficar agradável pra usar, mas naquela época a gente não tinha Elementary ou Deepin. E pra mim, eu tenho gostos superficiais e pra mim visual faz diferença, e não ter a opção de desktop managers com compositing fazia muita diferença. No Windows a gente teve que esperar até sei lá, depois de 2009 pro Aero funcionar de verdade quando o Windows 7 ficou mais estável. E levou do Windows 8 até o 10 pra nova linguagem de interface Metro finalmente começar a ser mais adotada. Ou seja, eu realmente não recomendava e ainda não recomendaria usar Vista, 7 ou 8. O Windows 10 é o primeiro Windows que demonstrou interesse em cortar coisas fora e gastar tempo limpando a casa em vez de só ficar adicionando inutilidades como aquela horrível barra de Charms.</p>
<p>Eu disse que se você precisa desenvolver pra iOS, não tem o que escolher, você é obrigado a ter um Mac. Porém, não se preocupe em comprar os mais novos. Mesmo se você comprar um Macbook Pro usado de 2016 ainda vai funcionar razoavelmente bem. É muito difícil de justificar o custo de um Mac, especialmente com o dólar caro em relação ao Real. Mas a boa notícia é que hoje em dia comprar um bom PC não dá mais aquela sensação de estar escolhendo uma opção de segunda linha. Se você precisa desenvolver em .NET fique esperto, na prática, vai ser obrigado a usar Windows mesmo, mas dependendo do tipo de desenvolvimento, com o novo .NET Core você pode ter praticamente tudo que precisa num Linux e desenvolver com o Visual Studio Code. Caso você não saiba disso hoje é possível instalar SQL Server no Linux também e compilar e rodar programas .NET feitos em C# ou F# nativamente num Linux, é uma opção suportada depois que eles compraram a Xamarin. E com os frameworks da Xamarin ainda é possível fazer aplicações tanto pra iOS quanto pra Android, então existem várias opções ainda a serem exploradas no mundo Linux.</p>
<p>E por tudo isso, eu diria: se você tem dinheiro sobrando, na real tanto faz. Macbook Pro, Thinkpad X1 Extreme ou Carbon, Razer Blade, Asus Zephirus S, tem uma variedade muito boa. Se você for jogar ou criar conteúdo, escolha alguma com uma GTX topo da série 10 como as 1080 ou 1070 ou os mid-tier com 1660. Ou se quiser mesmo rasgar dinheiro, compra com as novas RTX série 20.</p>
<p>Se você não tem dinheiro sobrando, não se sinta mal em não estar comprando um Macbook. Procure os Dell Inspiron, Acer Switch, os HP Presario com Core i3 pelo menos. Antes pesquise no Google sobre a compatibilidade desses modelos com Linux. Escolha uma boa distro como um Ubuntu, Manjaro. E mesmo nessas máquinas dá pra ser criador de conteúdo, com um pouco mais de paciência, você consegue rodar Blender, Gimp, Kdenlive, Inkscape, Da Vince Resolve, Audacity e pra maioria dos casos você deve conseguir trabalhar normalmente.</p>
<p>Em 2016 meu objetivo de migrar pra Linux depois de mais de 10 anos usando Macs foi porque primeiro eu não tenho lealdade nenhum com a Apple. Não havia mais nada que me empolgava na Apple o suficiente pra ficar lá. E eu não ia ser aquele cara com Mac falando pras pessoas “usa lá Linux, dizem que funciona”. Eu só recomendo o que eu pessoalmente já usei como ferramenta primária por algum tempo, senão prefiro não recomendar. Eu não tenho lealdade com a Apple, também não tenho lealdade com a Microsoft e apesar de ter elogiado, ainda tá longe, mas bem longe do que eu gostaria que o Windows fosse. E também não sou ativista então nesse episódio longo veja que eu não disse nenhuma vez que você devia usar Linux por causa do aspecto de software livre. Estou sendo bem pragmático: do ponto de vista de produtividade, programação, gaming e criação de conteúdo, hoje em dia você tem PC antes de Mac e Windows e Linux antes de MacOS. Mas, mas, se você tem acesso a todas as opções, tanto faz na real.</p>
<p>E por hoje é isso aí, já fiz muito bikeshedding pra um episódio só. No final isso tudo foi um pouco uma desculpa pra eu contar alguns dos episódios da história da Apple que eu gosto, a migração do Mac Classic pro OS X, depois a migração de Power PC pra Intel. Acho uma pena que a Apple de hoje não se parece muito com a Apple daquela época, mas pelo lado bom, ainda bem que a Microsoft de hoje está muito melhor que a Microsoft daquela época. E como eu sempre digo: o mercado anda em ciclos. Espero que tenham gostado da história. Se ficaram com dúvida mande nos comentários abaixo, se curtiram mandem um joinha, assinem o canal, cliquem no sininho pra não perder os próximos episódios e continuem compartilhando com seus amigos pra ajudar o canal. A gente se vê semana que vem, até mais!</p>
<p>No episódio de hoje, pegando carona que eu fiz um vídeo sobre instalar ambiente de desenvolvimento em Ubuntu () eu queria aproveitar pra contar vários pequenos momentos e conceitos sobre sistemas operacionais que eu gosto de ficar discutindo.</p>
<p>No geral eu poderia dizer que é um vídeo “comparando” Linux, Mac e Windows mas a idéia não é escolher um no final mas sim delinear o que aconteceu nos últimos 20 e tantos anos que me fez ficar mudando de sistemas e hardware ao longo do tempo e porque existem algumas opiniões formadas hoje que quem está só começando não consegue entender porque as recomendações são extremas em muitos casos.</p>
<p>Antigamente a gente pedia “pelamor” pros desenvolvedores darem uma chance pros Macs. Hoje em dia o povo não entende porque tem tanta gente ainda recomendando Macs tão veementemente. E no fim, qual é a melhor escolha pra desenvolvedores de software? Vamos descobrir isso hoje.</p>
]]></content:encoded><category>apple</category><category>microsoft</category><category>linux</category><category>akitando</category></item><item><title>[Akitando] #42 - Entendendo Apple, GPL e Compiladores</title><link>https://akitaonrails.github.io/2019/03/06/akitando-42-entendendo-apple-gpl-e-compiladores/</link><guid isPermaLink="true">https://akitaonrails.github.io/2019/03/06/akitando-42-entendendo-apple-gpl-e-compiladores/</guid><pubDate>Wed, 06 Mar 2019 17:00:00 -0300</pubDate><description>&lt;p&gt;Disclaimer: esta série de posts são transcripts diretos dos scripts usados em cada video do canal &lt;a href="https://www.youtube.com/channel/UCib793mnUOhWymCh2VJKplQ"target="_blank" rel="noopener"&gt;Akitando&lt;/a&gt;. O texto tem erros de português mas é porque estou apenas publicando exatamente como foi usado pra gravar o video, perdoem os errinhos.&lt;/p&gt;
&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/suSvMnNwV-8"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h3&gt;Descrição no YouTube&lt;span class="hx:absolute hx:-mt-20" id="descrição-no-youtube"&gt;&lt;/span&gt;
&lt;a href="#descri%c3%a7%c3%a3o-no-youtube" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Finalmente! Chegamos no episódio 42!&lt;/p&gt;
&lt;p&gt;Se você é geek que nem eu sabe que 42 é um número especial. Segundo o sábio profeta Douglas Adams o número 42 é a resposta da vida, do universo e de tudo. Se não acreditam leiam a bíblia do Guia do Mochileiro das Galáxias. De curiosidade é por isso que minha empresa se chama Codeminer 42. E em especial este ano eu vou completar meus 42 anos. Mas chega de numerologia, vamos começar a história de hoje.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Disclaimer: esta série de posts são transcripts diretos dos scripts usados em cada video do canal <a href="https://www.youtube.com/channel/UCib793mnUOhWymCh2VJKplQ"target="_blank" rel="noopener">Akitando</a>. O texto tem erros de português mas é porque estou apenas publicando exatamente como foi usado pra gravar o video, perdoem os errinhos.</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/suSvMnNwV-8"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h3>Descrição no YouTube<span class="hx:absolute hx:-mt-20" id="descrição-no-youtube"></span>
    <a href="#descri%c3%a7%c3%a3o-no-youtube" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Finalmente! Chegamos no episódio 42!</p>
<p>Se você é geek que nem eu sabe que 42 é um número especial. Segundo o sábio profeta Douglas Adams o número 42 é a resposta da vida, do universo e de tudo. Se não acreditam leiam a bíblia do Guia do Mochileiro das Galáxias. De curiosidade é por isso que minha empresa se chama Codeminer 42. E em especial este ano eu vou completar meus 42 anos. Mas chega de numerologia, vamos começar a história de hoje.</p>
<p>Hoje vamos fugir um pouquinho do tema de Back-end, que pretendo retomar semana que vem. Desta vez quero contar uma história que eu pessoalmente acho interessante. Vou falar sobre Apple, sobre licenças de software livre, sobre compiladores, um pouco do mundo mobile e um pouco do mundo web de novo. É uma história meio complicada mas que vai ajudar vocês a entenderem um pouco da dinâmica de como o mundo real afeta a evolução e adoção de linguagens e tecnologias.</p>
<p>Errata: várias vezes no vídeo eu falo &ldquo;SpiderMonkey&rdquo; mas eu queria dizer &ldquo;JavascriptCore&rdquo;. A SpiderMonkey é a engine de Javascript do Firefox, a JavascriptCore que é a engine que vem no WebKit e Safari. E o V8 é o do Chrome.</p>
<p>Errata 2: Eu falo que GPL é General Protection License, mas na verdade é General Public License.</p>
<p>Errata 3: me avisaram nos comentários e eu realmente comi bola quando falei dos emuladores de Android. Antigamente as imagens do OS eram realmente só de ARM mas hoje em dia de fato já existem imagens compilados pra x86, então em um Virtualbox habilitado pra usar os recursos de virtualização dos processadores AMD e Intel como o VT-X é possível acelerá-los. Ainda não é a mesma coisa que no MacOS/iOS que é um simulador sem necessidade de camada de virtualização, mas não deixa de ser um avanço.</p>
<p>Links:</p>
<ul>
<li>Why WebAssembly is Faster Than asm.js (<a href="https://hacks.mozilla.org/2017/03/why-webassembly-is-faster-than-asm-js/"target="_blank" rel="noopener">https://hacks.mozilla.org/2017/03/why-webassembly-is-faster-than-asm-js/</a>)</li>
<li>Awesome Wasm (<a href="https://github.com/mbasso/awesome-wasm"target="_blank" rel="noopener">https://github.com/mbasso/awesome-wasm</a>)</li>
<li>Swift is like Kotlin (<a href="http://nilhcem.com/swift-is-like-kotlin/"target="_blank" rel="noopener">http://nilhcem.com/swift-is-like-kotlin/</a>)</li>
<li>THE CASE THAT NEVER ENDS: ORACLE WINS LATEST ROUND VS. GOOGLE (<a href="https://www.wired.com/story/the-case-that-never-ends-oracle-wins-latest-round-vs-google/"target="_blank" rel="noopener">https://www.wired.com/story/the-case-that-never-ends-oracle-wins-latest-round-vs-google/</a>)</li>
<li>Facts and effects of Caldera/SCO vs IBM (<a href="https://www.computerweekly.com/feature/Facts-and-effects-of-Caldera-SCO-vs-IBM"target="_blank" rel="noopener">https://www.computerweekly.com/feature/Facts-and-effects-of-Caldera-SCO-vs-IBM</a>)</li>
<li>A new GCC runtime library license snag? (<a href="https://lwn.net/Articles/343608/"target="_blank" rel="noopener">https://lwn.net/Articles/343608/</a>)</li>
<li>A visual timeline of the Microsoft-Novell controversy (<a href="https://arstechnica.com/information-technology/2007/01/linux-20070128/"target="_blank" rel="noopener">https://arstechnica.com/information-technology/2007/01/linux-20070128/</a>)</li>
<li>The Microsoft-Novell Linux deal: Two years later (<a href="https://www.infoworld.com/article/2654097/the-microsoft-novell-linux-deal--two-years-later.html"target="_blank" rel="noopener">https://www.infoworld.com/article/2654097/the-microsoft-novell-linux-deal--two-years-later.html</a>)</li>
<li>An Introduction to Tivoization (<a href="http://www.linfo.org/tivoization.html"target="_blank" rel="noopener">http://www.linfo.org/tivoization.html</a>)</li>
<li>Linus Torvalds, Dual-Licensing Linux Kernel with GPL V2 and GPL V3 (<a href="https://lkml.org/lkml/2007/6/13/289"target="_blank" rel="noopener">https://lkml.org/lkml/2007/6/13/289</a>)</li>
<li>An insider&rsquo;s look at drafting the GPLv3 license (<a href="https://opensource.com/article/18/6/gplv3-anniversary"target="_blank" rel="noopener">https://opensource.com/article/18/6/gplv3-anniversary</a>)</li>
<li>Apple’s great GPL purge (<a href="http://meta.ath0.com/2012/02/05/apples-great-gpl-purge/"target="_blank" rel="noopener">http://meta.ath0.com/2012/02/05/apples-great-gpl-purge/</a>)</li>
<li>Apple Invests in LLVM, Suggests Merge with GCC (<a href="https://www.osnews.com/story/12715/apple-invests-in-llvm-suggests-merge-with-gcc/"target="_blank" rel="noopener">https://www.osnews.com/story/12715/apple-invests-in-llvm-suggests-merge-with-gcc/</a>)</li>
<li>Arquitetura LLVM (<a href="https://www.aosabook.org/en/llvm.html"target="_blank" rel="noopener">https://www.aosabook.org/en/llvm.html</a>)</li>
<li>What is LLVM? The power behind Swift, Rust, Clang, and more (<a href="https://www.infoworld.com/article/3247799/what-is-llvm-the-power-behind-swift-rust-clang-and-more.html"target="_blank" rel="noopener">https://www.infoworld.com/article/3247799/what-is-llvm-the-power-behind-swift-rust-clang-and-more.html</a>)</li>
</ul>
<h2>Script<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>Desta vez vamos dar uma pequena pausa na série Começando aos 40. Vocês já viram dois episódios falando sobre back-end e o assunto ainda não acabou, mas pra quebrar um pouco decidi fazer uma longa tangente hoje e falar sobre um tema cabeludo que envolve o mundo de software livre, a Apple e compiladores. É até difícil definir que tema é esse exatamente. Tem a ver com compiladores e linguagens mas não é só isso. Mas é uma história que eu acho fascinante e queria compartilhar com vocês.</p>
<p>Além disso hoje finalmente estou completando o episódio 42. Se você é geek que nem eu sabe que 42 é um número especial. Segundo o sábio profeta Douglas Adams o número 42 é a resposta da vida, do universo e de tudo. Se não acreditam leiam a bíblia do Guia do Mochileiro das Galáxias. De curiosidade é por isso que minha empresa se chama Codeminer 42. E em especial este ano eu vou completar meus 42 anos. Mas chega de numerologia, vamos começar a história de hoje.</p>
<p>(&hellip;)</p>
<p>Como vocês viram nos vídeos passados, acho que deu pra entender que a Microsoft foi um rolo compressor nos anos 90 empurrando tecnologia atrás de tecnologia, boas ou ruins. Depois ela foi bruscamente parada no começo do século por causa do julgamento anti-truste. E de 2001 até pelo menos 2014, quem calçou seus sapatos de certa forma foi a Apple. Sem repetir muito o que todo mundo já sabe vamos resumir: em 1999 os iMacs translúcidos de plástico colorido foram um enorme sucesso pra marcar o retorno de Steve Jobs, numa época onde a Apple estava a dias de fechar as portas e declarar falência. Em 2001 surgia o Mac OS X baseado no NextStep e BSD UNIX, também em 2001 o iPod conquistou o mundo, em 2003 o iTunes conquistou o mundo.</p>
<p>Em 2005 com a ascendência do Ruby on Rails e a preferência por Macs de seu criador fez com que a comunidade Rails e o gosto pela estética da Apple andassem lado a lado. De 2005 a 2006 a Apple migrou dos processadores PowerPC pra Intel e de repente todo mundo queria usar Macs pra desenvolvimento já que ele era um sabor de BSD UNIX. Diversas ferramentas que só existiam em Linux passaram a ser portados. Gerenciadores de pacotes como Fink, MacPorts e hoje HomeBrew começaram a surgir. E mais importante, Ruby vinha pré-instalado nos Macs, facilitando ainda mais a adoção inicial.</p>
<p>Por duas vezes a Apple não só passou ilesa como explodiu em crescimento no meio de duas grandes crises. Em 2001 ela lançou seu iPod bem na queda da Crash das Ponto Coms, um dos piores episódios da história da Internet. E em 2007 os iPhones aparecem, 1 ano antes da famosa crise econômica de 2008 que muitos diziam que poderia ser o fim do mundo, e você pode assistir em filmes recentes como o incrível The Big Short. Mesmo em meio a essa crise, em 2009 a App Store vai ao ar inaugurando a era do desenvolvimento mobile e todo mundo quer aprender Objective-C agora, validando o estilo de orientação a objetos que já era mais familiar a quem usava Ruby do que quem usava Java. A Apple forçou a evolução da Web em direção à morte do Flash, e ao HTML 5 e CSS 3 que rodavam melhor nos seus navegadores Safari. E com o nascimento do MobileMe que foi o serviço online de cloud da Apple; nasceu o framework javascript SproutCore, que depois viria a se tornar Ember, inaugurando o estilo de produtos Web que conhecemos hoje.</p>
<p>Pós crise de 2008 e 2009, todo mundo queria desenvolver produtos mais sofisticados, com linguagem visual limpa, com a usabilidade que a Apple era lendária por oferecer em seus produtos. Mesmo antes disso, enquanto o mundo enterprise estava adotando soluções J2EE como o IBM Websphere ou BEA Weblogic a própria Apple tinha uma arquitetura mais simples e mais sofisticada na forma do WebObjects que era o motor por trás do lendário e-commerce da Apple na época. Uma pena que o WebObjects nunca teve real tração. Toda essa experiência trouxe a Apple como uma das maiores influenciadoras das tecnologias da época. E isso coincidiu com o pior período da história da Microsoft pós-processo dos Estados Unidos contra suas práticas monopolistas depois da Guerra dos Navegadores, então a Apple praticamente não teve competição.</p>
<p>Voltando ao nosso tema de programação e linguagens, entenda que 2006 e 2007 foram anos interessantes pro mundo dos compiladores por três motivos: a migração da plataforma de Macs para Intel, o lançamento do iPhone e a migração no mundo de software livre da famosa licença GPL v2 para o controverso GPL v3. Esses três acontecimentos, na minha opinião, influenciaram muito o landscape de desenvolvimento de software entre os mundos comercial e de software livre, e eu acho que ainda não vimos tudo que pode sair disso até hoje.</p>
<p>No ano 2000 um novo projeto começou a aparecer como uma pesquisa, o Low Level Virtual Machine de Chris Lattner e Vikram Adve. Em resumo essa tecnologia se tornou um compilador modular que chamamos de LLVM apesar de não ser de fato uma máquina virtual como uma JVM. O monopólio dos compiladores, principalmente no mundo open source, era basicamente do GCC, responsável por compilar os códigos em C, C++ e várias outras linguagens, incluindo coisas como Fortran, e que gera o binário da kernel Linux e todas as ferramentas de licença aberta que rodam ao seu redor nas distribuições Linux. Mas o GCC é um grande monolito, com mais de 25 anos de contribuições e evoluções, complicado de evoluir, expandir e integrar. Porém com décadas de refinamento e ajustes, é definitivamente um dos melhores compiladores do mercado.</p>
<p>O LLVM foi criado pra ser diferente, ele separou o processo de compilação em 3 grandes estágios, front-end, otimização e back-end. Não confundir com as carreiras de front-end e back-end. Pense na entrada do compilador que é o front, o miolo, e a saída do compilador que é o back, Vale a pena eu explicar o que isso significa. Em resumo, o front-end pega o seu código fonte, digamos em C, e faz a checagem e o parsing. O resultado desse estágio é seu código limpo e traduzido em outra linguagem intermediária, chamada literalmente de Intermediate Representation ou IR. Não seria muito diferente do Java gerando bytecodes ou do .NET que gera em IL pro CLR que é literalmente Intermediate Language. Também meio parecido com o que um transpiler de Coffeescript ou Dart ou Typescript faz transformando em Javascript por baixo. Na sequência esse código em IR passa pelo tal miolo, a fase de otimização, que vai fazer todas aquelas otimizações que eu expliquei no episódio anterior pra deixar seu código o mais eficiente possível. Inclusive como o GCC e outros compiladores, essa fase pode precisar “passar” pelo código múltiplas vezes, você às vezes vai ver esse termo “passes” porque algumas otimizações exigem conhecimento do código anterior. Finalmente o LLVM pega esse sub-produto otimizado e passa pro back-end, que vai finalmente traduzir em binário de máquina, gerando o executável do seu programa. Mas o importante é entender que existem 3 grandes pedaços de software independentes que, juntos, formam o compilador.</p>
<p>Então, em vez de usar GCC pra compilar C, você pode substituir por Clang que é um front-end de C feito pra LLVM. Teoricamente hoje você poderia tirar o GCC e recompilar uma distribuição Linux inteira usando Clang, até existem projetos testando isso. Por muitos anos, fazer o LLVM cuspir um binário tão otimizado quanto o de GCC foi bem difícil. E também havia a questão: pra que eu quero substituir o GCC se ele já funciona tão bem?</p>
<p>Em 2005 a Apple fez um de seus movimentos mais interessantes e pouco comentados e contratou Chris Lattner, que na época estava em início de carreira na Microsoft Research. Em 2006 Steve Jobs sobe ao palco na conferência WWDC e anuncia a transição da plataforma Mac dos processadores IBM PowerPC para Intel, mais especificamente a nova linha de processadores Intel Core. O sistema operacional OS X 10.4 Tiger foi o primeiro compilado ainda com GCC pra rodar tanto em PowerPC quanto Intel.</p>
<p>Mas em 2007 teríamos a sequência com o OS X 10.5 Leopard e o XCode 3.1, a IDE de desenvolvimento pra Mac e junto com ela viria o compilador GCC 4.2 e junto o LLVM integrado ao code generator do GCC, que foi conhecido como LLVM-GCC. O XCode 4.1 da época do Mac OS X Lion de 2011 foi o último a vir com o GCC como compilador, e de lá em diante o desenvolvimento em MacOS e iOS depende só do Clang. Ou seja, de 2006 até 2008 os produtos com processadores PowerPC foram todos migrados para Intel. Mas mais importante que isso, o compilador GCC foi sendo gradativamente substituído por Clang, a partir de 2007 até pelo menos 2011. Guarde essa informação.</p>
<p>No começo do século um novo tipo de produto começou a fazer um sucesso estrondoso. Lembra quando eu contei qual era o objetivo original do Java quando ele foi criado no começo dos anos 90? Ser um sistema pra um hardware de set-top-boxes. Ele estava quase uma década adiantado porque foi só nos anos 2000 que esse tipo de produto realmente explodiu, em particular o Tivo. Aqui no Brasil não tivemos Tivo mas tivemos similares. Era aquele produto que você podia gravar programas de TV a cabo pra assistir depois. É o que se chamava de DVR ou Digital Video Recorder, basicamente um receptor de sinal analógico, que digitalizava o vídeo e gravava organizado num HD. Acho que até hoje algumas empresas de TV a cabo ainda oferecem esse tipo de produto. Mas nos Estados Unidos o Tivo teve um sucesso explosivo. Tecnicamente falando ele era um mini-pczinho com uma placa de captura de vídeo que rodava uma versão de distribuição Linux.</p>
<p>Não é hoje que vou entrar em detalhes sobre licenças de software livra, mas a kernel Linux e a maioria das ferramentas que compõe uma distribuição que forma um sistema operacional completo, as ferramentas GNU, o compilador GCC e tudo mais usavam a licença GPL v2. GPL que significa General Protection License. Na prática, qualquer um, especialmente qualquer empresa que modifique código licenciado via GPL é obrigado a republicar as modificações ao público. O GPL não é uma unaminidade, por isso existem outras licenças, mas a maioria das coisas num Linux costumava ser GPL. E foi o que a Tivo fez: ela seguiu a licença e liberou as modificações que fez. Isso inclusive permitia que hobistas pudessem baixar esse código, fazer suas próprias modificações e carregar no Tivo. Então era como se fosse um PCzinho que dava pra brincar e instalar seus próprios programas.</p>
<p>Pelo menos naquela época, a maioria das empresas não gostava que seus dispositivos fossem modificados pra fazer coisas que não deveriam. Existem motivos pra isso, e nem vou entrar no mérito de certo ou errado, vamos só entender que eles não gostavam. Então na série 2 eles adicionaram um hardware que validava a assinatura do binário. Eu não sei como exatamente eles faziam isso, mas se você é iniciante vale entender pelo menos o conceito básico. Existe uma coisa em computação que chamamos de hashing. Existem algoritmos como os antigos MD5 ou SHA-1 ou os atuais SHA-256 ou bcrypt. Sem entender de criptografia entenda que eles são funções. O argumento de entrada pode ser qualquer bloco de dados, seja texto ou seja um binário. E a saída é sempre um texto de tamanho fixo.</p>
<p>Isso não é encriptação. Quando se encripta alguma coisa, você consegue reverter o processo e desencriptar. Em hashing não existe forma de pegar o resultado e reverter o processo e conseguir o argumento original. Dois blocos de dados diferentes podem dar o mesmo resultado, isso seria o que chamamos de colisão, mas é raro que isso aconteça num cenário real. O importante é que esse resultado serve como uma impressão digital, um fingerprint, de seja lá qual dado você tenha passado pra função. Ou seja, digamos que você passe o binário do kernel Linux. E o Tivo tem um firmware separado que quando carrega a kernel passa o binário por essa função e compara com a impressão digital que ele tem guardado num hardware que você não pode modificar.</p>
<p>Ou seja, se você modificou o kernel e instalou lá, a impressão digital vai ser diferente, então o Tivo pode rejeitar esse novo binário e impedir o boot. Essa seria uma forma simplória de fazer isso. Existem formas mais sofisticadas mas esse exemplo deve ajudar a entender parte do processo. Isso seria um tipo de DRM ou Digital Rights Management que a indústria de música adorava. Mas a Tivo achou um loophole no GPL v2, uma brecha na licença. A licença obrigava a liberar o código modificado, e isso eles fizeram, mas ela não fala nada sobre impedir o hardware de rodar código modificado no seu hardware.</p>
<p>Isso foi uma controvérsia gigante porque esse sistema de DRM, do ponto de vista dos desenvolvedores, restringia a liberdade do que o consumidor poderia fazer com o hardware que ele comprou. Isso gerou uma enorme polarização na opinião se uma empresa podia ou não fazer isso. Richard Stallman e Eben Mogler, os criadores da licença GPL ficaram enfurecidos, porque a GPL v2 não conseguia proibir essa atitude. Então eles iniciaram a modificação da GPL v2 para o novo GPL v3 que adicionava cláusulas que impediria isso que eles chamaram de “Tivoização”. E se você acha que o mundo open source apoiou essa medida, você está enganado. Isso gerou uma nova controvérsia e uma nova polarização. Por exemplo, Linus Torvalds odiou a medida e a kernel do Linux permanece na GPL v2.</p>
<p>Como eu já havia explicado no episódio da Lerna vs a ICE, licenças de software livre podem ser divididas em duas grandes categorias: as licenças restritivas e as licenças permissivas. Ao contrário do que o senso comum pode imaginar, o GPL é uma licença restritiva. Licenças como BSD, MIT, Apache e outras são mais permissivas. Em última instância a GPL impõe uma restrição importante: você é obrigado a liberar qualquer modificação que fizer num código GPL e essa modificação também será GPL. E sem cláusulas especiais e sub-licenças como LGPL você teria que se preocupar inclusive, se o binário gerado por um compilador com licença GPL se ela herda o GPL e se pode ser usada livremente ou não. É por isso que inclusive muitos chamam a GPL de uma licença viral. Já código licenciado via BSD por exemplo, não tem essa restrição. Você pode modificar o código e não tem a obrigação de liberar a modificação. Você pode gerar um binário e comercializar o binário e não se preocupar em ter que liberar o código.</p>
<p>A discussão sobre licenças de software livre é em última instância uma discussão sobre propriedade intelectual. A maioria das empresas prefere ficar bem longe de licenças restritivas pra não comprometer suas propriedades intelectuais, que é o que garante o seu valor. Nos anos recentes no começo dos anos 2000 tivemos grandes casos controversos em torno de propriedade intelectual no mundo open source como o famoso caso da SCO ou Santa Cruz Operation que processou a IBM pedindo nada menos que 1 bilhão de dólares, alegando que eles infringiram na sua propriedade do UNIX e usaram esse conhecimento nas contribuições ao Linux que a IBM fazia.</p>
<p>Se a SCO tivesse ganhado isso teria sido uma bomba nuclear tornando o Linux material radioativo pra quem usasse. Mas numa virada de eventos um juiz determinou que quem possuía os direitos que a SCO clamava na verdade era a Novell. E nessa mesma época por 2005 ou 2006 a Microsoft fechou um acordo de 400 milhões de dólares com a Novell que era dona do Suse Linux, cujo combinado era que uma não iria processar a outra em torno de propriedade intelectual, meio que sugerindo que haveria alguma coisa no Linux que deixaria quem não usasse Suse Linux vulnerável a algum processo no futuro de alguma forma. A comunidade open source odiou esse movimento, claro.</p>
<p>Certo ou errado, vocês podem entender pelo menos porque levar propriedade intelectual e licenças a sério é importante, principalmente nos Estados Unidos. À medida que as empresas iam adotando tecnologias open source, essa dúvida sempre deixa todos com os nervos à flor da pele. Se o Linux, que é a kernel por baixo de todas as distribuições e que estava sendo adotado rápido por todos, fosse condenado num processo desses, ele se tornaria material radioativo e toda empresa usando poderia descobrir uma bomba relógio explodindo. Isso é realmente sério. Se nos anos 2000 alguém perguntasse porque a Apple preferiu usar a base do FreeBSD nos OS X em vez do Linux, esse certamente poderia ser considerado um dos principais motivos: o FreeBSD usa licença BSD que é bem permissivo, ao contrário da GPL que tinha todas essas dúvidas pairando no ar.</p>
<p>Agora, o GPL v3 é um problema sério. Que outra empresa além da Tivo prefere manter certos códigos escondidos e dificultar você de instalar o que quiser em seus hardwares? Eu sempre fui fã da Apple e certamente a integração de hardware e software que eles fazem é excepcional, mas se você pensar puramente em questão de software livre, você vai ficar no mínimo em cima do muro com as práticas da Apple. E não confunda, sim, a Apple tem o código da base do seu sistema operacional aberto ao público na forma do Darwin, mas o MacOS é bem mais que só o Darwin, tem centenas de componentes que eles não querem abrir, incluindo a forma como o sistema se integra perfeitamente nos Macs e Macbook e, claro, nos iPhones de hoje. Se você notou que um iPhone faz a mesma coisa que um Tivo, impedindo você de instalar outro sistema nele, você pensou certo.</p>
<p>No outro lado do espectro, além de distribuições baseadas na kernel Linux, existem as distribuições baseadas em BSD, como FreeBSD, OpenBSD, NetBSD. O Linux é como se fosse um clone de UNIX, mas os BSDs em princípio são herdeiros do UNIX original. BSD seria o concorrente da outra linhagem de UNIX, o System V que deriva da época do UNIX System III da AT&amp;T. Como o próprio nome diz, a filosofia dessas distribuições é Software Livre no sentido mais permissivo e liberal, com a licença BSD. Vamos dizer que eles “toleram” a GPL mas nunca gostaram dela e o GPL v3 foi uma afronta direta e ofensiva pra eles, e podemos dizer que eles não gostaram nada das cláusulas restritivas anti-Tivoização. Existe uma longa história de brigas políticas em torno do que é considerado Software Livre ou não e vou parar por aqui pra não me alongar demais por hoje.</p>
<p>O maior problema? Tudo no mundo open source era compilado com o GCC. Como eu já expliquei no episódio sobre a Lerna vs a ICE, licenças não podem ser mudadas retroativamente, só em novas versões. Como quem controla o GCC é o Richard Stallman, ele migraria pra nova GPL v3. Ou seja, quem não quisesse adotar a nova licença ficaria preso na versão 4 do GCC que ainda seria GPL v2. Então começou uma corrida contra o relógio. Você pode ficar usando o GCC que ainda era GPL v2 mas quanto mais tempo passa, mais ele fica defasado e até inseguro, já que correções e novas funcionalidade só iriam subir no GCC com GPL v3.</p>
<p>Resumo da história? Tanto FreeBSD quanto a Apple começaram um projeto que iria levar alguns anos pra sair do GCC e migrar a compilação de tudo pra usar LLVM e Clang, que era o único concorrente viável ao GCC. Se você alguma vez já se perguntou porque no MacOS vem um Bash tão antigo? Porque além do GCC outras ferramentas GNU mudaram pro GPL v3, o Bash foi um deles. Por isso hoje se instala o Bash mais novo e outras ferramentas com versões mais novas, como o próprio Git, você mesmo via Homebrew ou de outra forma manual como baixar os códigos fonte e gerando binários você mesmo. E por isso às vezes você tem confusão de compilar usando GCC ou Clang.</p>
<p>Pra Apple, além da questão das licenças, a linguagem Objective-C que é o coração dos frameworks de aplicativos nativos de MacOS e iOS nunca teve prioridade no grupo de desenvolvimento do GCC. Por causa disso o projeto Clang começou a avançar a passos mais largos e por isso eles começaram a estratégia de primeiro começar a usar GCC como o front-end pra LLVM, já que a primeira coisa mais difícil era parsear corretamente os códigos em C, C++ e Objective-C e por isso você começa com LLVM-GCC como eu disse antes. À medida que a compatibilidade do front-end entre GCC e Clang ficou mais próxima, daí eles começaram a colocar Clang como escolha padrão até finalmente remover completamente o GCC antigo.</p>
<p>Nesse período de 2006 então a Apple estava migrando seus sistemas operacionais de PowerPC pra Intel e ao mesmo tempo já estava planejando outro dispositivo pra ser lançado em 2007: o primeiro iPhone. E os iPhones não usam processador Intel e sim ARM. E os iPhones seriam sempre produzidos com o bloqueio de DRM pra impedir outro sistema de rodar no hardware, ou seja, eles seriam Tivoizados. E com todos os aplicativos desenvolvidos usando Objective-C e com a necessidade de compilar binários nativos pra Intel e para ARM.</p>
<p>Agora vamos entender outra coisa do LLVM que eu não disse antes. O LLVM é um conjunto modular de bibliotecas. O compilador Clang é um conjunto dessas bibliotecas. Como ele foi desenhado pra ser modular, significa que você teria relativa facilidade de trocar partes do front-end ou do back-end. Por exemplo, você pode fazer back-ends que cospem binários em Intel ou PowerPC ou ARM ou qualquer outro tipo de hardware. E como o front-end também é modular e ele cospe em IR antes de passar pro módulo de otimização, você também tem facilidade de integrar no XCode pra fazer análise estática do código e debug. Com a integração de ferramentas sofisticadas como o famoso DTrace do antigo Solaris e a substituição do debugger GDB que era usado com GCC pelo LLDB, a IDE do XCode foi ficando mais e mais avançada para conseguir instrumentar o código e otimizar muito melhor do que antes.</p>
<p>Ao mesmo tempo que Chris Lattner e sua equipe iam evoluindo o LLVM dentro da Apple, muitas das pesquisas geraram novas funcionalidades primeiro no próprio Objective-C como a introdução de lambdas e o ARC que é o Automatic Reference Counting. Pra você que é iniciante, na maioria das linguagens mais modernas você não pensa muito em gerenciar memória porque linguagens como Java tem garbage collectors, ou seja, o runtime gerencia a memória por você. Mas se você começou a aprender com linguagens como C, sabe que precisa você mesmo codificar o gerenciamento de memória manualmente. Ou seja, no seu código você chama funções como malloc e free e outros pra pedir memória pro sistema operacional e depois devolver essa memória. Lembra que eu falei que além de multi-thread o outro aspecto em programação mais difícil é gerenciamento de memória?</p>
<p>Pois é, à medida que sua aplicação fica complexa, você vai errar isso. Ao longo da sua carreira você vai ficar ouvindo falar de vazamento de memória por exemplo. Gerenciar memória é complicado, porque memória se fragmenta, você precisa lidar com coisas como regiões, arenas e muitos outros detalhes. Mas se você tem uma máquina potente, digamos, com 8GB de RAM ou mais, você fica preguiçoso e não percebe vazamentos porque tem memória sobrando. Pra facilitar se falta memória RAM o sistema operacional ainda tem a opção de usar o HD como memória. É isso que se chama de SWAP. Se você chega nesse ponto com uma aplicação mal feita que vaza memória, tudo bem, o sistema vai passar a usar HD. Tudo vai ficar lento pra caramba, mas não vai crashear. Mas pense em 2007 um iPhone com meros 128MB de RAM pra comportar o sistema operacional e os aplicativos e sem a opção de um HD pra fazer swap. Ou seja, se faltar memória o sistema vai crashear o aplicativo. Então gerenciar memória se torna especialmente importante em dispositivos com poucos recursos.</p>
<p>E como Objective-C é basicamente compatível com C e usa a mesma semântica de você manualmente codificar onde quer alocar memória e onde quer devolver essa memória, os primeiros aplicativos pra iOS que eram feitos por amadores ou mesmo por descuido acabavam tendo muitos vazamentos e crasheavam dando uma má experiência aos usuários. Por isso recursos como o ARC que foram introduzidos ao Objective-C eram importantes, pra evitar que você precise manualmente escrever código pra gerenciar memória, além da introdução de ferramentas como o DTrace e LLDB pra instrumentar seu código e conseguir analisar exatamente onde estão ocorrendo vazamentos, pra que você consiga consertar antes de mandar o binário final pra App Store.</p>
<p>E como desenvolvedor você ainda tem outro problema grave. Se você já tentou desenvolver pra Android deve ter notado que se quiser testar seu código antes de instalar no celular, a única forma de rodar no seu computador é usando uma máquina virtual. Não estou falando da JVM mas de máquinas virtuais de verdade como QEMU, VirtualBox ou VMWare. Primeiro porque o Android é um sistema operacional baseado em Linux e os binários estão pré-compilados pra processadores ARM. E binários de ARM não são compatíveis com processadores Intel que roda na sua máquina de desenvolvimento, seja PC ou Mac.</p>
<p>A única forma então é usar um emulador, que é uma máquina virtual, que vai traduzir as instruções de ARM em instruções de Intel. Quando você ouve que seu novo Samsung S10 ou mesmo Xiaomi Mi Mix rodam Qualcomm, você sabe que é um processador ARM. Então você programa seu aplicativo pra Android e sobe um emulador de Android como o da Bluestacks ou Nox ou qualquer outro no seu PC e ele vai emular o Android fazendo ele pensar que está rodando numa máquina ARM. Por isso é tudo tão absurdamente lento pra testar seu código, porque emular exige essa tradução de instruções e isso é lento. Não tem jeito.</p>
<p>Mas se você já desenvolveu pra iOS em Macs sabe que a mesma coisa não acontece quando você pede pra testar seu novo app de iPhone no seu Mac. Seu app roda com velocidade total, sem nenhuma lentidão. E você vai notar no XCode que quando vai rodar seu app no seu Mac de desenvolvimento, não existe uma opção pra subir um Emulador, como no Android, e sim um Simulador. A Apple fez uma coisa difícil mas que se pagou: eles compilam o sistema operacional iOS que roda em iPhone e iPad pra binários de Intel de verdade. Então quando você sobe o simulador, ele não precisa de uma máquina virtual pra traduzir as instruções, ele já é binário de Intel! E quando você compila seu projeto pra rodar no simulador o XCode está usando o LLVM pra cuspir binários de Intel também. Só quando você manda empacotar pra publicar na App Store que ele vai compilar em binário de ARM. Parece uma coisa meio óbvia de fazer, mas fazer isso da forma quase transparente como o XCode faz é impressionante até hoje dado que as ferramentas de desenvolvimento de Android do Google até hoje não fazem isso.</p>
<p>Por outro lado, alguns podem argumentar que apesar das funcionalidades impressionantes que a Apple conseguiu colocar no Objective-C, ele ainda tem a sensação de ser uma linguagem com sintaxe muito velha, especialmente se comparado ao Android onde o Google resolveu copiar a linguagem Java, embora similar ao J++ da Microsoft nos anos 90, ele também não é compatível com a JVM de verdade. O runtime do Android, o Dalvik é diferente. De qualquer forma, já discutimos como a linguagem Java também tem sintaxe considerada meio velha se comparada a coisas como Python ou Ruby ou mesmo Groovy. Mas se comparar com Objective-C - que eu pessoalmente gosto - a maioria vai dizer que prefere Java por estar mais acostumado e ter visto na faculdade.</p>
<p>Enquanto evoluía o LLVM, o Clang, os frameworks de iOS, as tecnologias do XCode, Chris Lattner começou a pensar numa nova sintaxe de linguagem. Assim em 2010 surgia o Swift, uma linguagem que é extremamente agradável ordens de grandeza se  comparado ao Objective-C. E aqui surge outra enorme vantagem do LLVM. Assim como você pode ter back-ends que cospem binários de Intel ou ARM, você também pode ter múltiplos front-end. Você já tinha o front-end que entendia Objective-C, então eles fizeram um novo front-end pra essa nova linguagem Swift. E qual a vantagem? Os binários de ambos Objective-C e Swift são compatíveis entre si. Então seria super fácil você migrar pra Swift e continuar consumindo as mesmas bibliotecas e frameworks que já existiam e eram feitos em Objective-C. Você não precisa reescrever tudo em Swift, pode migrar aos poucos.</p>
<p>Então no mundo de Mac e iOS você tem agora a escolha de usar Swift com sua sintaxe bem mais moderna inspirada em Ruby, Python, Groovy e outras linguagens, com construções modernas, com o ARC pra gerenciar memória e ter a facilidade de rodar sua aplicação iOS em velocidade máxima no simulador de iOS com tudo compilado em binário de Intel e depois facilmente empacotar em binário de ARM pra rodar no seu iPhone de verdade. Por isso muitos desenvolvedores preferem criar apps pra iOS antes de Android até hoje.</p>
<p>No mundo Android as coisas não eram muito agradáveis. O Google também teve sua parcela de dor de cabeça com processo por propriedade intelectual. Lembram que eu já falei várias vezes que a Sun tinha sido adquirida pela Oracle? Então, eles foram processados por usar Java e a Oracle veio atrás com força. Oito anos depois o processo ainda não acabou e em 2018 a Oracle estava ganhando a batalha. Mas todo esse stress não faz o Google ter muito amor pelo Java. Ao mesmo tempo eles decidiram começar a mudar o foco do Java pra outra linguagem, no caso o Kotlin.</p>
<p>No Android o processo é o seguinte: você escreve seu código em Java e pode usar um compilador normal pra gerar bytecodes Java. Por isso você pode também usar muitas bibliotecas Java que já existem. Daí o bytecode Java é traduzido num segundo conjunto diferente de bytecodes chamado DEX que é o que roda no Dalvik. Antes esse DEX era interpretado no Dalvik, e tinha mais ou menos as mesmas funcionalidades que uma JVM como um Just-in-time compiler ou JIT pra gerar o binário nativo de ARM à medida que era executado. Como eu também já disse, isso é bacana pra aplicativos que rodam num servidor que fica de pé por dias e dias. Mas num dispositivo móvel que você abre um aplicativo e fecha a qualquer momento, um JIT ajuda mas não tanto assim, porque ele não tem tempo pra otimizar como poderia. Fora que rodar um compilador JIT também consome processamento, e isso consome bateria, que é outra coisa que sempre falta em dispositivos móveis.</p>
<p>Então nas versões mais recentes o bytecode DEX é pré-compilado em binário nativo antes de rodar, esse é o processo que você vai ouvir falar como AOT ou Ahead-of-Time compiler. Que é o que um compilador normal como GCC ou Clang fazem: geram binários nativos. O processo de desenvolvimento no Android tem mais passos pra poder ter essa opção de compatibilidade com o bytecode Java, que foi uma jogada importante pra conseguir trazer programadores Java pro mundo Android sem precisar ensinar uma nova linguagem pra todo mundo.</p>
<p>Mas ao mesmo tempo temos a Oracle baforando no cangote do Google e a essa altura já disse várias vezes que Java é uma linguagem que já não é mais considerada agradável de trabalhar e nem tão produtiva se comparado a outras linguagens como o novo Swift. Então o Google foi bater na porta de outra empresa, a JetBrains, que a anos faz uma das melhores IDEs comerciais pro mundo Java, e em 2011 havia começado a criar uma nova linguagem, que assim como Groovy ou Scala ou Clojure também compilam em bytecode compatível com Java. Pro Google foi uma escolha fácil porque eles negociaram pra liberar as ferramentas da JetBrains de graça pra desenvolvedores Android e a evangelizar a nova linguagem deles, que é chamado de Kotlin. Kotlin que é finalmente uma linguagem moderna mas familiar e ser ser exótica demais como Clojure.</p>
<p>Então no mundo mobile, em iOS você ainda pode usar Objective-C que é considerado uma linguagem “velha” mas agora a maior parte do desenvolvimento é na linguagem Swift que é bem mais moderna e produtiva. Mesma coisa no mundo Android onde você ainda pode usar a linguagem Java e as bibliotecas Java que também já é considerado meio “velho” por muita gente mas também pode migrar pro Kotlin que está ainda em adoção por toda a comunidade Android. Você pode até misturar código Kotlin e Java no mesmo projeto. Na verdade, por coincidência, seja porque ambas se inspiraram em fontes parecidas na linhagem de linguagens, Swift e Kotlin tem sintaxes até que similares. Dependendo do código que você ver, pode até quase confundir um pelo outro. Claro, as bibliotecas de iOS e Android são bem diferentes, mas as duas linguagens são igualmente modernas e eu pessoalmente diria que são as melhores até agora para o mundo geral de programação de aplicativos, especialmente se comparar com Java ou C#.</p>
<p>Mas deixando o mundo mobile um pouco de lado, um dos resultados de tudo isso foi a evolução rápida do LLVM enquanto uma solução robusta pra desenvolvimento de compiladores. Em vez de ter que mexer no monolito complicado que é o GCC e ainda ter que lidar com a política da licença GPL v3, você pode ir pro LLVM e foi isso que muita gente fez, menos o Google. Pra ser justo, o Google contribui pro LLVM também mas não usa tão extensivamente quanto a Apple. A linguagem Go eles preferiram criar o compilador do zero, primeiro em C e depois traduzindo o código C no próprio Go. Lembra que eu falo que o Google tem a péssima mania de ficar reinventando a roda? A gente chama isso de NIH ou síndrome de Not-Invented Here, muitos programadores sofrem dessa síndrome de prima-donna de achar que pode fazer melhor que os outros.</p>
<p>Mas já sabemos que C/C++, Objective-C e Swift tem front-ends pra LLVM e sabemos que ele tem back-ends que geram binários pra Intel e ARM. E sabemos que ele tem um design mais moderno, mais modular e com ferramentas mais modernas pra desenvolvedores como o LLDB  que muitos consideram melhor do que o antigo GDB. E ele ficou muito bom em otimizar o IR pra gerar binários nativos quase tão performáticos quanto o GCC. Isso abre uma oceano de possibilidades. E se decidíssemos criar mais front-ends pra outras linguagens?</p>
<p>E foi isso que a comunidade open source começou mesmo a fazer. Hoje temos front-ends de LLVM pra ActionScript, Ada, C#, Common Lisp, Crystal, CUDA, D, Delphi, Fortran, Graphical G, Halide, Haskell, bytecode Java, Julia, Kotlin, Lua, Objective-C, a linguagem de shading de OpenGL, Pony, Python, R, Ruby, Rust, Scala, Swift, e Xojo.
Mas claro, algumas estão mais avançadas do que outras, algumas são mais experimentais. Algumas usam só algumas funcionalidades como o Just-in-Time compiler do LLVM que é o caso da linguagem Julia e inclusive em lugares inusitados como o banco de dados PostgreSQL que hoje também usa o JIT do LLVM pra otimizar queries complexas.</p>
<p>Uma das linguagens que você mais deve ter ouvido falar que depende de LLVM é o Rust da Mozilla. Agora você sabe o que roda por baixo do Rust e quem gera os binários. A linguagem Rust é uma das mais diferentes de todas que já mencionamos até agora. Sem entrar em muitos detalhes hoje, ela tem um foco maior no problema do gerenciamento de memória combinado com preocupação de segurança. Mas seu maior problema é o que chamamos da ergonomia da linguagem. Apesar de ser uma sintaxe moderna, ela realmente exige mais do desenvolvedor se comparado a um Swift ou Kotlin. Partes do Firefox hoje são escritos com Rust e, adivinhem, alguns evangelistas da linguagem são ex-rubistas também.</p>
<p>Outra linguagem que compila com LLVM que ainda não é muito conhecida mas que eu pessoalmente gosto bastante é a Crystal. Ela se parece muito, mas muito mesmo com Ruby já que é inspirada diretamente nela, e em alguns casos você pode quase copiar e colar trechos de código Ruby e compilar com Crystal sem mexer em nada, então a curva de aprendizado pra quem vem de Ruby é muito mais simples. Ao contrário de Rust a ergonomia da linguagem é muito melhor. Mas Rust tem características que a tornam mais adequadas como substituto de C pra desenvolver código nativo rápido e leve. O Crystal se assemelha mais ao Go, ele tem um runtime maior e um garbage collector maior também. Diferente do Go que tem o investimento infinito Google por trás, o Crystal é um esforço quase voluntário da comunidade, por isso anda mais devagar. Mas graças ao LLVM os binários que o Crystal gera são competitivos com Go mesmo nesse estágio.</p>
<p>E mesmo sem ser programador você provavelmente usa tecnologias LLVM hoje e nem sabe disso. Por exemplo tanto o SpiderMonkey que é a engine, ou motor, de Javascript do navegador Safari no MacOS e no iOS quanto o V8 que é a engine de Javascript do Chrome possuem a funcionalidade de Just-in-Time Compiler ou JIT que eu mencionei já hoje e no episódio anterior. Repetindo: Javascript é uma linguagem interpretada, como Python ou Ruby. O SpiderMonkey e o V8 recebem o arquivo de texto escrito em Javascript e fazem um parsing e começam a interpretar o código.</p>
<p>Porém como vocês já sabem e eu expliquei no episódio da História do Front-end nesta série, começou a surgir o conceito de Single Page Application, que é basicamente um site que se comporta mais como um aplicativo de desktop do que um site web normal de conteúdo. Na prática são sites onde você não fica navegando entre diversas páginas, você carrega uma página e fica nela e por sua vez ela carrega muito javascript pra controlar o comportamento. Imagine Google Docs, ou Spotify. Nesses casos as engines de Javascript, quando percebem que estão rodando faz algum tempo começam um processo que é mais devagar, que é o JIT, e começam a otimizar e compilar as partes do código Javascript mais executadas em binário nativo, que ainda depende do runtime das engines, mas é bem mais eficiente do que interpretação.  No caso, o SpiderMonkey usa o JIT do LLVM. SpiderMonkey e V8 passaram anos evoluindo e competindo pra ver quem era o melhor e acho que isso continua assim até hoje.</p>
<p>Por isso aplicativos como Spotify, Atom, Slack, Discord e outros conseguem rodar com performance aceitável. Some a isso que os navegadores por baixo hoje suportam CSS acelerado pelo hardware gráfico, as GPUs como o que já vem integrado no seu processador Intel ou placas externas como os GeForce da NVIDIA ou os Radeon e Vega da AMD. A evolução do que chamamos de GPU foi uma explosão neste século como o de CPUs foi nos anos 70 a 2000. Num determinado momento as GPUs passaram a suportar shaders, que como o nome diz, serviam pra controlar a sombra ou tonalidade das cores. Mas em breve elas passaram a ser programáveis numa linguagem similar a C. E adivinhem, podemos acelerar esses shaders compilando em tempo real, via um JIT, usando LLVM hoje em dia. Por isso se você executar um VirtualBox, a renderização gráfica via software, que é lento, hoje é compilado via JIT por um driver chamado llvmpipe. Se você lida com desenvolvimento com placas NVIDIA tem o compilador pros CUDA cores da GeForce, e a NVIDIA contribuiu os códigos de back-end pra permitir gerar shaders pras suas placas diretamente no LLVM abrindo as portas pra qualquer linguagem poder se beneficiar do processamento paralelo massivo em GPUs.</p>
<p>Agora, o último assunto de hoje pra você entender como o LLVM pode ir mais longe. O Front-end pode ser qualquer linguagem, ele cospe o IR, que é otimizado e depois passado pra um Back-end, que também pode ser qualquer coisa, por exemplo, os back-ends que geram binários de Intel ou ARM como já repeti várias vezes. Porém, vocês já viram que existem os transpilers, como o do Typescript que cospe Javascript. E se pudéssemos usar um front-end de C como o Clang e usar um back-end que cospe Javascript?</p>
<p>Esse é o projeto Emscripten. A demonstração mais impressionante se não me engano em 2014 foi quando a Epic Games pegou uma animação usando a engine de jogos Unreal e compilou com esse Emscripten, usando LLVM, de C pra Javascript e somado às capacidades de aceleração via GPUs dos navegadores via WebGL, conseguiu rodar o que antes era um programa nativo dentro de um navegador, com excelente performance graças a tudo que eu expliquei que dá pra fazer com LLVM. Pra fazer isso, eles limitaram o Javascript num sub-conjunto que ficou conhecido como ASM.js. O conceito é simples: CPUs tem instruções nativas, que podemos escrever em Assembly e usar um Assembler pra cuspir o bytecode nativo da máquina. Máquinas virtuais como a JVM tem seus bytecodes. E se considerarmos que o Javascript é um assembly da máquina virtual chamada navegador?</p>
<p>Isso abre todo um leque de possibilidades. E foi o que inspirou o projeto WebAssembly que surgiu pra formalizar esse sub-conjunto de Javascript que poderia ser o back-end pra compiladores baseados em LLVM. Hoje em dia ainda temos o Enscripten pra compilar em ASM.js e o novo projeto Brynaryen que nasceu sendo uma extensão do Enscripten mas foi reescrito do zero em C++ pra gerar WebAssembly - maldita síndrome de not-invented here, a Mozilla também sofre disso como o Google. Ainda não tivemos nenhum resultado bombástico, mas diversos grupos estão fazendo experimentos pra entender o que realmente podemos fazer. Se você procurar por emscripten vai ver demonstrações muito interessantes, inclusive uma pequena distribuição de Linux compilado inteiro com Emscripten e rodando dentro do navegador, sem emulação nem nada. Na prática, no futuro, poderíamos escrever aplicativos Web em qualquer linguagem e compilar tanto pra WebAssembly quanto pra binário nativo se quiséssemos. Mas ainda estamos no começo dessa jornada.</p>
<p>E por hoje vamos ficar por aqui, pra variar virou um episódio grande, mas eu queria contar essa história pra que você pudessem entender como política influencia a evolução das linguagens, ferramentas e arquiteturas que nós usamos hoje. Não é só uma questão se determinada linguagem é mais rápida que outra ou não. Como programador você precisa entender como diversos fatores externos e modelos de negócio e interesses políticos influenciam tudo que você usa.</p>
<p>Na semana que vem vou retornar ao tema de back-end falando sobre outro assunto que é controverso e muitos se confundem até hoje: concorrência e paralelismo e como diferentes linguagens lidam com isso de formas diferentes. Se ficou com dúvidas nesse episódio não deixe de mandar nos comentários abaixo, se curtiram mandem um joinha, compartilhem com seus amigos, assinem o canal e não deixem de clicar no sininho pra não perder os próximos episódios. A gente se vê semana que vem, até mais!</p>
]]></content:encoded><category>linguagens-de-programacao</category><category>apple</category><category>open-source</category><category>akitando</category></item><item><title>Da Microsoft para a Apple e de Volta</title><link>https://akitaonrails.github.io/2017/11/21/da-microsoft-para-a-apple-e-de-volta/</link><guid isPermaLink="true">https://akitaonrails.github.io/2017/11/21/da-microsoft-para-a-apple-e-de-volta/</guid><pubDate>Tue, 21 Nov 2017 21:51:00 -0200</pubDate><description>&lt;p&gt;Este vai ser um artigo bem longo, se preparem.&lt;/p&gt;
&lt;p&gt;Para quem tem pressa, o resumo é este:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows 10 ainda é Windows, mas não chega nem perto do pesadelo dos anos 2000. Merece uma segunda chance de verdade.&lt;/li&gt;
&lt;li&gt;O OS X está a caminho de se tornar apenas um runtime do Xcode. Rumores dizem que a Apple nem tem mais uma equipe dedicada ao SO de desktop. O foco é total no iOS e em transformar o iPad no substituto do computador.&lt;/li&gt;
&lt;li&gt;Linux é ótimo. Se você é desenvolvedor web em tempo integral, consegue trabalhar confortavelmente com Ubuntu ou Manjaro/Arch (minha recomendação pessoal).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Melhor custo-benefício: o Dell XPS 13. O Surface Book 2 vale cada centavo se você é nerd como eu. Mas, como sempre, há ressalvas a discutir.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Este vai ser um artigo bem longo, se preparem.</p>
<p>Para quem tem pressa, o resumo é este:</p>
<ul>
<li>Windows 10 ainda é Windows, mas não chega nem perto do pesadelo dos anos 2000. Merece uma segunda chance de verdade.</li>
<li>O OS X está a caminho de se tornar apenas um runtime do Xcode. Rumores dizem que a Apple nem tem mais uma equipe dedicada ao SO de desktop. O foco é total no iOS e em transformar o iPad no substituto do computador.</li>
<li>Linux é ótimo. Se você é desenvolvedor web em tempo integral, consegue trabalhar confortavelmente com Ubuntu ou Manjaro/Arch (minha recomendação pessoal).</li>
</ul>
<p>Melhor custo-benefício: o Dell XPS 13. O Surface Book 2 vale cada centavo se você é nerd como eu. Mas, como sempre, há ressalvas a discutir.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/663/20171121_111616.jpg" alt="Book 2"  loading="lazy" /></p>
<h2>As Especificações<span class="hx:absolute hx:-mt-20" id="as-especificações"></span>
    <a href="#as-especifica%c3%a7%c3%b5es" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Não vou duplicar cada <a href="https://www.youtube.com/watch?v=-Hh0lZ7Jg4U"target="_blank" rel="noopener">review de hardware</a> que você encontra por aí. Todos são verdadeiros. Como o <a href="https://www.ifixit.com/Teardown/Microsoft&#43;Surface&#43;Book&#43;2&#43;Teardown/100364"target="_blank" rel="noopener">iFixIt diz</a>: é a pior pontuação em reparabilidade. Como o MacBook, a linha Surface é uma declaração. É a melhor combinação de design e funcionalidade. A contrapartida é que tem zero de expansibilidade e você precisa tomar cuidado para não quebrá-lo. Se quebrar, garanta que tem garantia e exija a substituição.</p>
<p>Em termos de especificações, fica próximo dos outros notebooks top de linha.</p>
<p>O Surface Book 2 top de linha custa <a href="https://www.microsoft.com/en-us/surface/devices/surface-book-2/overview"target="_blank" rel="noopener">USD 3.299</a> e vem com SSD de 1 TB, 16 GB de RAM, GTX 1060 com 6 GB GDDR5, Intel Core i7 8ª geração Kaby Lake R, display 4K. Caríssimo, mas dá para justificar. Explico mais abaixo.</p>
<p>O Dell XPS 15&quot; Touch top de linha custa <a href="http://dell.to/2jMDOx5"target="_blank" rel="noopener">USD 2.459</a> e vem com SSD de 1 TB, <strong>32 GB de RAM</strong>, GTX 1050 com 4 GB GDDR5, Intel Core i7 7ª geração Kaby Lake, display 4K. O design do XPS é impecável faz pelo menos 3 gerações. Para mim, é o melhor custo-benefício.</p>
<p>O Razer Blade top de linha custa <a href="https://www.razerzone.com/gaming-laptops/razer-blade/shop"target="_blank" rel="noopener">USD 2.599</a> e vem com SSD de 1 TB, 16 GB de RAM, GTX 1060 com 6 GB, Intel Core i7 7ª geração, display 4K. É provavelmente o melhor design industrial do grupo, com a atenção impecável da Razer aos detalhes. Mas também é o que tem menos suporte disponível e mais problemas de construção relatados, então cuidado ao comprar no exterior.</p>
<p>O HP Spectre x360 top de linha custa <a href="http://store.hp.com/us/en/pdp/hp-spectre-x360-15-bl152nr"target="_blank" rel="noopener">USD 1.499</a> e vem com SSD de 512 GB, GeForce MX150 com 2 GB GDDR5, Intel Core i7 8ª geração, display 4K. O design é lindo, super fino e conversível. As especificações não são lá essas coisas, mas é o mais barato entre os notebooks premium.</p>
<p>O Lenovo Yoga 920 14&quot; Vibe top de linha custa <a href="http://lnv.gy/2A4DjlU"target="_blank" rel="noopener">USD 1.899</a> mas vem apenas com gráficos integrados Intel (sem GPU secundária), SSD de 1 TB, 16 GB de RAM, Intel Core i7 8ª geração, display 4K, e já inclui a Caneta. O design é ótimo, com uma dobradiça de quase 360 graus para usar como tablet. Um bom 2-em-1.</p>
<p>Agora, o MacBook Pro 15&quot; top de linha custa <a href="http://apple.co/2zXSz6d"target="_blank" rel="noopener">USD 3.399</a> e vem com SSD de 1 TB, Radeon Pro 560 com 4 GB, Intel Core i7 7ª geração, display UHD e a infame touch bar (50% de chance de gostar). É isso. O design industrial e a construção ainda são excelentes, mas os concorrentes chegaram bem perto.</p>
<p>Se você usa aplicações gráficas intensivas, a Radeon Pro 560 é boa, mas a GTX 1060 é <a href="http://bit.ly/2zsIjE5"target="_blank" rel="noopener">superior</a>. Os displays UHD IPS (LCD) da Apple têm resolução máxima de 2560x1060. Todos os notebooks premium hoje vêm com displays 4K completos (LED) com resolução máxima de 3840x2160. A diferença é perceptível. Se você nunca viu um display 4K moderno, o display do MacBook vai parecer bom. E isso sem mencionar que todos são touchscreens com 4.096 pontos de sensibilidade. O que antes era gimmick hoje rivaliza com o melhor que a Wacom tem a oferecer. A linha Surface chega perto do topo da linha Wacom Cintiq e do novo iPad Pro. Estão no mesmo nível.</p>
<p>Há 2 aspectos do Surface Book 2 que deixam a desejar. Primeiro, a ausência de uma porta Thunderbolt 3 de verdade. Sem ela, você não consegue conectar armazenamentos externos modernos ou GPUs externas. O segundo é a fonte de alimentação fraca. Relatos indicam que em jogos muito exigentes (como Destiny 2 sem configuração adequada), o sistema throttla e drena a bateria mais rápido do que consegue carregar da tomada. <a href="https://www.theverge.com/2017/11/21/16685986/microsoft-surface-book-2-power-problem"target="_blank" rel="noopener">The Verge quebrou essa história</a> e a Microsoft ainda não apresentou solução. Então, se jogos são prioridade máxima, compre um Razer ou qualquer notebook específico para games, como um Alienware. O problema de bateria <a href="https://www.youtube.com/watch?v=imzVR4JSITM&amp;t=1s"target="_blank" rel="noopener">não é tão dramático</a> quanto alguns relataram anteriormente.</p>
<p>Em termos de construção: Macs são todos feitos com a mesma construção unibody de alumínio. O Book 2 usa magnésio. Fica muito sólido e bem leve. Aliás, depois de tantos anos, todo mundo dominou o alumínio. E estão indo em outras direções. A Dell, por exemplo, usa fibra de carbono nos apoios de pulso, o que acho muito mais confortável. O magnésio também não é tão gelado quanto o alumínio. Gosto que os fabricantes superaram a fase de copiar e estão experimentando materiais novos e interessantes.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/664/20171121_111533.jpg" alt="it’s not as thin"  loading="lazy" /></p>
<h2>A Proposta de Valor<span class="hx:absolute hx:-mt-20" id="a-proposta-de-valor"></span>
    <a href="#a-proposta-de-valor" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Já estabelecemos que o Surface Book 2 é caríssimo e nem é bom o suficiente para jogos muito exigentes como Destiny 2.</p>
<p>Onde ele realmente brilha é no fato de não ser um 2-em-1 conversível comum como o Spectre ou o Yoga. Você já sabe que a tela pode ser desacoplada da base.</p>
<p>A grande conquista da equipe Surface é a <strong>dobradiça fulcrum dinâmica</strong>. Uma maravilha de engenharia. Quando acoplada, não balança nem perto do que se esperaria. É muito sólida — você pode pegar o conjunto inteiro pela tela sem se preocupar que a base vai cair ou quebrar.</p>
<p>Quando ouvi falar nisso pela primeira vez, 2 anos atrás, achei legal mas pensei que poderia quebrar com o tempo, então esperei. Agora estou totalmente convencido porque 2 anos depois não se vê nenhum &ldquo;hinge-gate&rdquo; ou relatos massivos de dobradiças se desfazendo. E 2 anos depois nenhum outro fabricante tem isso. Se você não vê uma cópia barata vinda da China, é porque é muito difícil de construir. A Microsoft acertou em cheio nessa parte.</p>
<p>Com a tela removível, os componentes principais ficam todos atrás dela. CPU, GPU, RAM, SSD. Você tem um Intel i7 top de linha em um tablet! A bateria é compreensivelmente pequena (no máximo 3 horas) para alimentar um display 4K de 15&quot; com capacidade touch e precisão suficiente para rivalizar com o iPad Pro e o Wacom Cintiq ou Mobile Studio.</p>
<p>O que a maioria não menciona é que, por causa disso, é o chassi da tela que esquenta. A base de performance fica fria! É super confortável ficar com ele no colo por muitas horas sem risco de ficar estéril ou cozinhar ovos no processo.</p>
<p>Tem potência para conectar 1 display 4K externo a 60hz ou dois displays 4K a 30hz. O MacBook Pro, com sua porta customizada, consegue alimentar um display 5K. Algo que a maioria dos notebooks ainda não consegue. Aí vai depender do uso.</p>
<p>Não sou designer de profissão, mas sou hobbyista. Depois de muitos anos de trabalho duro, acredito que posso me dar ao luxo de ter algo assim. E não me entendam mal, o Surface Pro é outra ótima opção para designers. O Surface Pro top de linha tem tudo que o Book 2 tem, sem a GTX 1060, mas custando USD 600 a menos, em <a href="https://www.microsoft.com/en-us/surface/devices/surface-pro/overview#surfaceconfiguration"target="_blank" rel="noopener">USD 2.699</a>. Acho que é um produto mais adequado para a maioria das pessoas que querem uma solução de esboço fácil de carregar.</p>
<p>Profissionais criativos são os que precisam ser mais cuidadosos nas especificações. Mas para a maioria dos profissionais sem demandas tão pesadas, dá para pagar bem mais barato. Não precisam de GPU extra, nem do i7 (um i5 já resolve), 8 GB de RAM são suficientes, até 256 GB de SSD já dão conta porque tudo hoje está na &ldquo;Nuvem&rdquo;. Esse é o <a href="http://www.dell.com/en-us/shop/dell-laptops/new-xps-13/spd/xps-13-9360-laptop/dncwtr744h"target="_blank" rel="noopener">Dell XPS 13 de USD 999</a>. Ou a única opção comparável da Apple é o <a href="https://www.apple.com/shop/buy-mac/macbook"target="_blank" rel="noopener">MacBook de USD 1.299</a> com um ridículo processador Intel m3. Para a maioria dos profissionais, o Dell XPS 13 mais barato é uma proposta de valor muito melhor do que o MacBook.</p>
<p>Para profissionais com demandas pesadas, o Dell XPS 15 é o melhor custo-benefício. O Surface Book 2 é o premium para quem valoriza a touchscreen mais do que o fluxo de trabalho. Em termos práticos: designers vão de Book 2, editores de vídeo ou modeladores 3D vão de Dell XPS.</p>
<p>Ah, e mais uma coisa sobre preço. O MacBook Pro 15&quot; custa USD 3.399 e o Book 2 custa USD 3.299. Mas se você quiser um tablet, ainda precisa adicionar USD 949 por um iPad Pro de 12&quot; com Wi-Fi e 256 GB de armazenamento. E vai acabar carregando uma mochila mais pesada.</p>
<h2>Por que não instalar Linux?<span class="hx:absolute hx:-mt-20" id="por-que-não-instalar-linux"></span>
    <a href="#por-que-n%c3%a3o-instalar-linux" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Você não compra um produto Surface a menos que tenha interesse na experiência e no ecossistema da <strong>Surface Pen</strong>. Isso me parece óbvio, caso contrário você está melhor com um Dell XPS ou qualquer outro notebook mais barato.</p>
<p>Também é óbvio por que não faz sentido perguntar <em>&ldquo;Por que não abandona o Windows e instala Linux nele?&rdquo;</em>. Porque nenhuma distribuição Linux tem suporte à Caneta. A base de performance também tem uma tecla física que você precisa pressionar para que a dobradiça libere a tela.</p>
<p>Você vai querer ter Adobe Photoshop, Autodesk Sketchbook, Sketchable ou qualquer outro pacote de software excelente disponível. Não vou repetir cada <a href="https://www.youtube.com/watch?v=U8cpC2jZdgM"target="_blank" rel="noopener">review disponível</a> mostrando quão boa é a caneta. Confirmo apenas que sim, a caneta é excelente, precisa, fiel, e flui de forma muito natural. É um estúdio inteiro numa caixa só.</p>
<p>Desenvolvedores de software deveriam <strong>evitar</strong> esse tipo de produto porque a maioria das distribuições Linux não terá os drivers adequados para tantas soluções de hardware exclusivas. Para essas situações, recomendo muito o Dell XPS 13, especificamente <a href="http://dell.to/2A3SPOZ"target="_blank" rel="noopener">a configuração de USD 1.759</a> com Windows 10 Pro (ou economize USD 60 pegando a edição Home se pretende instalar Linux por cima), o ótimo display touch InfinityEdge QHD+ (3200x1800), Intel Core i7 8ª geração, 16 GB de RAM, SSD de 512 GB. É, de longe, o melhor custo-benefício para um desenvolvedor de software em tempo integral.</p>
<p>O OS X tem uma comunidade excelente <strong>apesar</strong> da Apple não fazer muito para ajudá-la. Historicamente, a transição do MacOS legado para o OS X significou ter um kernel e toolchain compatíveis com UNIX disponíveis. Até hoje, ainda não é comparável a uma distribuição Linux moderna. Mas o OS X compensa isso por ter, de longe, o melhor Compositor Gráfico do mercado. A GUI é fluida, responsiva.</p>
<p>O kernel Darwin Mach suporta múltiplas políticas, e a mais importante para Profissionais Criativos, especialmente músicos, era a capacidade de <strong>soft real-time</strong> do scheduler. Até hoje, o <a href="https://wiki.archlinux.org/index.php/Realtime_kernel"target="_blank" rel="noopener">Linux Real Time</a> não é a opção padrão, e não é tão bem ajustado nem estável. E o kernel do Windows evoluiu, mas ainda está longe de ser tão polido.</p>
<p>O Soft Real-Time evita o efeito de travamento que observamos. E é um dos fatores pelo qual a experiência Mac é, no geral, superior mesmo em hardware menos potente.</p>
<p>Em particular, todos na comunidade do <a href="https://brew.sh/"target="_blank" rel="noopener">Homebrew</a> merecem muito elogio pelo esforço de continuar trazendo ferramentas open source para o OS X, <strong>apesar</strong> de cada nova atualização do Xcode e do OS X quebrar tudo.</p>
<h2>Meu Ambiente<span class="hx:absolute hx:-mt-20" id="meu-ambiente"></span>
    <a href="#meu-ambiente" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/662/20171121_111546.jpg" alt="Magnesium Body"  loading="lazy" /></p>
<p>Depois de muita experimentação, decidi usar o Windows 10 nativo como host e uma distribuição Linux completa (<a href="https://manjaro.org/get-manjaro/"target="_blank" rel="noopener">Manjaro GNOME</a>) em um ambiente Virtualbox, alocando 4 dos 8 cores (2 cores físicos, cada um com 2 hyperthreads) e metade da memória (8 GB).</p>
<p>Por que não usar o novíssimo <a href="https://msdn.microsoft.com/en-us/commandline/wsl/faq#can-i-run-all-linux-apps-in-wsl"target="_blank" rel="noopener">Windows Subsystem for Linux (WSL)</a>?</p>
<p>Porque embora seja promissor, ainda precisamos esperar que resolvam as arestas. Em particular, um suporte melhor a GUI e uma abstração de I/O mais rápida. O que dói mais é como a camada de sistema de arquivos é <strong>dolorosamente lenta</strong> agora. É uma <a href="http://www.akitaonrails.com/2017/09/20/windows-subsystem-for-linux-e-bom-mas-ainda-nao-suficiente"target="_blank" rel="noopener">ordem de magnitude mais lenta</a> do que usar Linux no Virtualbox.</p>
<p>Poderia usar uma solução híbrida estilo Vagrant, com uma distribuição Linux headless no Virtualbox e acessando arquivos via CIFS/NFS. Funcionaria bem se você gosta de editores como Sublime Text 3, Visual Studio Code ou Atom. Mas sou do time Vim e gosto do GVIM, que funciona melhor dentro do GNOME, dentro de uma distribuição Linux com GUI de verdade.</p>
<blockquote>
  <p><em>&ldquo;Por que não usar Docker? É super rápido e tal.&rdquo;</em></p>

</blockquote>
<p>Me surpreende quando as pessoas perguntam isso, porque demonstra como pouco entendem das ferramentas que recomendam.</p>
<p>Docker faz sentido de verdade em uma distribuição Linux nativa. No Windows, precisa rodar Linux no Virtualbox ou Hyper-V. No Mac, usa o framework Hypervisor, que — como o Hyper-V da Microsoft — é uma camada de <strong>virtualização</strong>. É basicamente o mesmo que Virtualbox, para todos os efeitos práticos.</p>
<p>Docker, como o LXC, apenas faz um processo &ldquo;acreditar&rdquo; que está rodando sozinho no SO ao ocultar os outros processos. Então, no Linux, é super rápido. Em qualquer outra plataforma, precisa virtualizar o Linux e então rodar o Docker lá dentro.</p>
<p>O cliente Docker está na verdade se comunicando com um Linux virtualizado no Windows ou Mac. Se você acreditou que é mais rápido que Virtualbox ou Hyper-V de forma significativa, foi enganado. Não há mágica aqui.</p>
<blockquote>
  <p><em>&ldquo;Por que não dar dual-boot então?&rdquo;</em></p>

</blockquote>
<p>Isso também não resolve meu cenário. Quero um ambiente GNOME completo com GUI. E não quero manter Outlook no Windows e Thunderbird ou Evolution no Linux, gerenciando contas diferentes em todo tipo de aplicação (e sim, prefiro muito binários nativos a web apps, sou old-school assim). Não quero reiniciar quando quiser usar o Photoshop e reiniciar de volta para Linux para usar o Vim.</p>
<p><strong>Quero</strong> ter software de ambas as plataformas disponível <strong>ao mesmo tempo</strong>. Não acredito em cenários de dual-boot a menos que os usos sejam completamente separados. Por exemplo, usar uma distribuição Linux o dia todo e à noite reiniciar no Windows para rodar o Steam e jogar.</p>
<p>Sim, o Virtualbox terá uma UI menos responsiva por causa do pipeline gráfico virtualizado. Mas para desenvolvimento de software, funciona perfeitamente. Até vejo pessoas fazendo coisas mirabolantes como ter um ambiente de desenvolvimento inteiro em uma instância EC2 da AWS e acessar via SSH com Vim e Tmux. Isso é bem mais complicado, na minha opinião. Não iria tão longe.</p>
<p>Todo o hardware top de linha que listei acima tem Cores e RAM suficientes para rodar 2 SOs ao mesmo tempo. Não faça isso em hardware básico.</p>
<p>E se não precisar de um notebook para carregar, com o mesmo dinheiro você compra um computador desktop muito superior.</p>
<blockquote>
  <p><em>&ldquo;Mas no OS X você tem tudo nativo, porque é UNIX e tal&rdquo;</em></p>

</blockquote>
<p>Sim, mas desconfio muito das grandes atualizações do OS X da Apple. Elas sempre, sempre estragam alguma coisa. Depois de ter minha cota de dias de trabalho perdidos pós-atualizações, migrei meu ambiente de desenvolvimento para o <a href="https://www.vagrantup.com/"target="_blank" rel="noopener">Vagrant</a> pelo menos 5 anos atrás. Então já estava usando Linux no Virtualbox (ou VMWare) o tempo todo. Nunca olhei para trás. Ficava lendo as reclamações das pessoas depois das grandes atualizações e eu estava lá, ileso e produtivo. O Virtualbox era muito pior naquela época, hoje não é tanto. Não me lembro da última vez que travou, se é que travou alguma vez.</p>
<blockquote>
  <p><em>&ldquo;Mas por que não usar Hyper-V em vez do Virtualbox?&rdquo;</em></p>

</blockquote>
<p>Tentei. E não recomendo agora. Foi construído para que o Windows rode caixas Linux em <strong>servidores</strong>. Então é excelente para particionar recursos de hardware entre diferentes instâncias virtuais. A menos que você seja sysadmin em treinamento ou precise de um servidor simulado no seu notebook, não é para você.</p>
<p>Tem suporte muito ruim para gráficos (servidores headless não precisam de gráficos). A resolução máxima no monitor virtual é um ridículo 1152x864. Meu Virtualbox suporta meu monitor LG Ultrawide 2560x1080 tranquilamente. O Hyper-V não consegue e isso é um dealbreaker.</p>
<p>Virtualbox, VMWare, Parallels e Hyper-V vão todos usar as mesmas instruções VT-X fornecidas pela Intel. A performance base não vai ser tão diferente. As ferramentas de guest podem diferir. Alguma estabilidade pode diferir. Mas no geral, são basicamente a mesma coisa do ponto de vista da usabilidade.</p>
<p>Sei que parece &ldquo;estranho&rdquo; rodar o Windows 10 como host nativo principal. Mas funciona bem no geral.</p>
<p>E também sei que parece ainda mais estranho rodar uma distribuição Linux como SO convidado secundário no Virtualbox. Mas posso dizer que quando estou usando em tela cheia, trabalhando, não tenho a sensação de que está lento ou sem resposta.</p>
<h2>O Software<span class="hx:absolute hx:-mt-20" id="o-software"></span>
    <a href="#o-software" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Se você está no OS X, provavelmente está acostumado com muitas ferramentas. Pagou dinheiro por algumas delas. E trocar de SO sempre é uma dor.</p>
<p>Em resumo, o único software que realmente senti falta no começo foi o Keynote. Mas superei meu preconceito contra o PowerPoint e tenho que admitir que ele faz tudo que preciso agora.</p>
<p>Sempre odiei Pages e Numbers — são ótimos para amadores. Mas nada, nem o LibreOffice, muito menos o Google Docs, substitui o Office. O Google Slides é terrível e o Impress é além de inútil para mim (e é super lento). Sério, o PowerPoint hoje é uma ferramenta muito melhor.</p>
<p>O Office no Mac sempre foi &ldquo;suficiente&rdquo;, felizmente. Mas o Office no Windows é muito superior. Sem dúvida na minha mente. Então um grande benefício de voltar ao Windows 10 é ter a experiência completa do Office.</p>
<p>Se você usa as ferramentas da linha Pro, vai sentir falta do Final Cut Pro. Se é músico profissional, vai sentir falta do Logic Pro. Não há nada como o GarageBand para músicos hobbyistas. Não há nada a fazer aqui. E mesmo tendo hardware melhor no PC, a Apple customiza o Final Cut para render excepcionalmente melhor no AMD Radeon Pro. Então os tempos de exportação do Final Cut ainda são superiores aos do Adobe Premiere. O Motion 5 ainda é mais fácil e responsivo que o After Effects.</p>
<p>Dito isso, a margem não é enorme. A Adobe Creative Suite é muito forte, e a menos que você seja um one-trick pony, qualquer profissional consegue migrar para a Adobe e fazer o trabalho.</p>
<p>Em termos de desenvolvimento de software, a menos que você seja um one-trick pony do .NET, vai querer toda a parafernália open source. O WSL deveria fornecer isso — no futuro. Agora mesmo, sua melhor aposta é rodar o Virtualbox e você não vai se arrepender.</p>
<p>Sim, existem pequenos softwares exclusivos como 1Password, Tweetbot, Alfred. Não sinto falta de nenhum deles. Especialmente porque meu último iPhone foi o 4, lá em 2010. Depois migrei para Android com o Galaxy S4 e também nunca olhei para trás. Estou usando um S8 e prestes a receber meu Pixel 2, então estou bem em termos de cliente de Twitter ou gerenciamento de senhas (uso o LastPass e, embora não seja perfeito, resolve).</p>
<p>Ou existe um substituto nativo bom o suficiente para desktop ou mobile, ou existe um serviço Web. Posso me sentir desconfortável com a mudança, mas na prática não há nada no macOS que me impeça de trocar. Mesmo que você tenha comprado músicas ou filmes no iTunes, existe iTunes para Windows.</p>
<blockquote>
  <p><em>&ldquo;Mas espera, o Windows Update vai te enlouquecer!&rdquo;</em></p>

</blockquote>
<p>Achei o mesmo. A Microsoft finalmente resolveu isso. Ainda existe, você ainda precisa reiniciar. Mas não é nem de longe tão irritante quanto era antes. A maioria das atualizações roda em segundo plano e você nem vai notar. E há várias opções como <a href="https://support.microsoft.com/en-us/help/4028233/windows-10-schedule-or-pause-updates"target="_blank" rel="noopener">agendar</a> para rodar apenas à noite quando você não está trabalhando.</p>
<blockquote>
  <p><em>&ldquo;E os problemas de segurança e vírus!?&rdquo;</em></p>

</blockquote>
<p>Sim, recomendo fortemente não navegar na Deep Web numa máquina Windows, você vai ser comprometido. Nem com um browser Tor. Vai ser comprometido.</p>
<p>Também recomendo usar o BitLocker (disponível apenas no Windows 10 Pro) para criptografar sua partição. E fazer backup em HDs externos com a maior frequência possível. Nada te protege melhor do que um backup frio prontamente disponível.</p>
<p>E sim, instale alguma solução de terceiros como o <a href="https://www.avast.com/index"target="_blank" rel="noopener">Avast antivírus</a>. Tenha comportamento saudável de navegação e evite sites duvidosos. Você sabe do que estou falando. Vai ser comprometido.</p>
<p>Se necessário, instale uma distribuição Linux segura dentro do Virtualbox e abra o Tor de lá.</p>
<blockquote>
  <p><em>&ldquo;E a bagunça que é o Registro!?&rdquo;</em></p>

</blockquote>
<p>Ainda existe. Se você nunca experimentou, o Registro é o equivalente Windows do &ldquo;/etc&rdquo; nas distribuições Linux. É um banco de dados binário. Fica corrompido. Fica com entradas sujas.</p>
<p>Mas minha recomendação é: esqueça-o. Se você ficar pensando e mexendo nele, vai corromper o sistema. Não tente limpá-lo (nunca, jamais use algo como o CCleaner).</p>
<p>O próprio Windows agora tem snapshots automáticos de restauração do sistema toda vez que algo importante acontece. E é bastante confiável. Chegam ao ponto de duplicar o diretório atual &ldquo;C:\Windows&rdquo; em um &ldquo;C:\Windows.old&rdquo; quando há uma grande atualização do Windows, só por precaução. Se atiraram no próprio pé tantas vezes que finalmente aprenderam a ter várias camadas de opções de recuperação.</p>
<p>Hoje você pode até baixar a <a href="https://www.microsoft.com/en-us/software-download/windows10"target="_blank" rel="noopener">ferramenta de Criação de Mídia</a> diretamente do site da Windows. Não precisa nem se cadastrar em lugar nenhum. E a licença do Windows vem no firmware (BIOS) da máquina. Não precisa nem lembrar onde está sua chave de ativação do produto. Ativa automaticamente e como cada máquina já vem com uma licença, o processo é transparente. E a maioria dos fabricantes tem atualizações automáticas para drivers e firmware.</p>
<p>Então você deve ter uma experiência razoavelmente tranquila, aconteça o que acontecer.</p>
<blockquote>
  <p><em>&ldquo;Mas o Windows não é open source!&rdquo;</em></p>

</blockquote>
<p>O OS X também não. E essa é uma vantagem do Linux. Então, se for obrigatório, use apenas Linux nativamente. O ponto da discussão é encontrar uma alternativa ao Mac. Então estamos alinhados.</p>
<h2>O Efeito Ruby on Rails e os Hipsters<span class="hx:absolute hx:-mt-20" id="o-efeito-ruby-on-rails-e-os-hipsters"></span>
    <a href="#o-efeito-ruby-on-rails-e-os-hipsters" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Sendo honesto: no mundo do desenvolvimento de software, migramos para o Mac principalmente por causa do Rails e do Textmate 2. Tínhamos acesso a algumas ferramentas open source embutidas, tínhamos GCC para compilar o resto. O Windows XP estava bem além da validade. O Windows Vista foi uma experiência horrível. Os fabricantes de hardware para PC nem estavam tentando, e a Apple lançava hardware bom e boa experiência o tempo todo.</p>
<p>Os desenvolvedores migraram em massa após a transição de PowerPC para Intel em 2005. Meu primeiro Mac foi um Mac Mini G4 com OS X 10.4 Tiger. Depois comprei o primeiro MacBook branco Intel e nunca olhei para trás.</p>
<p>As ferramentas de software no Windows eram risíveis. O Visual Studio .NET era terrível. IDEs baseadas em Eclipse eram terríveis. Não tínhamos PowerShell ainda. E definitivamente nunca tivemos nada como o WSL para linha de comando. Você podia instalar o Cygwin, mas era uma experiência sofrível.</p>
<p>E rodar Linux como SO principal também era terrível. O Wine ainda é terrível, apesar de seus melhores esforços. Infelizmente, as GPUs da NVIDIA e AMD só rodam no melhor de sua capacidade no Windows. E Linux nunca foi realmente bom para criação de conteúdo. Não é nem questão de aprender um novo fluxo de trabalho — as ferramentas são medíocres. Precisam fazer engenharia reversa de tudo, e isso leva tempo. E na velocidade das redes sociais, não temos tempo suficiente, então precisamos aceitar compromissos.</p>
<p>O ecossistema Windows parou de fingir e finalmente abraçou tudo que o ecossistema open source e da Apple construiu. Agora todos nos beneficiamos.</p>
<p>A propósito, se você gosta do iTerm 2, vai adorar instalar o <a href="https://gnunn1.github.io/tilix-web/"target="_blank" rel="noopener">Tilix para Linux</a>, que é muito similar.</p>
<h2>Com o Passar do Tempo<span class="hx:absolute hx:-mt-20" id="com-o-passar-do-tempo"></span>
    <a href="#com-o-passar-do-tempo" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Acompanho a evolução da linha Surface ao longo dos anos. No começo, era muito cético. É muito fácil lançar um produto gimmick e descontinuá-lo. Confio em empresas que continuam evoluindo seus produtos ao longo dos anos. Não só um ecossistema se forma em torno deles, como você tem tempo para montar serviços de suporte, peças disponíveis nas lojas oficiais e no mercado secundário. Depois de todos esses anos, a Microsoft merece ser chamada de fabricante de hardware.</p>
<p>É a Microsoft finalmente cumprindo o que Alan Kay disse uma vez:</p>
<blockquote>
  <p><em>&ldquo;Pessoas que são realmente sérias sobre software deveriam fazer seu próprio hardware.&rdquo;</em></p>

</blockquote>
<p>Só falharam de verdade no mercado de smartphones, onde a competição é muito mais difícil e as margens são super baixas por causa disso. Mas acertaram no mercado de tablets, no desktop, no notebook, nos games, nos servidores (com seus próprios serviços Azure). Então agora acredito que eles realmente <strong>entendem</strong> as necessidades específicas de todas essas áreas, e isso aparece no software. Têm um entendimento muito superior de cada mercado — exceto smartphones — em relação à Apple. Finalmente têm skin no jogo de verdade.</p>
<p>Porque agora a Microsoft fabrica seu próprio hardware e fez um negócio disso, há um incentivo real dentro das equipes da empresa para um ciclo de feedback positivo que resulta em mais refinamentos no código do Windows.</p>
<p>Ficaram tentando e falhando em soluções touch desde o início dos anos 2000. Agora a Caneta não é mais um gimmick, é um produto real, com qualidades reais e casos de uso reais.</p>
<p>Também mantiveram sua visão de se dar bem com o Open Source. Ninguém pode razoavelmente esperar que a Microsoft vire totalmente open source. Mas aparece. São os segundos apenas para o Google no GitHub em termos de contribuições open source. Adquiriram a Xamarin e sua estratégia de .NET Core está em andamento e forte. O próprio Visual Studio recebeu tratamento open source. Ainda há um longo caminho, mas é preciso reconhecer os passos gigantescos.</p>
<p>O que é muito mais do que podemos dizer sobre a Apple, onde os coitados do <a href="https://github.com/Homebrew/homebrew-core/issues/14418"target="_blank" rel="noopener">Homebrew sofrem</a> a cada atualização do OS X.</p>
<p>A tentativa do Surface RT e do Windows Mobile até possibilitou que o Windows fosse finalmente compilado para rodar em processadores ARM. É um bom sinal para o futuro. Me lembra quando o OS X foi compilado pela primeira vez para rodar em processadores Intel (antes rodava em PowerPC) em 2005.</p>
<p>E o MacBook? Ganhou uma touch bar gimmick. A Apple está realmente desconectada da realidade.</p>
<h2>Por Que Saí do Ecossistema Apple?<span class="hx:absolute hx:-mt-20" id="por-que-saí-do-ecossistema-apple"></span>
    <a href="#por-que-sa%c3%ad-do-ecossistema-apple" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O foco da Apple não é no Mac. Pior: o Mac está rapidamente se tornando abandonware, apesar dos comunicados de relações públicas.</p>
<p>São claramente uma empresa de iPhone, com um negócio paralelo hobbyista que fabrica Macs e MacBooks, que existem principalmente para servir como toolchain de desenvolvimento de apps para iPhone. Esse é o modelo de negócios.</p>
<p>Você viu o último anúncio deles para o iPad?</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/sQB2NjhJHvY"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Sim, é super fofo e eu curto.</p>
<p>Mas a mensagem é cristalina: a visão é para as pessoas usarem apenas iPhones e iPads. Não existe tal coisa como um &ldquo;computador&rdquo;.</p>
<p>São a empresa de tecnologia mais valiosa no momento. Mas desde o ano passado, não têm mais nem uma equipe dedicada ao OS X. O que isso diz?</p>
<p>A linha iOS é um &ldquo;monopólio&rdquo; dentro da linha Apple. O Mac não consegue competir. O próprio Steve Jobs <a href="https://www.youtube.com/watch?v=ZBma82g3Uag"target="_blank" rel="noopener">alertou</a> sobre o que acontece com os monopólios.</p>
<p>Estamos começando a ouvir a mesma história por toda a indústria:</p>
<ul>
<li><a href="http://cdm.link/2016/09/apples-relationship-pro-music-needs-mending/"target="_blank" rel="noopener">Apple&rsquo;s relationship with pro music needs some mending</a> - Set, 26, 2016</li>
<li><a href="https://www.bloomberg.com/news/articles/2016-12-20/how-apple-alienated-mac-loyalists"target="_blank" rel="noopener">How Apple Alienated Mac Loyalists</a> - Dez, 20, 2016</li>
<li><a href="https://www.theverge.com/2016/12/21/14037686/apple-macbook-macos-focus-mobile-features-ios"target="_blank" rel="noopener">macOS is becoming legacy software</a> - Dez, 21, 2016</li>
<li><a href="https://www.stuckincustoms.com/2017/02/10/switching-from-mac-to-windows/"target="_blank" rel="noopener">Apple Is Dead To Me… I&rsquo;m Switching To Windows!</a> - Fev, 10, 2017</li>
<li><a href="https://char.gd/blog/2017/why-i-left-mac-for-windows-apple-has-given-up"target="_blank" rel="noopener">Why I left Mac for Windows: Apple has given up</a> - Mar, 5, 2017</li>
</ul>
<p>A Microsoft jogou bem suas cartas. Levou quase 15 anos. Mas valeu muito a pena. A Apple realmente alienou os leais, os que costumavam &ldquo;Think Different&rdquo;.</p>
<p>A Apple é &ldquo;vítima&rdquo; do <a href="https://www.amazon.com/Innovators-Dilemma-Revolutionary-Change-Business/dp/0062060244"target="_blank" rel="noopener">&ldquo;Dilema do Inovador&rdquo;</a> de Clayton Christensen. Se ainda tivessem visão, poderiam se estender e manter. Mas ao invés disso, escolheram apostar tudo em uma única linha de produtos.</p>
<p>A Microsoft parece ter lido a <a href="https://www.amazon.com/Innovators-Solution-Creating-Sustaining-Successful/dp/1422196577/ref=pd_sim_14_4?_encoding=UTF8&amp;psc=1&amp;refRID=CC6NWGVZMEWTTDETMZ8W"target="_blank" rel="noopener">&ldquo;Solução do Inovador: Criando e Sustentando o Crescimento de Sucesso&rdquo;</a> de Clayton.</p>
<p>Quando o iPod estava no auge, a Microsoft havia &ldquo;perdido&rdquo;. Estavam fora do jogo. Era deprimente de ver. Steve Ballmer foi um CEO vergonhoso. O Windows Vista foi um SO vergonhoso. O Zune falhou em capturar a aura do iPod. O Windows Mobile era uma bagunça. E o Sharepoint&hellip; ah, o Sharepoint. Chegaram a comemorar quando o jQuery foi adicionado ao ASP.NET! Falar em tarde demais.</p>
<p>E a Amazon — uma loja de varejo — lançou com sucesso a melhor infraestrutura do mundo e se tornou sinônimo de &ldquo;Nuvem&rdquo;, enquanto a Microsoft ainda estava tentando entender o que era Linux.</p>
<p>Falha após falha, em vez de defender sua posição baixa, finalmente decidiram se erguer e seguir em frente um passo de cada vez. Refinar. Evoluir. Sustentar.</p>
<p>Agora, o Windows 10 recapturou a aura do XP no seu melhor. Está fazendo atualizações incrementais e sólidas. Primeiro a Anniversary Edition, depois a Creators Update e finalmente a mais recente Fall Creators Update. Todas atualizações sólidas.</p>
<p>A linha Surface está indo forte como a melhor referência de design industrial e funcionalidades em desktops, notebooks e acessórios. Sério, a Apple ainda vende aquele terrível <a href="https://www.apple.com/shop/product/MLA02LL/A/magic-mouse-2"target="_blank" rel="noopener">Magic Mouse 2</a> escorregadio e difícil de segurar, mas a &ldquo;mágica&rdquo; é que alguém de fato compra. A Microsoft tem o <a href="http://amzn.to/2ztHZVv"target="_blank" rel="noopener">Arc Touch</a> e o <a href="http://amzn.to/2zu8p9o"target="_blank" rel="noopener">Precision Mouse</a>, dois dos melhores já fabricados.</p>
<p>Profissionais criativos, desenvolvedores de software — todos migramos em massa para o OS X quando era a &ldquo;Coisa Diferente&rdquo; da campanha &ldquo;Think Different&rdquo;. Ajudamos a evangelizar. Ajudamos a construir ferramentas. Ajudamos a construir serviços. Escrevemos toneladas de <a href="http://www.akitaonrails.com/2012/04/20/off-topic-comprei-meu-primeiro-mac-e-agora-edicao-2012"target="_blank" rel="noopener">posts</a> e documentação para ajudar.</p>
<p>Steve Jobs morreu e a Apple morreu com ele. Basicamente não fizeram nada novo desde então, e seus produtos antes bem-sucedidos foram deixados para decair e morrer. O que resta é o efeito halo, a inércia, e o crescente apetite por ordenhar a mesma vaca indefinidamente, abandonando todo o P&amp;D.</p>
<h2>A Apple Não Liga. Por Que Eu Deveria?<span class="hx:absolute hx:-mt-20" id="a-apple-não-liga-por-que-eu-deveria"></span>
    <a href="#a-apple-n%c3%a3o-liga-por-que-eu-deveria" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A Microsoft jogou com inteligência, continuou corrigindo e evoluindo, ano após ano. Perdeu a geração dos anos 90. Recuperou a geração dos anos 2010. E começaram cedo, atraindo atenção pelo Xbox até chegar ao Windows.</p>
<p>Sério, o Dashboard do XBox é melhor do que o do PS4. Prefiro muito mais.</p>
<p>E agora estão em boa posição. Os jogadores estão invertidos. O &ldquo;Think Different&rdquo; agora se refere ao Windows 10 e ao hardware PC. A Intel está conservadora. A NVIDIA fabrica as melhores GPUs. Há muitas ótimas opções que não estão disponíveis no Mac.</p>
<p>A transição de 32 para 64 bits e as necessidades do XBox até ajudaram a Microsoft a repensar como isolar e empacotar seu software. Mesmo que a Windows Store ainda seja uma piada de mau gosto neste ponto.</p>
<p>E Bill Gates estava absolutamente certo em meados dos anos 90: o browser tornaria o monopólio do Windows obsoleto. E tornou. Do lado bom, você tem os mesmos Chrome e Firefox disponíveis no OS X, Windows 10 e qualquer distribuição Linux. Isso significa acesso imediato a tudo que a maioria das pessoas precisa: Gmail, Google Docs, Office 365, Dropbox, LastPass, Spotify, Slack, Discord, Twitter, Netflix, HBO, Hulu, etc.</p>
<p>Odeio wrappers de desktop baseados em Javascript como a praga. O Electron é pesado demais. Mas o que posso fazer? Pelo menos hardware poderoso e RAM estão baratos hoje em dia, e podemos nos dar ao luxo de abas de browser que consomem 100 MB cada.</p>
<p>O browser é o novo SO para a maioria das pessoas. Muita gente se vira com Chromebooks! Todo o resto está nos celulares, não no desktop. Então ferramentas pesadas são necessárias. Ferramentas leves você já carrega no bolso.</p>
<p>O ecossistema Apple ainda não está morto. A Apple ainda tem tempo de corrigir a situação. Tenho esperado pelos últimos 3 anos, mas ainda zero sinais de melhora. Meu primeiro artigo sobre a troca foi <a href="http://www.akitaonrails.com/2015/11/10/situacao-brasil-no-macs-for-the-rest-of-us"target="_blank" rel="noopener">publicado em 10 de novembro de 2015</a>.</p>
<p>Diferente de outros artigos sobre troca de plataforma, não estou dizendo isso de forma leviana. Já fiz a troca, nos últimos 2 anos.</p>
<p>Como digo em muitos dos meus posts e palestras: não sou definido pelas minhas ferramentas. Não carrego bandeiras. Não sou leal a ninguém por padrão. Nunca fui pago pela Apple para defendê-la. E não sou pago pela Microsoft para dizer coisas boas sobre ela. Apenas analiso os fatos e aponto o melhor caminho a seguir.</p>
<p>E os fatos me dizem que o macOS chegou ao fim. Foi uma boa viagem. Adeus ao Mac e obrigado pelos peixes.</p>
]]></content:encoded><category>apple</category><category>microsoft</category><category>hardware</category></item><item><title>Do MacBook Pro para o Dell XPS: Arch Linux para Usuários Criativos</title><link>https://akitaonrails.github.io/2017/01/31/do-macbook-pro-para-o-dell-xps-arch-linux-para-usuarios-criativos/</link><guid isPermaLink="true">https://akitaonrails.github.io/2017/01/31/do-macbook-pro-para-o-dell-xps-arch-linux-para-usuarios-criativos/</guid><pubDate>Tue, 31 Jan 2017 18:26:00 -0200</pubDate><description>&lt;p&gt;Como venho relatando em posts anteriores, estou migrando para Linux em tempo integral. Aqui quero mostrar como configurar o Arch Linux para deixá-lo adequado a Usuários Criativos &lt;strong&gt;Pro&lt;/strong&gt;, onde o acesso à GPU secundária é fundamental.&lt;/p&gt;
&lt;p&gt;Se você é um Usuário Criativo Pro, não dá para rodar Final Cut Pro X (com Motion e Compressor), Logic Pro, Photoshop da Adobe e afins. Então você vai precisar mudar seu fluxo de trabalho se quiser entrar no ecossistema Linux. Felizmente, para muitos fluxos os aplicativos Linux amadureceram bem e dá para trabalhar sem precisar se contentar com software de baixa qualidade ou gambiarra.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Como venho relatando em posts anteriores, estou migrando para Linux em tempo integral. Aqui quero mostrar como configurar o Arch Linux para deixá-lo adequado a Usuários Criativos <strong>Pro</strong>, onde o acesso à GPU secundária é fundamental.</p>
<p>Se você é um Usuário Criativo Pro, não dá para rodar Final Cut Pro X (com Motion e Compressor), Logic Pro, Photoshop da Adobe e afins. Então você vai precisar mudar seu fluxo de trabalho se quiser entrar no ecossistema Linux. Felizmente, para muitos fluxos os aplicativos Linux amadureceram bem e dá para trabalhar sem precisar se contentar com software de baixa qualidade ou gambiarra.</p>
<p>Desenvolvedores de software raramente precisam de mais do que a placa Intel integrada barata, a menos que queiram instalar o <a href="https://wiki.archlinux.org/index.php/Steam/Wine"target="_blank" rel="noopener">Steam via Wine</a> para jogar títulos pesados.</p>
<p>Depois de muita pesquisa (leia-se: <a href="https://www.youtube.com/results?search_query=Dell&#43;XPS&#43;15&#43;9550&#43;review"target="_blank" rel="noopener">YouTube!</a>) fui com o Dell XPS 15&quot; (modelo 9550). É uma máquina com quase um ano de vida, arquitetura SkyLake, usando o NVIDIA Optimus Híbrido Intel + GTX960M.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/612/20170127_133009.jpg" alt="Dell XPS 15&#34; 9550"  loading="lazy" /></p>
<p>Até hoje nada supera a coesão entre software e hardware da Apple. Isso não pode ser subestimado. O mundo PC/Windows melhorou bastante, mas ainda é assombrado por BIOS instável, drivers instáveis etc. No Linux, é ainda pior.</p>
<p>Aqui vai o primeiro <strong>protip</strong>: evite modelos super novos. A maioria não tem drivers estáveis nem para Windows 10, quanto mais para Linux. Deixe o pessoal do Windows sofrer os primeiros meses e dê tempo à Dell, à <a href="http://windowsreport.com/nvidia-driver-crash-windows-10/"target="_blank" rel="noopener">NVIDIA</a> e à Intel para corrigir o caos com firmware de BIOS e drivers mais estáveis.</p>
<p>Se você realmente quiser comprar um dos modelos Kaby Lake de 2017 que acabaram de sair, está numa roleta russa. Até os primeiros MacBooks costumam <a href="http://www.digitaltrends.com/computing/apple-releases-macos-sierra-10123-update/"target="_blank" rel="noopener">dar problema</a>. Regra geral: não compre no dia do lançamento, espere pelo menos 3 meses. Você foi avisado.</p>
<p>Dentre as máquinas de início de 2016 que a maioria das distros Linux suporta razoavelmente bem, as séries <a href="http://www.anandtech.com/show/10116/the-dell-xps-15-9550-review"target="_blank" rel="noopener">Dell XPS</a>, <a href="http://www.anandtech.com/show/10697/the-lenovo-thinkpad-x1-yoga-review"target="_blank" rel="noopener">Lenovo Thinkpad X1 Yoga</a> e possivelmente <a href="http://www.digitaltrends.com/computing/dell-xps-15-vs-asus-zenbook-pro-ux501-battle-of-the-plus-sized-premiums/"target="_blank" rel="noopener">Asus Zenbook Pro</a> e <a href="http://laptopmedia.com/review/hp-probook-450-g3-455-g3-review-what-a-budget-business-notebook-should-look-like/"target="_blank" rel="noopener">HP ProBook</a> estão bem.</p>
<p>Mas na maioria das categorias, a série XPS leva vantagem. A Dell fez um trabalho muito bom dessa vez.</p>
<p>O teclado, como na maioria dos PCs, é mediano: plástico, um pouco bamboleante, com curso aceitável mas clique duro e sem resistência suficiente. Para 99% das pessoas é bom o suficiente, mas não é o ideal para quem digita muito rápido.</p>
<p>O touchpad é um dos melhores em qualquer notebook PC, mas vale lembrar que a maioria dos touchpads de PC é vergonhosamente ruim, especialmente com gestos mais complexos do que rolar com dois dedos. Essa continua sendo uma área em que o Mac é imbatível. Dito isso, o da Dell é funcional e deve dar conta do recado, embora a rejeição de palma falhe aqui e ali para te irritar de vez em quando.</p>
<p>O monitor é outra história: o deslumbrante display 4K IPS do XPS 15 é excelente, superando de longe os Retina Displays do MacBook. O SSD Samsung PCIe NVMe M.2 também é o melhor da categoria. A carcaça de alumínio é simples mas bem usinada, e o acabamento em fibra de carbono é um bônus bem-vindo que faz da máquina algo que você genuinamente aprecia carregar.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/613/20170124_211855.jpg" alt="Dell XPS Display"  loading="lazy" /></p>
<p>Se você não quer mexer muito na configuração de hardware, a aposta mais segura costuma ser o Ubuntu, e mesmo assim <a href="http://web.archive.org/web/20160707232552/http://ubuntuforums.org:80/showthread.php?t=2317843"target="_blank" rel="noopener">não vai ser perfeito</a>.</p>
<p>Especialmente com displays HiDPI (acima de Full-HD), o Linux ainda está atrás. GNOME e KDE até suportam, mas outros ambientes desktop têm resultados mistos, e aplicativos mais antigos ainda não se adaptaram direito. Em distros LTS com pacotes velhos, você vai encontrar aplicativos com HiDPI errado, como o <a href="https://bugs.documentfoundation.org/show_bug.cgi?id=99508"target="_blank" rel="noopener">Libreoffice</a> e o <a href="https://community.spotify.com/t5/Desktop-Linux-Windows-Web-Player/Linux-client-barely-usable-on-HiDPI-displays/td-p/1067272"target="_blank" rel="noopener">Spotify</a>.</p>
<p>E se você for como eu, usando múltiplos monitores com DPIs diferentes, pode esquecer. Ou usa o notebook com a tampa fechada, aí só tem um monitor externo para se preocupar, ou o texto fica minúsculo no monitor HiDPI principal para o DPI ficar certo no segundo monitor externo.</p>
<p>Uma saída é configurar o display 4K para escalar para Full-HD (1080p). Mas aí fica a pergunta: qual é o sentido de ter um display 4K se você não consegue usá-lo direito? Então não compre o 4K sem entender isso.</p>
<p>MacOS e Windows lidam com essa situação muito melhor. No MacOS nunca tive nenhum problema de HiDPI. Nenhum. A Apple foi muito mais eficaz em empurrar um padrão mais alto do que o resto da indústria, e essa coesão, sem precisar fuçar drivers e configurações, tem um valor enorme.</p>
<p>Com Mac, você liga e usa. Com Windows, provavelmente vai ficar bem, a menos que apareça algum problema de driver. Com Linux, espere um volume razoável de ajustes para colocar o básico em ordem.</p>
<p>Notebooks PC novos também estão vindo com configurações esquisitas que fazem sentido no Windows, mas que dão trabalho para as distros Linux. Toda vez você começa desativando coisas no BIOS como Secure Boot, mudando para AHCI, etc. Então vamos direto ao ponto.</p>
<h3>Configuração do BIOS<span class="hx:absolute hx:-mt-20" id="configuração-do-bios"></span>
    <a href="#configura%c3%a7%c3%a3o-do-bios" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A primeira coisa a fazer é alterar as configurações do BIOS. Pressione F2 na tela do logo Dell para entrar no setup e faça as seguintes mudanças:</p>
<ul>
<li>General - Advanced Boot Options - Enable Legacy Option ROMs</li>
<li>General - Boot Sequence - Legacy (o padrão é UEFI)</li>
<li>System Configuration - SATA Operation - AHCI (o padrão é RAID On)</li>
<li>System Configuration - Touchscreen (desabilite, pois é praticamente desnecessário e consome mais bateria)</li>
<li>Security - Secure Boot - Secure Boot Enable - Disabled</li>
<li>POST Behavior - Fastboot - Through (o padrão é minimal)</li>
</ul>
<p>Ao fazer essas mudanças, o Windows 10 pré-instalado não vai mais iniciar, então certifique-se de que não precisa dele antes de prosseguir.</p>
<h3>Ajustes no Kernel<span class="hx:absolute hx:-mt-20" id="ajustes-no-kernel"></span>
    <a href="#ajustes-no-kernel" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Siga a página do <a href="https://wiki.archlinux.org/title/Dell_XPS_15_%289550%29"target="_blank" rel="noopener">Wiki do Dell XPS (9550)</a>.</p>
<p>O display 4K pode apresentar flickering, e para evitar isso edite o arquivo de configuração do Grub <code>/boot/grub/grub.cfg</code> e adicione os seguintes flags à linha existente:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>GRUB_CMDLINE_LINUX_DEFAULT=&#34;... i915.edp_vswing=2 i915.preliminary_hw_support=1 intel_idle.max_cstate=1 acpi_backlight=vendor acpi_osi=Linux&#34;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Essa linha já existe com alguns flags. Não apague, apenas adicione os novos, e não se esqueça de rodar em seguida:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo grub-mkconfig -o /boot/grub/grub.cfg</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>No mais, tudo deve funcionar bem, mas por precaução instalei também os pacotes <a href="https://wiki.archlinux.org/index.php/Powertop"target="_blank" rel="noopener">Powertop</a> e acpid:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo pacman -S powertop acpid</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Fico feliz em reportar que consigo fechar a tampa do notebook e o sistema suspende corretamente. Ao abrir, ele volta do sleep sem problemas, economizando bateria e me poupando de reiniciar todo dia.</p>
<h3>Distros Arch: Manjaro ao resgate<span class="hx:absolute hx:-mt-20" id="distros-arch-manjaro-ao-resgate"></span>
    <a href="#distros-arch-manjaro-ao-resgate" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Estou me tornando um entusiasta do Arch, mas configurá-lo para funcionar num notebook moderno dá um trabalho absurdo. Não recomendo tentar se você estiver com pressa. Testei o <a href="https://arch-anywhere.org/"target="_blank" rel="noopener">Arch Anywhere</a>, mas ele nem consegue passar pelo particionamento do disco (não gosta da configuração de SSD ou SATA). Testei o <a href="http://web.archive.org/web/20170205034235/https://antergos.com/"target="_blank" rel="noopener">Antergos</a>, mas por algum motivo as Contas Online do Gnome não funcionaram lá, mesmo reinstalando. No final fui com o <a href="https://manjaro.org/"target="_blank" rel="noopener">Manjaro</a>, que instalou e funcionou sem grandes problemas.</p>
<p>Existem várias distros baseadas em Arch. Arch Anywhere e Antergos são mais &ldquo;instaladores&rdquo; do Arch: os repositórios principais ainda são o Arch vanilla, e eles tentam tornar o processo de instalação mais fácil do que você ter de se virar num shell de linha de comando cru.</p>
<p>O Manjaro é mais uma distro independente. As fontes principais apontam para o Manjaro primeiro, então eles testam os pacotes mais recentes e os seguram por um tempo antes de liberar, evitando que pacotes problemáticos quebrem seu sistema com frequência. Mas você ainda tem acesso direto aos pacotes AUR. O grande diferencial é um instalador <strong>muito</strong> melhor, com particionamento automático mais sofisticado do que o Arch Anywhere, e o próprio software de detecção de hardware <a href="https://wiki.manjaro.org/index.php?title=Manjaro_Hardware_Detection_Overview"target="_blank" rel="noopener">MHWD</a>.</p>
<p>No geral funcionou bem, embora eu ainda tenha precisado ajustar a configuração gráfica, pois por padrão ele opta pelos drivers open source Nouveau. Confie em mim: vá para os binários proprietários.</p>
<p>Se você também é desenvolvedor de software, vai querer ler meu <a href="http://www.akitaonrails.com/2017/01/10/arch-linux-a-melhor-distro-de-todas"target="_blank" rel="noopener">post anterior sobre Arch</a>.</p>
<h3>Gráficos Híbridos Optimus<span class="hx:absolute hx:-mt-20" id="gráficos-híbridos-optimus"></span>
    <a href="#gr%c3%a1ficos-h%c3%adbridos-optimus" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>O Dell XPS modelo 9550 usa a arquitetura Híbrida <strong>Optimus</strong>. Os drivers <strong>Prime</strong> são para GPUs NVIDIA standalone. A maioria dos notebooks funciona com a placa Intel integrada como única e principal (especialmente ultrabooks leves), e os modelos mais &ldquo;Pro&rdquo; conectam isso a uma NVIDIA GTX 960M secundária.</p>
<p>Se você tem apenas uma placa Intel simples, a maioria das distros vai fazer a coisa certa automaticamente e instalar os drivers e configurações corretas.</p>
<p>Agora, se você tem uma máquina de alta performance como este XPS 9550 ou 9560 (Kaby Lake), vai precisar de mais configuração. Primeiro, entenda a terminologia:</p>
<ul>
<li>Você precisa instalar o Bumblebee. É um daemon que habilita o acesso à GPU secundária. Só instalar o Bumblebee já resolve a maioria dos problemas.</li>
<li>Depois instale o Primusrun, que é um back-end para o Bumblebee usado para rodar programas como o Steam de forma que tenham acesso à GPU secundária.</li>
<li>Às vezes você vai ver referências ao Optirun, que hoje em dia parece usar o Primusrun por padrão (caso contrário, usava um framebuffer X secundário, adicionando overhead extra).</li>
</ul>
<p>Com tudo instalado, geralmente basta fazer:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>primusrun kdenlive</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Por exemplo, para carregar o editor de vídeo Kdenlive usando OpenGL pela GPU Nvidia. Ou para rodar o <a href="http://web.archive.org/web/20170220054700/https://forum.manjaro.org/t/newbie-questions-about-hybrid-nvidia-and-intel-gpu-drives-tutorial/2974/26"target="_blank" rel="noopener">Steam via Wine</a>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>primusrun wine ~/.wine/drive_c/Program\ Files\ (x86)/Steam/Steam.exe</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Como mencionei, o Manjaro provavelmente vai instalar o driver Nouveau, que é open source. Você deve instalar os binários proprietários assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo mhwd -a pci nonfree 0300
sudo mhwd -r pci video-hybrid-intel-nouveau-bumblebee
sudo mhwd -i pci video-hybrid-intel-nvidia-bumblebee</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Lembrando que estou falando do XPS 9550 com configuração Optimus Intel-Nvidia. Leia a página <a href="http://web.archive.org/web/20170517195417/https://wiki.manjaro.org/index.php/Configure_Graphics_Cards"target="_blank" rel="noopener">Configuring Graphics</a> do Manjaro sobre o assunto.</p>
<p>Aqui me deparei com um problema estranho. Estou usando o kernel <strong>Linux 4.9</strong>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>$ uname -a
Linux arch42 4.9.6-1-MANJARO #1 SMP PREEMPT Thu Jan 26 12:29:20 UTC 2017 x86_64 GNU/Linux</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Teoricamente o pacote <code>core/linux49 4.9.6-1</code>. Mas por algum motivo o comando <code>mhwd -i</code> estava instalando os drivers <code>linux44-nvidia</code>.</p>
<p>Os módulos da GPU Nvidia nunca eram carregados até eu removê-los manualmente:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo pacman -R linux44-nvidia</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E então instalar a versão correta manualmente:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo pacman -S linux49-nvidia</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Por precaução, desinstalei o pacote <code>linux44</code> e todos os outros pacotes <code>linux44-*</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo pacman -Ss linux44 | grep installed
# sudo pacman -R linux44-(nome do pacote)</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Agora tenho isso:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>$ sudo pacman -Ss linux4 | grep installed
core/linux49 4.9.6-1 [installed]
extra/linux49-bbswitch 0.8-6 (linux49-extramodules) [installed]
extra/linux49-ndiswrapper 1.61-4 (linux49-extramodules) [installed]
extra/linux49-nvidia 1:375.26-6 (linux49-extramodules) [installed]</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>No <code>/etc/bumblebee/bumblebee.conf</code> confirmo que está carregando explicitamente o driver <code>nvidia</code> correto (o <code>linux49-nvidia</code> mencionado acima). Caso contrário, você precisa editar com <code>sudo vim</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>$ cat /etc/bumblebee/bumblebee.conf | grep Driver
# The Driver used by Bumblebee server. If this value is not set (or empty),
Driver=nvidia</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Ao final, se você abrir o Manjaro Settings Manager, deve ver algo assim:</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/614/Screenshot_from_2017-01-31_18-24-34.png" alt="Settings Manager"  loading="lazy" /></p>
<h3>Edição 3D e Vídeo Profissional<span class="hx:absolute hx:-mt-20" id="edição-3d-e-vídeo-profissional"></span>
    <a href="#edi%c3%a7%c3%a3o-3d-e-v%c3%addeo-profissional" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Para testar esse setup, comecei instalando o <a href="https://wiki.archlinux.org/index.php/Blender"target="_blank" rel="noopener">Blender</a> (uma das melhores ferramentas de edição 3D da indústria). Baixei um modelo 3D e animação gratuitos e tentei renderizar cycles via GPU Compute. Por segurança, instalei também o pacote Cuda:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo pacman -S blender cuda</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Com os drivers corretos instalados, o Blender deve detectá-los e habilitar o uso dos cores CUDA:</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/608/Screenshot_from_2017-01-31_17-04-58.png" alt="CUDA GPU Compute"  loading="lazy" /></p>
<p>Você pode monitorar a placa Nvidia com o comando <code>nvidia-smi</code>, que mostra algo assim:</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/609/Screenshot_from_2017-01-31_16-43-46.png" alt="nvidia-smi monitoring"  loading="lazy" /></p>
<p>Isso cobre a modelagem 3D profissional se você precisar.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/615/Screenshot_from_2017-01-31_17-11-18.png" alt="Blender"  loading="lazy" /></p>
<p>Possivelmente o melhor editor de vídeo disponível para Linux é o <a href="https://kdenlive.org/"target="_blank" rel="noopener">Kdenlive</a>. É o mais próximo que você vai encontrar do Adobe Premiere ou do Apple Final Cut Pro.</p>
<p>A instalação é assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo pacman -S kdenlive ladspa movit sox ffmpeg frei0r-plugins breeze-icons</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E para previews em tempo real mais rápidos, ele pode ser iniciado via Primusrun num terminal assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>$ primusrun kdenlive
OpenGL vendor:  &#34;NVIDIA Corporation&#34;
OpenGL renderer:  &#34;GeForce GTX 960M/PCIe/SSE2&#34;
OpenGL Threaded:  true
OpenGL ARG_SYNC:  true
OpenGL OpenGLES:  false
OpenGL vendor:  &#34;NVIDIA Corporation&#34;
OpenGL renderer:  &#34;GeForce GTX 960M/PCIe/SSE2&#34;
OpenGL Threaded:  true
OpenGL ARG_SYNC:  true
OpenGL OpenGLES:  false</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Se eu iniciar sem o Primusrun, ele detecta primeiro a placa Intel:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>$ kdenlive
OpenGL vendor:  &#34;Intel Open Source Technology Center&#34;
OpenGL renderer:  &#34;Mesa DRI Intel(R) HD Graphics 530 (Skylake GT2) &#34;
OpenGL Threaded:  false
OpenGL ARG_SYNC:  true
OpenGL OpenGLES:  false
OpenGL vendor:  &#34;Intel Open Source Technology Center&#34;
OpenGL renderer:  &#34;Mesa DRI Intel(R) HD Graphics 530 (Skylake GT2) &#34;
OpenGL Threaded:  false
OpenGL ARG_SYNC:  true
OpenGL OpenGLES:  false</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Não tenho certeza absoluta, mas acredito que o Kdenlive usa OpenGL para mostrar previews em tempo real dos efeitos aplicados às faixas de vídeo, e isso provavelmente pode ser redirecionado via primus para a placa Nvidia secundária.</p>
<p>Na verdade, o Kdenlive, assim como seu concorrente OpenShot, usa o <a href="https://www.mltframework.org/"target="_blank" rel="noopener">MLT Multimedia Framework</a>, o motor de edição de vídeo não-linear. Por sua vez, o MLT usa o <a href="https://movit.sesse.net/"target="_blank" rel="noopener">movit</a>, que são filtros de vídeo de alta performance e qualidade para a GPU. O comando de instalação via <code>pacman</code> que mencionei já cuida de instalar esses pacotes opcionais.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/616/Screenshot_from_2017-01-31_18-29-38.png" alt="Kdenlive"  loading="lazy" /></p>
<p>E se você quiser aproveitar a GPU Nvidia até no GIMP, existe um esforço em andamento para portar filtros para usar <a href="https://wiki.gimp.org/wiki/Hacking:Porting_filters_to_GEGL"target="_blank" rel="noopener">GEGL/OpenCL</a>. Você pode habilitar o GEGL iniciando o Gimp pelo terminal assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>GEGL_USE_OPENCL=yes gimp</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Depois, você pode usar os plugins portados pelo menu <code>Tools - GEGL Operation</code>:</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/610/Screenshot_from_2017-01-31_17-49-30.png" alt="GEGL Operation"  loading="lazy" /></p>
<p>E se você é fotógrafo profissional, vai querer instalar o <a href="http://www.darktable.org/"target="_blank" rel="noopener">Darktable</a>, que é o mais próximo que você vai chegar do Apple Aperture ou Adobe Lightroom. Tem uma aparência bem cuidada e você consegue retocar suas fotos adequadamente.</p>
<p>O Darktable detecta automaticamente o driver Nvidia. Não precisa rodar via Primusrun nem passar nenhuma flag especial.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/617/Screenshot_from_2017-01-31_18-31-04.png" alt="Darktable"  loading="lazy" /></p>
<h3>Considerações Finais<span class="hx:absolute hx:-mt-20" id="considerações-finais"></span>
    <a href="#considera%c3%a7%c3%b5es-finais" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Você pode verificar se o aplicativo está usando a GPU monitorando com <code>nvidia-smi</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>watch -n 0.5 nvidia-smi</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Isso mantém o monitoramento da GPU a cada meio segundo. O aplicativo aparece na lista de processos com um PID e você consegue ver o uso de memória (minha GPU tem 2GB de DRAM dedicada), o uso de processamento e a temperatura, que pode chegar perto de 70 graus Celsius renderizando pelo Blender.</p>
<p>Acredito que isso é o máximo que dá para extrair do hardware com aplicativos multimídia de nível profissional. Não sou profissional de Blender, Kdenlive, Darktable ou Gimp, mas é bom saber que posso usá-los para minhas necessidades pontuais. Usuários Pro vão conseguir aproveitar ainda mais essa máquina com essa configuração.</p>
<p>Como disse no começo: se você é realmente um Usuário Pro, sempre em movimento e precisa fazer mudanças rápidas nos seus projetos multimídia on-the-go, provavelmente vai continuar melhor com o stack da Apple, um MacBook Pro com Final Cut Pro. Não esqueça que o Final Cut Pro e os outros softwares Pro da Apple são super otimizados para o hardware Mac, exportando vídeos em velocidades ordens de magnitude maiores do que o Premiere, por exemplo.</p>
<p>Mas você pode ser um Usuário Criativo Pro na indústria de games, desenvolvimento mobile, animação 3D, pós-produção, ou trabalhando num time misto com engenheiros de software. E ter a capacidade de construir seus assets multimídia numa plataforma Linux pode abrir possibilidades interessantes para fluxos de trabalho integrados no futuro.</p>
<p>Mesmo que você seja do mundo Mac ou PC, provavelmente vai querer usar software como o Blender, que é um competidor respeitável ou até complemento de ferramentas premiadas como o Maya.</p>
<p>Então, mesmo que você tenha que enfrentar algumas arestas na instalação e configuração inicial, uma vez feito isso funciona bem.</p>
]]></content:encoded><category>linux</category><category>apple</category><category>hardware</category></item><item><title>Off-Topic: Por que Estamos Todos Migrando para Longe da Apple?</title><link>https://akitaonrails.github.io/2017/01/12/off-topic-por-que-estamos-todos-migrando-para-longe-da-apple/</link><guid isPermaLink="true">https://akitaonrails.github.io/2017/01/12/off-topic-por-que-estamos-todos-migrando-para-longe-da-apple/</guid><pubDate>Thu, 12 Jan 2017 11:37:00 -0200</pubDate><description>&lt;p&gt;&amp;ldquo;Todo mundo que é alguém acompanhou a Apple nas últimas décadas. Ame ou odeie, a única coisa que você não pode fazer é ignorá-la.&amp;rdquo; - esse sempre foi o consenso geral.&lt;/p&gt;
&lt;p&gt;Os profissionais &amp;ldquo;criativos&amp;rdquo; (como se &amp;ldquo;criativo&amp;rdquo; fosse restrito a pintores e ilustradores) sempre foram os seguidores mais fiéis da Apple, e com razão. A plataforma foi o berço de ferramentas essenciais como Photoshop, QuarkXPress, PostScript, PDF e QuickTime. A Apple estabeleceu os padrões da criação de mídia, e qualquer um que era alguém usava essas ferramentas.&lt;/p&gt;</description><content:encoded><![CDATA[<p>&ldquo;Todo mundo que é alguém acompanhou a Apple nas últimas décadas. Ame ou odeie, a única coisa que você não pode fazer é ignorá-la.&rdquo; - esse sempre foi o consenso geral.</p>
<p>Os profissionais &ldquo;criativos&rdquo; (como se &ldquo;criativo&rdquo; fosse restrito a pintores e ilustradores) sempre foram os seguidores mais fiéis da Apple, e com razão. A plataforma foi o berço de ferramentas essenciais como Photoshop, QuarkXPress, PostScript, PDF e QuickTime. A Apple estabeleceu os padrões da criação de mídia, e qualquer um que era alguém usava essas ferramentas.</p>
<p>A Microsoft focava no mercado corporativo, não nos criativos. O Linux ainda engatinhava, e a maioria dos desenvolvedores nem sabia a diferença entre CMYK e RGB. Ficavam satisfeitos em ter um bitmap tosco na tela.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/587/918d80cb21131a7a62e6ccaf71229960.jpg" alt="Old Macintosh"  loading="lazy" /></p>
<p>Tenho uma teoria: achamos que dominávamos a tecnologia no final dos anos 90, que estávamos no topo do mundo. Essa euforia era fruto da Bolha da Internet, que estourou junto com o 11 de setembro. A depressão que se seguiu desperdiçou os próximos 3 a 4 anos enquanto todo mundo tentava descobrir o que fazer a seguir.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/588/1dot.jpg" alt="Dotcom burst"  loading="lazy" /></p>
<p>A Apple teve a sorte de escapar da explosão. Ela já estava no fundo do poço desde 1997. A reorganização do portfólio de hardware e o lançamento do iPod criaram uma bolhinha própria. Steve Jobs havia voltado e trouxe bons desenvolvedores que fizeram do OS X um prazer de usar, não só para criativos, mas também para desenvolvedores.</p>
<p>O processo antitruste contra a Microsoft em 2000, o estouro da Bolha da Internet em 2001, o lançamento do iPod em 2001, a transição do System 9 para o OS X/BSD em 1999, a troca do PowerPC para Intel em 2005, o lançamento do desejadíssimo Titanium PowerBook G4 em 2001. Tudo isso junto deu à Apple uma vantagem enorme. E enquanto todo mundo estava em baixa, a Apple parecia maior do que realmente era.</p>
<p><a href="http://www.economist.com/node/2535519"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/589/Microsoft.gif" alt="Microsoft Antitrust"  loading="lazy" /></a></p>
<p>Aí vieram 2007 e 2008 com um novo impulso: o iPhone, a App Store e a necessidade de usar o Xcode, disponível apenas em computadores Apple. Diferente de ficar preso ao Windows por causa do Visual Studio, usar o Xcode era um motivo a mais para comprar um Mac.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/590/SteveJobsUnveilsiPhone.jpg" alt="iPhone announcement"  loading="lazy" /></p>
<p>As distros Linux ainda sofriam. Até então, estávamos presos ao <a href="https://www.youtube.com/watch?v=RIctzAQOe44"target="_blank" rel="noopener">maldito X11</a>. Se o núcleo de um sistema Linux era moderno, o X11 em cima era o pior dos mundos. A Apple foi esperta o suficiente para não adotá-lo e criou o Quartz do zero, melhorando-o a cada nova versão do OS X. Levou cinco anos para estabilizar direito. Só agora, em 2017, estamos finalmente saindo do X para o Wayland/Weston.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/591/steve-ballmer.jpg" alt="Steve Ballmer"  loading="lazy" /></p>
<p>A Microsoft também sofreu depois que Bill Gates passou as rédeas para Steve Ballmer. A trajetória do XP até o Windows 10 passou pelos desastres do Vista, do Windows 8 e do Windows Mobile, além das inúmeras tentativas de ressuscitar o Internet Explorer, o maior Walking Dead da história da tecnologia. A era Ballmer foi um desastre.</p>
<p>Aí veio o iPad. E Steve Jobs morreu.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/592/hi-steve-jobs-memorial-0139.jpg" alt="Jobs Dies"  loading="lazy" /></p>
<h3>A Apple está presa em 2010.<span class="hx:absolute hx:-mt-20" id="a-apple-está-presa-em-2010"></span>
    <a href="#a-apple-est%c3%a1-presa-em-2010" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>E nós também.</p>
<p>As grandes distros Linux, a Microsoft, os fabricantes de hardware para PC, as viradas de grandes empresas (Nokia, Blackberry, Motorola), o começo da era das GPUs, o fim das guerras de clock da Lei de Moore em direção à computação paralela, a ascensão do ARM. Levou dez anos para a poeira baixar, e foi preciso a Apple ficar parada por seis anos para que todos os outros conseguissem alcançá-la.</p>
<p>Ballmer passou o bastão para Satya Nadella. A Microsoft adquiriu a Xamarin, deu passos enormes em direção ao open source e até o <a href="http://www.akitaonrails.com/2016/07/26/o-ano-do-linux-no-desktop-esta-usavel"target="_blank" rel="noopener">Ubuntu passou a rodar nativamente no Windows 10</a>.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/593/THE_END_TIMES_ARE_HERE-399de53540c79757ac9af535579cdad9.jpg" alt="Satya Nadella"  loading="lazy" /></p>
<p>E os asiáticos. Samsung, LG, Huawei, sul-coreanos e chineses forçaram os norte-americanos a se mexerem mais.</p>
<p>Um último legado da era Steve Jobs foi matar o Adobe Flash (finalmente!) e impulsionar as tecnologias HTML 5, comprimindo dez anos de evolução em cinco. Foi por causa do iPhone que a Web é o que é hoje.</p>
<p><a href="https://web.archive.org/web/20170114150212/http://www.apple.com/hotnews/thoughts-on-flash/"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/594/flash-dead.jpg" alt="HTML 5 kills Flash"  loading="lazy" /></a></p>
<p>O Google entrou em campo e assumiu o espaço deixado pelo Internet Explorer. O WebKit se tornou a referência obrigatória de navegadores. O JavaScript se transformou na nova plataforma de aplicações, impulsionado pelas redes sociais em constante evolução.</p>
<p>Para o bem ou para o mal, as redes sociais forçaram o surgimento de uma nova geração de aplicações web complexas e interativas. O Gmail e a Web 2.0 serviram de exemplo, e com o novo ambiente mobile, tudo convergiu para aplicações multiplataforma e ubíquas.</p>
<p>Hoje é mais fácil do que nunca trocar de sistema operacional no desktop, porque já treinamos o hábito de pular entre desktop e dispositivos móveis.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/599/alldevices.jpg" alt="All devices"  loading="lazy" /></p>
<p>Por que ficou fácil migrar entre macOS, Windows ou distros Linux? Ou entre macOS e iOS, ou entre Linux e Android? Porque a maior parte do software está &ldquo;na nuvem&rdquo;. O Linux domina o mundo da nuvem que a Amazon estreou em 2006 com S3 e EC2, seguida de perto pelo Google Cloud, Microsoft Azure e outros competidores menores.</p>
<p>Porque em qualquer plataforma existe pelo menos um bom Chrome.</p>
<p>Porque os apps que usamos são majoritariamente web: Gmail, Spotify, Slack, Hangout, Twitter, Facebook, YouTube, Netflix, Amazon. E a outra metade está disponível nativamente no iOS ou Android: WhatsApp, Waze, Swarm, Snapchat, Instagram.</p>
<p>Dez anos atrás, com o lançamento do iPhone, a indústria de tecnologia finalmente começou a se organizar.</p>
<p>Foi um jogo de gato e rato até uns cinco anos atrás, quando as coisas começaram a se estabilizar.</p>
<p>Depois que Jobs morreu, ainda tínhamos a expectativa de que a Apple continuaria avançando, ainda que num ritmo mais lento sem o chicote do Jobs.</p>
<p>Não aconteceu. Foram decisão ruim atrás de decisão ruim, e a sensação é de que voltamos ao início dos anos 90, na era de Scully, Spindler ou Amelio.</p>
<p><a href="https://web.archive.org/web/20170116083256/http://uk.businessinsider.com/wired-1997-save-apple-predictions-pray-2015-5"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/595/wired_cover.jpg" alt="Apple, Prey"  loading="lazy" /></a></p>
<p>Mas agora existem alternativas sólidas disponíveis: o Windows 10 Anniversary Edition é finalmente um Windows competente, recuperando a glória dos meados dos anos 90. E as grandes distros Linux são coesas, exigindo pouco ou nenhum ajuste nerd em arquivos de configuração obscuros, empurradas pela Canonical, para o bem ou para o mal.</p>
<p>E a maioria dos apps que usamos no dia a dia está disponível. Dá até para encontrar um bom editor de texto multiplataforma baseado na web na forma do Atom.</p>
<p>A Apple também deixou o legado da compilação multiplataforma ubíqua na forma do <a href="https://www.infoq.com/br/presentations/novas-linguagens-o-que-vem-depois-do-ruby"target="_blank" rel="noopener">LLVM</a>. Serviu às próprias necessidades deles de ter Objective-C disponível em PowerPC, Intel, ARM e nos processadores Apple Ax. Mas o LLVM é agora a melhor espinha dorsal para permitir que linguagens como Rust, RubyMotion e Crystal existam e criem binários rápidos em múltiplas plataformas.</p>
<p><a href="https://www.tesla.com/blog/welcome-chris-lattner"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/596/11-1484116910-chris-lattner-01.jpg" alt="Chris Lattner leaves Apple to Tesla"  loading="lazy" /></a></p>
<p>&ldquo;O conselho da Apple precisa ir embora.&rdquo; &ldquo;Tim Cook precisa renunciar.&rdquo; Tenho certeza que muita gente grita isso por aí, mas não tem Steve Jobs esperando para voltar. A Apple é grande o suficiente para que a inércia sozinha a mantenha andando por mais alguns anos, mas ela corre o risco real de cair na irrelevância.</p>
<p>Outras indústrias como energia, saúde e genética evoluem do jeito delas, mas a tecnologia da computação está num perigoso marasmo.</p>
<p>As linguagens de programação pararam de evoluir em meados dos anos 90. Todas as linguagens &ldquo;novas&rdquo; são amálgamas de recursos que já existiam desde os anos 70 e 80. Os processadores estão presos em fazer transistores menores e mais eficientes em termos de energia. E já chegamos lá: <a href="https://www.kickstarter.com/projects/1598272670/chip-the-worlds-first-9-computer"target="_blank" rel="noopener">computadores de US$ 9</a> são suficientes para tarefas triviais como navegar na web. A ponto de estarmos colocando processadores em tudo: inclusive numa escova de dentes bluetooth que registra suas sessões de escovação.</p>
<p><a href="https://www.dezeen.com/2017/01/06/ara-first-toothbrush-artifical-intelligence-kolibree-ces/"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/597/smart-video-toothbrush-ces.jpg" alt="Bluetooth Toothbrush"  loading="lazy" /></a></p>
<p>Viu os produtos da CES 2017? Travesseiros e camas que monitoram seu sono e sincronizam com um app. Máquinas de lavar. Aspiradores de pó. Dispositivos fitness. Dispositivos de saúde. Assistentes pessoais como a Alexa. Tudo captura dados seus e sincroniza na nuvem.</p>
<p>A nuvem também chegou ao pico. É ubíqua, acessível e barata. A tecnologia em geral está absurdamente barata hoje em dia.</p>
<p>Wearables e VR são boas novidades, mas mesmo que se tornem ubíquos, continuam sendo apenas uma extensão dos casos de uso que a revolução do iPhone iniciou.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/600/3017180-inline-mg5205.jpg" alt="Baby monitor"  loading="lazy" /></p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/601/iswimband-drowning-prevention-510px.jpg" alt="iSwimband"  loading="lazy" /></p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/602/6e752109eac4d37830078517b2aefd583d52722a.jpg" alt="mobile"  loading="lazy" /></p>
<p>Mobile, wearables, redes sociais, só deixaram as pessoas mais ansiosas. Dar &ldquo;voz&rdquo; a todo mundo online não melhorou as coisas, só aumentou a ansiedade geral. Opiniões estão em oferta tão grande que valem cada vez menos.</p>
<p>Cada pessoa online é agora uma fonte de terabytes de informação inútil para gerar pseudo-estatísticas que não servem para quase nada. <a href="http://www.techrepublic.com/article/the-dark-side-of-wearables-how-theyre-secretly-jeopardizing-your-security-and-privacy/"target="_blank" rel="noopener">Cada pessoa é agora definida por um monte de dados na nuvem</a>.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/603/donald-trump-twitter-president.jpg" alt="Trump"  loading="lazy" /></p>
<p>Não faço ideia para onde vamos daqui. Como testemunha da história, tenho que dizer que sinto falta da empolgação de explorar novas fronteiras. Tivemos isso a partir dos meados dos anos 90. Demos uma pausa depois do estouro da Bolha da Internet, mas recuperamos com tudo em 2004. Perdemos depois de 2010.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/598/20150824-bill-gates-microsoft-windows-95-launch.0.jpg" alt="Windows 95 launch"  loading="lazy" /></p>
<p>2010 foi o ano mais longo que já vivi. Talvez estabilizar seja uma coisa boa. Quem sabe?</p>
]]></content:encoded><category>apple</category><category>mercado-de-tecnologia</category><category>pessoal</category><category>off-topic</category></item><item><title>Situação Brasil: No Macs for the Rest of Us</title><link>https://akitaonrails.github.io/2015/11/10/situacao-brasil-no-macs-for-the-rest-of-us/</link><guid isPermaLink="true">https://akitaonrails.github.io/2015/11/10/situacao-brasil-no-macs-for-the-rest-of-us/</guid><pubDate>Tue, 10 Nov 2015 16:54:00 -0200</pubDate><description>&lt;p&gt;Este artigo quer ser prático, então vou direto ao ponto. Com o &lt;strong&gt;inquestionável&lt;/strong&gt; governo inepto e corrupto que temos, um dos efeitos concretos para nós, desenvolvedores de software, é a incapacidade de comprar boas máquinas para fazer o nosso próprio trabalho.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/523/cotacao_dolar.png" alt="Cotação do Dólar 2015" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;O Real entrou em queda livre no começo deste ano e só agora começa a estabilizar um pouco. Mesmo assim, ficamos cada vez mais longe do ideal de comprar um notebook profissional.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Este artigo quer ser prático, então vou direto ao ponto. Com o <strong>inquestionável</strong> governo inepto e corrupto que temos, um dos efeitos concretos para nós, desenvolvedores de software, é a incapacidade de comprar boas máquinas para fazer o nosso próprio trabalho.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/523/cotacao_dolar.png" alt="Cotação do Dólar 2015"  loading="lazy" /></p>
<p>O Real entrou em queda livre no começo deste ano e só agora começa a estabilizar um pouco. Mesmo assim, ficamos cada vez mais longe do ideal de comprar um notebook profissional.</p>
<p>No site oficial da Apple do Brasil, somando a desvalorização do Real e o <strong>maldito</strong> Custo Brasil em impostos, a máquina ideal de desenvolvimento, o Macbook Pro 15&quot; Retina com 16GB de RAM e 512GB SSD, chega à quantia impossível de R$ 23.499,00.</p>
<p>Nos Estados Unidos, essa mesma máquina custa USD 2.499 mais (pouco) imposto. Se fôssemos pelo mercado paralelo (que eu recomendo), com o dólar nos atuais R$ 3,80 mais uns 30% a 40% do &ldquo;custo paralelo&rdquo;, ainda assim não vamos pagar menos que R$ 13.500.</p>
<p>Mesmo escolhendo a versão 13&quot; Retina com 8GB de RAM, que custa USD 1.799 nos EUA, aqui não sai por menos que R$ 9.700.</p>
<p>Ou seja, é mais que o dobro do que a maioria dos desenvolvedores consegue pagar, considerando um orçamento de R$ 4.000, até R$ 5.000 se esticarmos muito.</p>
<p>O TL;DR é simples: o melhor hardware (não só processador, mas teclado, trackpad, acabamento geral) continua sendo o Macbook Pro. Nenhuma outra máquina chega perto, e para mim o melhor sistema operacional continua sendo o OS X, com virtualização de Linux para desenvolvimento. Sem poder comprar um Macbook, resta escolher um bom PC e rodar Linux.</p>
<h3>Qual Máquina Comprar?<span class="hx:absolute hx:-mt-20" id="qual-máquina-comprar"></span>
    <a href="#qual-m%c3%a1quina-comprar" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Mesmo comprando uma máquina no Brasil, não dá para levar a melhor configuração, que empurra o preço para acima dos R$ 8.000.</p>
<p>Na faixa dos R$ 5.000, esqueçam SSD, não existe. O melhor custo-benefício que achei foi o <a href="http://web.archive.org/web/20150625001142/http://www.dell.com/br/p/inspiron-15-5548-laptop/pd?oc=cai5548u1612656br052&amp;model_id=inspiron-15-5548-laptop"target="_blank" rel="noopener">Dell Inspiron 15 Series 5000</a>, que no momento da publicação deste artigo estava R$ 4.117. Vale escolher com bastante RAM, mais de 8GB de preferência, para evitar ao máximo o swap no disco lento, normalmente mecânico de 5400 RPM.</p>
<p>Se alguém tiver boas opções nessa faixa, com pelo menos Core i5 de 3a geração, 8GB de RAM e 256GB de SSD, compartilhe nos comentários.</p>
<p>Em termos de hardware, um Lenovo Thinkpad ou mesmo um Sony Vaio (que também deve estar proibitivamente caro) têm acabamento melhor que o da Dell. Asus e Acer eu não considero boas opções para durar muito tempo, e o acabamento também não é grande coisa.</p>
<p>Já adianto que teclado e trackpad de PC são terríveis. Se possível, use teclado e trackpad externos da Apple. O modelo da Dell que estou testando tem um teclado horrível, fora o layout brasileiro que eu detesto: plástico leve, com feedback de clique muito ruim para quem digita rápido. O trackpad interrompe a digitação a cada leve toque, tem dificuldade de registrar múltiplos cliques corretamente e no geral atrapalha mais do que ajuda.</p>
<h3>Perfis de Desenvolvedor<span class="hx:absolute hx:-mt-20" id="perfis-de-desenvolvedor"></span>
    <a href="#perfis-de-desenvolvedor" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A ideia é uma máquina para desenvolvedores. A menos que você seja um desenvolvedor .NET, instale uma distribuição Linux. Qual distro depende do seu perfil: quanto mais low level, mais você se aproxima de querer um Arch Linux. Quanto mais high level, sobretudo desenvolvedor de web apps, mais eu recomendo um Ubuntu LTS, que no caso seria o Ubuntu 14.04.</p>
<p>Windows está fora de cogitação, sinto muito. Fui usuário de Windows por quase 15 anos antes de migrar para Macs em 2004. Sou muito experiente com Windows, conheço todos os meus caminhos tortuosos pelo Registry e a bagunça que é o famigerado C:\WINDOWS. Testei todos os últimos Windows (7, 8, 8.1, 10) e a conclusão é a mesma: não faço nenhuma questão de voltar.</p>
<p>Se tivesse que desenvolver em .NET, nem tentaria emular o ambiente, apenas usaria Windows mesmo, numa máquina virtual. A única solução, quando o ambiente de desenvolvimento exige um híbrido de .NET com open source, é rodar Linux com virtualização.</p>
<p>O ciclo de desenvolvimento open source num Mac também não é exatamente simples. Você precisa entender o XCode e precisa saber que o GCC deixou de ser a escolha default faz tempo, já que a Apple migrou para LLVM-Clang, e por conta disso muita coisa pode quebrar. Mesmo assim, o pessoal do <a href="https://brew.sh/"target="_blank" rel="noopener">Homebrew</a> fez um excelente trabalho removendo a maior parte dos problemas. Dá para desenvolver confortavelmente, desde que você não seja um desenvolvedor system/low level.</p>
<p>Para desenvolvimento de iOS, você precisa do XCode. Não há alternativa. Nas outras linguagens dá para trabalhar com relativa facilidade, seja Python, Ruby ou as mais novas como Rust, Elixir e Go. Java também roda mais ou menos bem no Mac, então Java 8, Clojure, Scala e Groovy estão à disposição.</p>
<p>Opcionalmente, recomendo usar um ambiente Linux virtualizado dentro do Mac. Seja direto pelo Virtualbox, que não é a coisa mais estável do mundo no Mac, seja pelo VMWare Fusion, com <a href="https://www.vagrantup.com/vmware"target="_blank" rel="noopener">Vagrant</a> para facilitar. Essa segunda opção vai custar caro, USD 170.</p>
<h3>Software Proprietário vs Código Aberto<span class="hx:absolute hx:-mt-20" id="software-proprietário-vs-código-aberto"></span>
    <a href="#software-propriet%c3%a1rio-vs-c%c3%b3digo-aberto" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Sim, no Linux temos diversas opções, como Inkscape, Gimp e Blender. Sim, &ldquo;dá&rdquo; para fazer muita coisa.</p>
<p>Na prática, usabilidade conta.</p>
<p>No OS X temos Keynote, iMovie e Garageband, sem iguais em usabilidade. Para fins mais high end, temos Aperture, Final Cut Pro e Logic Pro, de novo sem iguais em usabilidade e flexibilidade.</p>
<p>No Windows, dá para escolher o pacote da Adobe, que vai de Photoshop e Illustrator a Premiere Pro e After Effects, todos com versões também para Mac.</p>
<p>No mundo da produtividade, esqueçam LibreOffice ou mesmo Google Docs: o pacote Microsoft Office, em particular Word e Excel, ainda é imbatível. Dá para fazer parecido, dá para editar parecido, mas ainda não chega perto, especialmente em planilhas mais complexas e cheias de fórmulas, pivot tables e afins.</p>
<p>Todos eles custam, e custam caro. Obviamente não é justo comparar com as opções open source. Mas eu gostaria muito de ter a opção de pagar para rodar isso numa distro Linux. O problema é que distros Linux não são amigáveis para software proprietário. Vai ser sempre o dilema do 100% aberto contra o híbrido ou o 100% fechado. Que o digam os caras do Ubuntu.</p>
<p>Um exemplo pequeno é o 1Password, que uso no Mac, no Android, usava no iOS (quando tinha iPhone) e tem versão para Windows. Tudo, menos para Linux. Fui obrigado a rodar o 1Password de Windows via Wine para conseguir acessar minhas senhas de novo. &ldquo;Bem feito, quem mandou usar software proprietário.&rdquo;</p>
<p>Para o bem ou para o mal, o ideal de software 100% aberto nunca esteve tão longe, ainda mais hoje, quando todo app tem um componente online. Existe agora muito &ldquo;client&rdquo; open source, mas o back-end é totalmente closed source. Pior: nem é um binário na sua máquina, está no &ldquo;cloud&rdquo;.</p>
<p>Ninguém vai aderir ao ideal da <a href="http://www.gnu.org/licenses/why-affero-gpl.en.html"target="_blank" rel="noopener">Affero GPL</a>, em que o código rodando no cloud também deveria ser aberto. E, mesmo se fosse, não seria prático para ninguém simular o mesmo ambiente cloud de todo mundo.</p>
<p>Hoje, o mundo open source não é um mundo de liberdade absoluta. Eu costumo sintetizar assim: ele é o melhor custo-benefício que as empresas já tiveram para manter software comoditizado.</p>
<p>Linguagens, frameworks, toolkits, ferramentas de desenvolvimento e bibliotecas de criptografia são software comoditizado.</p>
<p>Pacote Adobe, Office e afins ainda não são commodities. Continuam a todo vapor, com feature nova atrás de feature nova, todo semestre. É impossível um copy-cat open source, sem recursos, atingir o mesmo nível. E nem há interesse nisso.</p>
<p>Para quem precisa de software proprietário como ferramenta do dia a dia, o conselho é direto: não saia do Windows, não saia do Mac.</p>
<p>Eu preciso ocasionalmente. 80% das minhas necessidades dependem de software comoditizado ou de software que não é o core business de nenhuma empresa que o produz. Para o Google, o Chromium vale a pena ser open source, mas ninguém chega perto do código do Ad Sense, que é o verdadeiro core business.</p>
<p>Para todo mundo, vale a pena que os clients que consomem os serviços sejam open source. Vou achar um bom client para Dropbox, para Google Drive, mas nem tente procurar o resto: o core business ainda é e vai continuar fechado. É aí que o ideal do Free Software vai ficando cada vez mais distante.</p>
<p>Eu não sou idealista. Para a maioria dos desenvolvedores, o que temos já basta, se sustenta e vira viável num mundo híbrido. No mundo real, 80% do que preciso está disponível. Os outros 20% eu resolvo por virtualização, com o meu Office rodando via Wine ou via Virtualbox.</p>
<p>Talvez eu consiga rodar o Apple Keynote via Hackintosh num Virtualbox. Ou então resolvo os últimos 5% com um Macbook defasado, mas que rode o que preciso nas poucas horas em que preciso dele.</p>
<p>Tentei instalar um Hackintosh via Virtualbox e, embora tenha conseguido depois de várias tentativas e muitos tutoriais, ele fica absolutamente instável e lento, mesmo com 2 dos meus 4 Core i7, 4GB de RAM e 128MB de memória de vídeo. Não dá para usar. Se eu quiser usar Keynote, vai ter que ser um Mac de verdade, não tem substituto.</p>
<h3>Por que Ubuntu + Unity?<span class="hx:absolute hx:-mt-20" id="por-que-ubuntu--unity"></span>
    <a href="#por-que-ubuntu--unity" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Se tem uma coisa em que todo mundo tem opinião é em como usar o seu Linux. Depende de quem você é.</p>
<p>Se você for um programador mais idealista, vai odiar o Ubuntu justamente por pegar o que o Debian faz e adicionar a <em>argh</em> terrível camada de software proprietário por cima.</p>
<p>Se você for um programador mais hardcore, vai querer entender cada centímetro do seu Linux, e para isso sempre vai achar o Arch Linux (ou pelo menos o <a href="http://web.archive.org/web/20150913071621/http://antergos.com/"target="_blank" rel="noopener">Antergos</a>) uma opção superior. Para esse pessoal, o Pacman sempre será infinitamente superior ao Apt-Get ou ao Yum.</p>
<p>Se você for do tipo &ldquo;seja estável sem mexer muito, mas não seja comum&rdquo;, pode acabar indo para o lado do Fedora.</p>
<p>E, seja qual for a distro, sempre vai existir a eterna briga entre Window Managers. O pessoal do KDE com o seu Plasma falando mal do antiquado Gnome, o XFCE afirmando sua posição de &ldquo;simples e estável&rdquo;, ou uma distro nova como o Elementary OS criando o seu novo Pantheon. Isso não tem fim.</p>
<p>A maioria dos programadores novos, que usam Linux há 5 anos ou menos, não entende como alguém pode usar um Linux sem customizá-lo totalmente ao seu gosto. Editar cada arquivo do X11, cada tema e cada pacote de ícones para virar um &ldquo;Windows-alternativo&rdquo;, um &ldquo;OS X-rebelde&rdquo;.</p>
<p>No meu caso, o que muitos podem não entender, é que sou usuário de Linux das antigas. Meu primeiro Linux foi o Slackware 1.0 em 1996. Instalei RedHat pré-4 e depois vieram distros como o Mandrake, muito antes de um Kurumin. Instalei as primeiras versões da maioria das distros de hoje.</p>
<p>Já varei noite após noite customizando o meu X, baixando temas, baixando widgets, ajustando cada parte do sistema. Depois eu fazia alguma coisa errada, resolvia formatar tudo e começava do zero de novo. Passei muito tempo checando flags de compilação de kernel para deixar o meu o mais customizado possível.</p>
<p>Fiquei nessa vibe de 1997 até talvez 2001. É cansativo, sério. Se você é programador, na faixa dos 20 anos e nunca fez isso, eu diria que tem obrigação <strong>moral</strong> de passar por esse processo. Todo programador precisa achar legal ter controle total do próprio ambiente.</p>
<p>Mas não é saudável fazer isso por mais de 5 anos. Depois disso, você quer mesmo é ser produtivo, produzir em vez de customizar. A quantidade de horas necessária para deixar uma distro 100% &ldquo;minha&rdquo; simplesmente não compensa.</p>
<p>É por isso que eu gosto do OS X: não preciso customizar nada. Tudo já vem do jeito certo out-of-the-box, o melhor Window Manager, em cima de um dos melhores sabores tradicionais de Unix, com acesso razoavelmente simples tanto ao mundo open source quanto ao melhor do mundo closed source. É o melhor dos dois mundos.</p>
<p>No mundo Linux, você tem que lidar com a ideologia do GPL. Eu entendo perfeitamente os argumentos do Stallman, li e reli o site inúmeras vezes. Quantas vezes você <strong>realmente</strong> leu o <a href="http://www.gnu.org/philosophy/philosophy.html"target="_blank" rel="noopener">gnu.org</a> inteiro? Infelizmente não existe almoço grátis: ficar na ideologia significa abrir mão de muita coisa que eu realmente não tenho disposição de abrir.</p>
<p>No caso, o Dell que eu comprei veio com Ubuntu pré-instalado. É o que ele suporta, o que significa que todo o hardware funciona e os drivers estão atualizados. Pretendo ficar dentro do ecossistema Ubuntu, incluindo o Unity, que eu sei que muitos não curtem por ideologia ou porque acham que XFCE, Gnome, KDE ou sei lá o quê funciona melhor para o gosto deles.</p>
<p>De novo: o custo de customizar simplesmente não compensa. Software não se instala uma vez e funciona para sempre. Tem que atualizar, tem que ter suporte, tem que ser consistente. O pessoal da Canonical é a única empresa seriamente focada em usabilidade e consumidor final, e isso importa.</p>
<p>A Canonical é freada o tempo todo pela ideologia e por opiniões demais que nunca chegam a consenso, e é vilipendiada toda vez que toma uma decisão: sempre uma metade da comunidade fica sem o que quer e vai chiar. É um processo moroso e burocrático que uma Apple simplesmente decidiu ignorar por completo.</p>
<p>Só que a Apple tem como trazer a Microsoft, a Adobe e gerar modelos de negócio lucrativos para centenas de outras software houses. A Canonical ainda não consegue fazer isso e depende muito das horas vagas de programadores voluntários do mundo open source. Essa dependência é ao mesmo tempo uma grande força e o seu maior problema.</p>
<p>Última dica: tive problemas para manter o sistema em inglês (menus e tudo mais) e usar um teclado USB externo de Mac no layout English (US, alternative international). O normal, acentuar o &ldquo;c&rdquo; para sair o cedilha &ldquo;ç&rdquo;, não funcionava. Só funcionou depois que segui este tutorial do <a href="http://linuxlegal.blogspot.com/2014/02/cedilha-no-ubuntu-1310-com-teclado.html"target="_blank" rel="noopener">Kemel Zaidan</a>.</p>
<h3>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Vou continuar usando Ubuntu como máquina principal? Ainda não sei. Estou mantendo as opções abertas para tempos mais difíceis, com o dólar acima de R$ 2,50. Abaixo desse patamar, fico com um Mac sem pensar duas vezes.</p>
<p>Para usuários domésticos, um Linux funciona bem. É a ideia do Chrome OS, um Linux rodando basicamente Web Apps como Google Docs, Gmail e afins. Nesse nível, tanto faz o OS ou a configuração. A vantagem de um Linux para o uso web de 90% da população é não ficar vulnerável aos malwares mais óbvios.</p>
<p>Para usuários de escritório, um Linux funciona razoavelmente bem, mas, como eu disse, o Office ainda não dá para substituir. A saída é a empresa inteira adotar um formato mais simples de documentos e não fazer nada muito complexo no Excel, por exemplo. No geral, Google Docs e Google Drive ou Dropbox, com Gmail Business, funcionam bem o suficiente.</p>
<p>Para desenvolvedores .NET, fiquem no Windows.</p>
<p>Para desenvolvedores open source, tanto faz ficar no Linux ou no Mac. Se for high end, escolha um Mac se puder pagar. Se for mais low level, fique no mundo Linux puro mesmo. Na dúvida: Ubuntu 14.04 LTS (com Unity!), instale a sua opção de Sublime Text 3 e o resto funciona perfeitamente.</p>
<p>Para usuários híbridos, que são desenvolvedores a maior parte do tempo mas também precisam de software proprietário (o meu caso), dá para ficar no Linux. Na maior parte do tempo não vai doer tanto. Mas naquele único momento em que você precisar editar um vídeo, mexer num Photoshop mais pesado ou montar um Keynote mais elaborado, tenha um Mac à mão. Para esse caso, não há alternativa.</p>
]]></content:encoded><category>linux</category><category>apple</category><category>hardware</category><category>off-topic</category></item><item><title>Swift para Rubistas, Funções e Closures</title><link>https://akitaonrails.github.io/2014/06/07/swift-para-rubistas-funcoes-e-closures/</link><guid isPermaLink="true">https://akitaonrails.github.io/2014/06/07/swift-para-rubistas-funcoes-e-closures/</guid><pubDate>Sat, 07 Jun 2014 12:38:00 -0300</pubDate><description>&lt;p&gt;Se tem uma coisa que nós rubistas estamos muito acostumados e gostamos bastante são closures, blocos ou fechamentos. Expliquei esse mecanismo pela primeira vez em 2007 aqui no blog, então se ainda não conhece bem o conceito, releia &lt;a href="http://www.akitaonrails.com/2007/11/30/anatomia-de-ruby-blocks-closures#.U5MdTBYduzA"target="_blank" rel="noopener"&gt;meu post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Em 2010 a Apple adicionou a funcionalidade de closures ao Objective-C também e modificou muitas de suas APIs para aproveitar esse recurso. Também postei sobre isso 3 anos atrás, então releia &lt;a href="http://www.akitaonrails.com/2010/11/28/objective-c-brincando-com-categorias-e-blocos#.U5MdhxYduzA"target="_blank" rel="noopener"&gt;meu post&lt;/a&gt; para aprender sobre isso.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Se tem uma coisa que nós rubistas estamos muito acostumados e gostamos bastante são closures, blocos ou fechamentos. Expliquei esse mecanismo pela primeira vez em 2007 aqui no blog, então se ainda não conhece bem o conceito, releia <a href="http://www.akitaonrails.com/2007/11/30/anatomia-de-ruby-blocks-closures#.U5MdTBYduzA"target="_blank" rel="noopener">meu post</a>.</p>
<p>Em 2010 a Apple adicionou a funcionalidade de closures ao Objective-C também e modificou muitas de suas APIs para aproveitar esse recurso. Também postei sobre isso 3 anos atrás, então releia <a href="http://www.akitaonrails.com/2010/11/28/objective-c-brincando-com-categorias-e-blocos#.U5MdhxYduzA"target="_blank" rel="noopener">meu post</a> para aprender sobre isso.</p>
<p>Finalmente, Swift é basicamente Objective-C melhorado então temos o mesmo recurso.</p>
<h2>Entendendo Funções e Blocos</h2>
<p>A idéia é poder criar funções &ldquo;customizáveis&rdquo;, ou seja, um pedaço de código que espera outro pedaço de código. Existem duas formas de se fazer isso. No mundo C podemos passar diretamente uma função como parâmetro para ser executada dentro de outra função. Isso não é uma closure, é o que chamamos de &ldquo;callback&rdquo;. Em Objective-C e Swift, podemos passar uma função como parâmetro ou mesmo fazer uma função retornar uma função.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="n">func</span> <span class="nf">soma</span><span class="p">(</span><span class="nl">x</span><span class="p">:</span> <span class="n">Int</span><span class="p">,</span> <span class="nl">y</span><span class="p">:</span> <span class="n">Int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Int</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">func</span> <span class="nf">calculadora</span><span class="p">(</span><span class="nl">calculo</span><span class="p">:</span> <span class="p">(</span><span class="n">Int</span><span class="p">,</span> <span class="n">Int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="n">Int</span><span class="p">),</span> <span class="nl">a</span><span class="p">:</span> <span class="n">Int</span><span class="p">,</span> <span class="nl">b</span><span class="p">:</span> <span class="n">Int</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">let</span> <span class="n">resultado</span> <span class="o">=</span> <span class="nf">calculo</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nf">println</span><span class="p">(</span><span class="n">resultado</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">calculadora</span><span class="p">(</span><span class="n">soma</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">// &#34;30&#34;
</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Veja o código acima, definimos uma função de soma, que recebe dois inteiros como parâmetro e retorna um inteiro. Depois definimos uma função genérica chamada &ldquo;calculadora&rdquo; que recebe como parâmetro uma função com a assinatura <tt>(Int, Int) -&gt; Int</tt> que significa &ldquo;uma função que receba dois inteiros e retorne um inteiro&rdquo; e depois dois parâmetros inteiros.</p>
<p>Ao executar <tt>calculadora(soma, 10, 20)</tt>, passamos a função soma, os números 10 e 20 e internamente atribuímos a função soma a uma variável chamada &ldquo;calculo&rdquo; e executamos passando os dois inteiros, que, obviamente, serão somados. E a resposta no final será 30.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="n">func</span> <span class="nf">multiplicacao</span><span class="p">(</span><span class="nl">x</span><span class="p">:</span> <span class="n">Int</span><span class="p">,</span> <span class="nl">y</span><span class="p">:</span> <span class="n">Int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Int</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">x</span> <span class="o">*</span> <span class="n">y</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">calculadora</span><span class="p">(</span><span class="n">multiplicacao</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">// &#34;15&#34;
</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Podemos agora criar quaisquer funções com a mesma assinatura e depois mandar para a calculadora. Em Ruby não temos a mesma funcionalidade:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">soma</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">x</span> <span class="o">+</span> <span class="n">y</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">calculadora</span><span class="p">(</span><span class="n">calculo</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nb">puts</span> <span class="n">calculo</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">calculadora</span><span class="p">(</span><span class="n">soma</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ArgumentError: wrong number of arguments (0 for 2)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 	from (irb):1:in `soma&#39;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 	from (irb):9</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 	from /usr/bin/irb:12:in `&lt;main&gt;&#39;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Em Ruby, parênteses são opcionais e ao tentar passar o método &ldquo;soma&rdquo; como parâmetro, na verdade ele está já tentando executar o método. Existe uma forma, não ortodoxa, que podemos ter um efeito similar, mas não é a mesma coisa, seria assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">calculadora</span><span class="p">(</span><span class="n">calculo</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nb">puts</span> <span class="nb">send</span><span class="p">(</span><span class="n">calculo</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">calculadora</span><span class="p">(</span><span class="ss">:soma</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O método <a href="http://ruby-doc.org/core-2.1.1/Object.html#method-i-send"target="_blank" rel="noopener"><tt>send</tt></a> é uma das formas de se enviar mensagens a objetos (Objective-C também tem isso, na forma de seletores e do método <tt>performSelector</tt> que expliquei <a href="http://www.akitaonrails.com/2010/12/06/objective-c-method-missing#.U5MhaRYduzA"target="_blank" rel="noopener">neste outro post</a>). Então, em vez de passar diretamente o método, passamos apenas o nome dele como um symbol e internamente executamos o método passando os parâmetros. Isso é só &ldquo;similar&rdquo; porque na prática o método em si nunca foi passado como parâmetro.</p>
<p>O que podemos fazer em Ruby é não usar métodos, mas blocos:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">soma</span> <span class="o">=</span> <span class="nb">lambda</span> <span class="k">do</span> <span class="o">|</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">  <span class="n">x</span> <span class="o">+</span> <span class="n">y</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">calculadora</span><span class="p">(</span><span class="n">calculo</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nb">puts</span> <span class="n">calculo</span><span class="o">.</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">calculadora</span><span class="p">(</span><span class="n">soma</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Aqui a semântica é diferente. Primeiro criamos um bloco, literalmente o que seria o &ldquo;corpo de um método&rdquo; usando <tt>lambda</tt>. Depois passamos o bloco com parâmetro ao método <tt>calculadora</tt>. E dentro dela executamos o bloco com um &ldquo;ponto&rdquo; antes dos parênteses, que é a forma curta de se fazer <tt>soma.call(a, b)</tt></p>
<p>Um bloco, em Ruby, é diferente de uma método ou função. Isso porque ele também é um fechamento do estado ao redor do bloco. Blocos não são métodos. Em Ruby, o método está associado (&ldquo;binding&rdquo;) à classe que a define (mesmo sem definir um <tt>class</tt>, estamos dentro sempre dentro de um objeto, diferente de Swift ou Objective-C ou mesmo outra linguagem). Um bloco está associado à uma variável e por isso podemos mais facilmente repassá-la para outros métodos.</p>
<p>Em Swift também podemos devolver funções ou ter &ldquo;Nested Functions&rdquo;, por exemplo:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="n">func</span> <span class="nf">calculo</span><span class="p">(</span><span class="nl">tipo</span><span class="p">:</span> <span class="n">String</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="n">Int</span><span class="p">,</span> <span class="n">Int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Int</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">func</span> <span class="nf">soma</span><span class="p">(</span><span class="nl">x</span><span class="p">:</span> <span class="n">Int</span><span class="p">,</span> <span class="nl">y</span><span class="p">:</span> <span class="n">Int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Int</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">func</span> <span class="nf">multiplicacao</span><span class="p">(</span><span class="nl">x</span><span class="p">:</span> <span class="n">Int</span><span class="p">,</span> <span class="nl">y</span><span class="p">:</span> <span class="n">Int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Int</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">x</span> <span class="o">*</span> <span class="n">y</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">tipo</span> <span class="o">==</span> <span class="s">&#34;soma&#34;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">soma</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">multiplicacao</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">func</span> <span class="nf">calculadora</span><span class="p">(</span><span class="nl">calculo</span><span class="p">:</span> <span class="p">(</span><span class="n">Int</span><span class="p">,</span> <span class="n">Int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Int</span><span class="p">,</span> <span class="nl">a</span><span class="p">:</span> <span class="n">Int</span><span class="p">,</span> <span class="nl">b</span><span class="p">:</span> <span class="n">Int</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">println</span><span class="p">(</span><span class="nf">calculo</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">calculadora</span><span class="p">(</span><span class="nf">calculo</span><span class="p">(</span><span class="s">&#34;soma&#34;</span><span class="p">),</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 30
</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Em Ruby, o mais próximo, usando blocos, seria:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">calculo</span><span class="p">(</span><span class="n">tipo</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">soma</span> <span class="o">=</span> <span class="nb">lambda</span> <span class="p">{</span> <span class="o">|</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="o">|</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="n">multiplicacao</span> <span class="o">=</span> <span class="nb">lambda</span> <span class="p">{</span> <span class="o">|</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="o">|</span> <span class="n">x</span> <span class="o">*</span> <span class="n">y</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="n">tipo</span> <span class="o">==</span> <span class="ss">:soma</span>
</span></span><span class="line"><span class="cl">    <span class="n">soma</span>
</span></span><span class="line"><span class="cl">  <span class="k">else</span>
</span></span><span class="line"><span class="cl">    <span class="n">multiplicacao</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">calculadora</span><span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nb">puts</span> <span class="n">c</span><span class="o">.</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">calculadora</span><span class="p">(</span><span class="n">calculo</span><span class="p">(</span><span class="ss">:soma</span><span class="p">),</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 30</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h2>Entendendo Blocos em Swift</h2>
<p>Sabendo dessa base podemos prosseguir para o próximo passo, blocos em Swift.</p>
<p>Primeiro, vejamos o uso mais comum de blocos em Ruby:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">numero</span><span class="p">(</span><span class="n">bla</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">yield</span><span class="p">(</span><span class="n">bla</span><span class="p">)</span> <span class="k">if</span> <span class="nb">block_given?</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">numero</span> <span class="mi">20</span> <span class="k">do</span> <span class="o">|</span><span class="n">x</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">  <span class="n">x</span> <span class="o">*</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 200</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Definimos um método chamado <tt>numero</tt> que recebe um parâmetro &ldquo;bla&rdquo;. Internamente chamamos <tt>yield</tt> que pega o bloco passado como último parâmetro do método e repassa o parâmetro &ldquo;bla&rdquo; a ele. Fora, executamos o método frase, passando 20 como parâmetro e um bloco (delimitado por &ldquo;do..end&rdquo;) que recebe uma variável x e apenas multiplica ela por 10.</p>
<p>Podemos reescrever o mesmo código da seguinte forma:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">numero</span><span class="p">(</span><span class="n">bla</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">bloco</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">bloco</span><span class="o">.</span><span class="p">(</span><span class="n">bla</span><span class="p">)</span> <span class="k">if</span> <span class="n">bloco</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">numero</span><span class="p">(</span><span class="mi">20</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">x</span><span class="o">|</span> <span class="n">x</span> <span class="o">*</span> <span class="mi">10</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 200</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>É exatamente o mesmo código mas agora o bloco está definido como parâmetro mais explicitamente. O &ldquo;&amp;&rdquo; diz que vamos passar o bloco fora dos parênteses do método. Executamos o bloco dentro com o &ldquo;ponto&rdquo; (no lugar de &ldquo;call&rdquo;, como explicamos antes). E ao executar o método, desta vez deixei os parênteses opcionais e no lugar de &ldquo;do..end&rdquo; usei &ldquo;{}&rdquo;, que é a mesma coisa. Por convenção, em Ruby, usamos &ldquo;{}&rdquo; quando um bloco tem somente uma linha de implementação e usamos &ldquo;do..end&rdquo; quando tem múltiplas linhas.</p>
<p>Obs, o <a href="http://twitter.com/josevalim"target="_blank" rel="noopener">@josevalim</a> me explicou que há outra sintaxe que podemos usar e são equivalentes (embora pareça que só funcione em one-lines):</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="n">numero</span><span class="p">.</span><span class="n">map</span> <span class="p">{</span> <span class="p">(</span><span class="n">var</span> <span class="nl">x</span><span class="p">:</span> <span class="n">Int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Int</span> <span class="n">in</span> <span class="k">return</span> <span class="n">x</span> <span class="o">*</span> <span class="mi">10</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">numero</span><span class="p">.</span><span class="n">map</span> <span class="p">{</span> <span class="err">$</span><span class="mi">0</span> <span class="o">*</span> <span class="mi">10</span> <span class="p">}</span> <span class="c1">// equivalente ao de cima
</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Confinuando, podemos fazer a mesma coisa em Swift, assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="n">func</span> <span class="nf">numero</span><span class="p">(</span><span class="nl">bla</span><span class="p">:</span> <span class="n">Int</span><span class="p">,</span> <span class="nl">bloco</span><span class="p">:</span> <span class="p">(</span><span class="n">Int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Int</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">println</span><span class="p">(</span><span class="nf">bloco</span><span class="p">(</span><span class="n">bla</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">numero</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="p">{</span> <span class="p">(</span><span class="nl">x</span><span class="p">:</span> <span class="n">Int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Int</span> <span class="n">in</span> <span class="k">return</span> <span class="n">x</span> <span class="o">*</span> <span class="mi">10</span> <span class="p">}</span> <span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Por causa da necessidade de definir o seletor/assinatura, com parâmetros e tipo de retorno, a execução da closure em Swift é bem mais verbosa do que em Ruby. A sintaxe é semelhante, usando chaves &ldquo;{}&rdquo; para delimitar o bloco, a assinatura para delimitar a função anônima e o corpo do bloco depois de &ldquo;in&rdquo;. Na prática é quase a mesma coisa.</p>
<p>Do livro oficial da Apple temos o seguinte exemplo que pode demonstrar um pouco melhor (eu mudei o exemplo pois no livro ele usa um Dictionary para &ldquo;digitNames&rdquo; mas as chaves são exatamente a posição num Array, então achei melhor usar diretamente um Array):</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="n">let</span> <span class="n">digitNames</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;Zero&#34;</span><span class="p">,</span> <span class="s">&#34;One&#34;</span><span class="p">,</span> <span class="s">&#34;Two&#34;</span><span class="p">,</span> <span class="s">&#34;Three&#34;</span><span class="p">,</span> <span class="s">&#34;Four&#34;</span><span class="p">,</span> <span class="s">&#34;Five&#34;</span><span class="p">,</span> <span class="s">&#34;Six&#34;</span><span class="p">,</span> <span class="s">&#34;Seven&#34;</span><span class="p">,</span> <span class="s">&#34;Eight&#34;</span><span class="p">,</span> <span class="s">&#34;Nine&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">let</span> <span class="n">numbers</span> <span class="o">=</span> <span class="p">[</span><span class="mi">16</span><span class="p">,</span> <span class="mi">58</span><span class="p">,</span> <span class="mi">510</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">let</span> <span class="n">strings</span> <span class="o">=</span> <span class="n">numbers</span><span class="p">.</span><span class="n">map</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="n">var</span> <span class="n">number</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">String</span> <span class="n">in</span>
</span></span><span class="line"><span class="cl">    <span class="n">var</span> <span class="n">output</span> <span class="o">=</span> <span class="s">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="n">number</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">output</span> <span class="o">=</span> <span class="n">digitNames</span><span class="p">[</span><span class="n">number</span> <span class="o">%</span> <span class="mi">10</span><span class="p">]</span> <span class="o">+</span> <span class="n">output</span>
</span></span><span class="line"><span class="cl">        <span class="n">number</span> <span class="o">/=</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">output</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// strings is inferred to be of type String[]
</span></span></span><span class="line"><span class="cl"><span class="c1">// its value is [&#34;OneSix&#34;, &#34;FiveEight&#34;, &#34;FiveOneZero&#34;]
</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>A mesma coisa em Ruby ficaria assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">digit_names</span> <span class="o">=</span> <span class="o">[</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;Zero&#34;</span><span class="p">,</span> <span class="s2">&#34;One&#34;</span><span class="p">,</span> <span class="s2">&#34;Two&#34;</span><span class="p">,</span> <span class="s2">&#34;Three&#34;</span><span class="p">,</span> <span class="s2">&#34;Four&#34;</span><span class="p">,</span> <span class="s2">&#34;Five&#34;</span><span class="p">,</span> <span class="s2">&#34;Six&#34;</span><span class="p">,</span> <span class="s2">&#34;Seven&#34;</span><span class="p">,</span> <span class="s2">&#34;Eight&#34;</span><span class="p">,</span> <span class="s2">&#34;Nine&#34;</span>
</span></span><span class="line"><span class="cl"><span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="n">numbers</span> <span class="o">=</span> <span class="o">[</span><span class="mi">16</span><span class="p">,</span> <span class="mi">58</span><span class="p">,</span> <span class="mi">510</span><span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="n">strings</span> <span class="o">=</span> <span class="n">numbers</span><span class="o">.</span><span class="n">map</span> <span class="k">do</span> <span class="o">|</span><span class="n">number</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">  <span class="n">output</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="k">while</span> <span class="n">number</span> <span class="o">&gt;</span> <span class="mi">0</span> 
</span></span><span class="line"><span class="cl">    <span class="n">output</span> <span class="o">=</span> <span class="n">digit_names</span><span class="o">[</span><span class="n">number</span> <span class="o">%</span> <span class="mi">10</span><span class="o">]</span> <span class="o">+</span> <span class="n">output</span>
</span></span><span class="line"><span class="cl">    <span class="n">number</span> <span class="o">=</span> <span class="n">number</span> <span class="o">/</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="n">output</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [&#34;OneSix&#34;, &#34;FiveEight&#34;, &#34;FiveOneZero&#34;]</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Veja como a lógica em si é bastante semelhante, se ignorar a definição mais exata de tipos do Swift, os dois códigos são praticamente idênticos.</p>
<p>No <a href="http://www.akitaonrails.com/2010/12/06/objective-c-method-missing#.U5MhaRYduzA"target="_blank" rel="noopener">meu post de 2010</a> sobre como implementar o equivalente a &ldquo;method_missing&rdquo; em Objective-C eu parti deste exemplo comum de DSL do mundo Ruby:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;builder&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">x</span> <span class="o">=</span> <span class="no">Builder</span><span class="o">::</span><span class="no">XmlMarkup</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">:target</span> <span class="o">=&gt;</span> <span class="vg">$stdout</span><span class="p">,</span> <span class="ss">:indent</span> <span class="o">=&gt;</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">x</span><span class="o">.</span><span class="n">html</span> <span class="k">do</span> <span class="o">|</span><span class="n">h</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">  <span class="n">h</span><span class="o">.</span><span class="n">body</span> <span class="k">do</span> <span class="o">|</span><span class="n">b</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">    <span class="n">b</span><span class="o">.</span><span class="n">h1</span> <span class="s2">&#34;Hello World&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">b</span><span class="o">.</span><span class="n">p</span> <span class="s2">&#34;This is a paragraph.&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">b</span><span class="o">.</span><span class="n">table</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">      <span class="n">t</span><span class="o">.</span><span class="n">tr</span> <span class="k">do</span> <span class="o">|</span><span class="n">tr</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">        <span class="n">tr</span><span class="o">.</span><span class="n">td</span> <span class="s2">&#34;column&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="k">end</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E cheguei neste equivalente em Objective-C:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="n">XmlBuilder</span><span class="o">*</span> <span class="n">xml</span> <span class="o">=</span> <span class="p">[[</span><span class="n">XmlBuilder</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="n">xml</span> <span class="nl">htmlBlock</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="n">XmlBuilder</span><span class="o">*</span> <span class="n">h</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">[</span><span class="n">h</span> <span class="nl">bodyBlock</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="n">XmlBuilder</span><span class="o">*</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="p">[</span><span class="n">b</span> <span class="nl">h1</span><span class="p">:</span><span class="err">@</span><span class="s">&#34;Hello World&#34;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="p">[</span><span class="n">b</span> <span class="nl">p</span><span class="p">:</span><span class="err">@</span><span class="s">&#34;This is a paragraph.&#34;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="p">[</span><span class="n">b</span> <span class="nl">tableBlock</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="n">XmlBuilder</span><span class="o">*</span> <span class="n">t</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="n">t</span> <span class="nl">trBlock</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="n">XmlBuilder</span><span class="o">*</span> <span class="n">tr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="p">[</span><span class="n">tr</span> <span class="nl">td</span><span class="p">:</span><span class="err">@</span><span class="s">&#34;column&#34;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">            <span class="p">}];</span>
</span></span><span class="line"><span class="cl">        <span class="p">}];</span>            
</span></span><span class="line"><span class="cl">    <span class="p">}];</span>
</span></span><span class="line"><span class="cl"><span class="p">}];</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Absolutamente verborrágico! Não era divertido usar blocos em Objective-C pela quantidade de delimitadores com chaves, parênteses, colchetes. Em Ruby é bem mais simples porque parênteses são todos opcionais e blocos são delimitados quase como métodos.</p>
<p>Ainda não reimplementei esse experimento que fiz em Objective-C para Swift (fica como lição de casa). Farei isso num próximo artigo sobre metaprogramação e seletores em Swift. Mas se tivéssemos reescrito, provavelmente o código ficaria mais ou menos assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="c1">// Swift:                            // Ruby:
</span></span></span><span class="line"><span class="cl"><span class="n">xml</span> <span class="o">=</span> <span class="nf">XmlBuilder</span><span class="p">()</span>                   <span class="c1">// x = Builder::XmlMarkup.new
</span></span></span><span class="line"><span class="cl"><span class="n">xml</span><span class="p">.</span><span class="nf">html</span><span class="p">({</span> <span class="p">(</span><span class="n">var</span> <span class="n">h</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Void</span> <span class="n">in</span>        <span class="c1">// x.html do |h|
</span></span></span><span class="line"><span class="cl">    <span class="n">h</span><span class="p">.</span><span class="nf">body</span><span class="p">({</span> <span class="p">(</span><span class="n">var</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Void</span> <span class="n">in</span>      <span class="c1">//   h.body do |b|
</span></span></span><span class="line"><span class="cl">        <span class="n">b</span><span class="p">.</span><span class="nf">h1</span><span class="p">(</span><span class="s">&#34;Hello World&#34;</span><span class="p">)</span>          <span class="c1">//     b.h1 &#34;Hello World&#34;
</span></span></span><span class="line"><span class="cl">        <span class="n">b</span><span class="p">.</span><span class="nf">p</span><span class="p">(</span><span class="s">&#34;This is a paragraph&#34;</span><span class="p">)</span>   <span class="c1">//     b.p &#34;This is a paragraph.&#34;
</span></span></span><span class="line"><span class="cl">        <span class="n">b</span><span class="p">.</span><span class="nf">table</span><span class="p">({</span> <span class="p">(</span><span class="n">var</span> <span class="n">t</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Void</span> <span class="n">in</span> <span class="c1">//     b.table do |t|
</span></span></span><span class="line"><span class="cl">            <span class="n">t</span><span class="p">.</span><span class="nf">tr</span><span class="p">({</span> <span class="p">(</span><span class="n">var</span> <span class="n">tr</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Void</span>  <span class="c1">//       t.tr do |tr|
</span></span></span><span class="line"><span class="cl">                <span class="n">tr</span><span class="p">.</span><span class="nf">td</span><span class="p">(</span><span class="s">&#34;column&#34;</span><span class="p">)</span>      <span class="c1">//         tr.td &#34;column&#34;
</span></span></span><span class="line"><span class="cl">            <span class="p">})</span>                       <span class="c1">//       end
</span></span></span><span class="line"><span class="cl">        <span class="p">})</span>                           <span class="c1">//     end
</span></span></span><span class="line"><span class="cl">    <span class="p">})</span>                               <span class="c1">//   end
</span></span></span><span class="line"><span class="cl"><span class="p">})</span>                                   <span class="c1">// end
</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Veja que comparado à versão em Objective-C é &ldquo;muito&rdquo; melhor. Mesmo assim, se comparado ao que fazemos em Ruby, continua sendo mais verboso do que gostaríamos por causa dos parênteses obrigatórios e declaração de tipos das funções, mas agora sim fica muito mais prático ver que podemos fazer DSLs em Swift também.</p>
<p>Isso deve dar uma luz sobre como a nova sintaxe do Swift é de fato um real ganho de legibilidade e produtividade para programadores acostumados a Objective-C e como nós, de Ruby, podemos rapidamente nos adaptar a essa nova linguagem para produzir bibliotecas e frameworks. Uma vantagem do Swift é que ele é imediatamente compatível com toda a API escrita em Objective-C, portanto onde antes era chato escrever as closures, agora fica imediatamente mais simples.</p>
]]></content:encoded><category>linguagens-de-programacao</category><category>apple</category><category>aprendizado</category></item><item><title>Swift para Rubistas, Rápida Introdução</title><link>https://akitaonrails.github.io/2014/06/03/swift-para-rubistas-rapida-introducao/</link><guid isPermaLink="true">https://akitaonrails.github.io/2014/06/03/swift-para-rubistas-rapida-introducao/</guid><pubDate>Tue, 03 Jun 2014 17:01:00 -0300</pubDate><description>&lt;p&gt;Como vocês devem ter assistido no keynote de abertura da &lt;a href="http://startupi.com.br/2014/apple-esta-retornando-suas-formas-jobs-ficaria-orgulhoso/"target="_blank" rel="noopener"&gt;WWDC 2014&lt;/a&gt;, a Apple lançou uma nova linguagem, mais moderna, para substituir o Objective-C como linguagem padrão para desenvolvimento de aplicações tanto OS X quanto iOS. Não se trata de uma nova &amp;ldquo;camada&amp;rdquo; mas uma linguagem que tecnicamente compila para o mesmo tipo de binário que o próprio Objective-C e mesmo C. Graças ao compilador que é implementado sobre LLVM isso se torna possível.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Como vocês devem ter assistido no keynote de abertura da <a href="http://startupi.com.br/2014/apple-esta-retornando-suas-formas-jobs-ficaria-orgulhoso/"target="_blank" rel="noopener">WWDC 2014</a>, a Apple lançou uma nova linguagem, mais moderna, para substituir o Objective-C como linguagem padrão para desenvolvimento de aplicações tanto OS X quanto iOS. Não se trata de uma nova &ldquo;camada&rdquo; mas uma linguagem que tecnicamente compila para o mesmo tipo de binário que o próprio Objective-C e mesmo C. Graças ao compilador que é implementado sobre LLVM isso se torna possível.</p>
<p>A linguagem Swift é um Objective-C com funcionalidades mais modernas e uma sintaxe mais elegante e menos verbosa. Já havia <a href="http://www.akitaonrails.com/Objective-C"target="_blank" rel="noopener">publicado neste blog</a> anos atrás como o Objective-C e Ruby tem conceitos muito similares. E isso se deve à herança comum da linguagem Smalltalk.</p>
<p>Antes que algum afobado comece a trolar: o artigo não tem como objetivo dizer que Swift tem inspiração em Ruby ou que Ruby tem algum tipo de relação com Swift. Apenas aproveitando o fato de terem origens similares e funcionalidades que fazem sua programação ser próxima, quero usar o artigo para mostrar a rubistas algumas nuances do Swift.</p>
<p>Todos os exemplos de código foram extraídos do eBook <a href="https://itun.es/us/jEUH0.l"target="_blank" rel="noopener">“The Swift Programming Language.”</a> que é uma boa introdução à linguagem. Mas para realmente tirar proveito é melhor conhecer a fundo Objective-C, C e obviamente, toda a documentação de APIs dos frameworks para iOS e OS X.</p>
<h2>Exemplos de Sintaxe<span class="hx:absolute hx:-mt-20" id="exemplos-de-sintaxe"></span>
    <a href="#exemplos-de-sintaxe" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Do ponto de vista da sintaxe, a linguagem está bem mais atraente. Vejamos um trecho muito simples em Swift:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="k">if</span> <span class="n">let</span> <span class="n">actualNumber</span> <span class="o">=</span> <span class="n">possibleNumber</span><span class="p">.</span><span class="nf">toInt</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">println</span><span class="p">(</span><span class="s">&#34;\(possibleNumber) has an integer value of \(actualNumber)&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">println</span><span class="p">(</span><span class="s">&#34;\(possibleNumber) could not be converted to an integer&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// prints &#34;123 has an integer value of 123&#34;
</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E em Ruby:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">if</span> <span class="n">actual_number</span> <span class="o">=</span> <span class="n">possible_number</span> <span class="o">&amp;&amp;</span> <span class="n">possible_number</span><span class="o">.</span><span class="n">to_i</span>
</span></span><span class="line"><span class="cl">  <span class="nb">puts</span> <span class="s2">&#34;</span><span class="si">#{</span><span class="n">possible_number</span><span class="si">}</span><span class="s2"> has an integer value of </span><span class="si">#{</span><span class="n">actual_number</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span>
</span></span><span class="line"><span class="cl">  <span class="nb">puts</span> <span class="s2">&#34;</span><span class="si">#{</span><span class="n">possible_number</span><span class="si">}</span><span class="s2"> could not be converted to an integer&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="c1"># prints &#34;123 has an integer value of 123&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Statements como &ldquo;if&rdquo; ou &ldquo;for&rdquo; não tem parênteses como em C, embora cada seção ainda seja separado por chaves &ldquo;{}&rdquo;. Visualmente falando a diferença é bem pequena. Interpolação em strings tem uma sintaxe um pouco diferente mas no geral é muito semelhante.</p>
<p>As convenções de nomenclatura são diferentes: no Ruby usamos tudo em caixa baixa separado por underline e Swift ainda tem a herança de Objective-C de camel casing. Além disso Swift identa código com 4 espaços e Ruby com 2.</p>
<p>Vejamos outro exemplo em Swift:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="n">func</span> <span class="nf">alignRight</span><span class="p">(</span><span class="n">var</span> <span class="nl">string</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span> <span class="nl">count</span><span class="p">:</span> <span class="n">Int</span><span class="p">,</span> <span class="nl">pad</span><span class="p">:</span> <span class="n">Character</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">String</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">let</span> <span class="n">amountToPad</span> <span class="o">=</span> <span class="n">count</span> <span class="o">-</span> <span class="nf">countElements</span><span class="p">(</span><span class="n">string</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">_</span> <span class="n">in</span> <span class="mf">1.</span><span class="p">..</span><span class="n">amountToPad</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">string</span> <span class="o">=</span> <span class="n">pad</span> <span class="o">+</span> <span class="n">string</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">string</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">let</span> <span class="n">originalString</span> <span class="o">=</span> <span class="s">&#34;hello&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">let</span> <span class="n">paddedString</span> <span class="o">=</span> <span class="nf">alignRight</span><span class="p">(</span><span class="n">originalString</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="s">&#34;-&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">// paddedString is equal to &#34;-----hello&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1">// originalString is still equal to &#34;hello&#34;
</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E o equivalente em Ruby seria:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">align_right</span><span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="n">count</span><span class="p">,</span> <span class="n">pad</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">amount_to_pad</span> <span class="o">=</span> <span class="n">count</span> <span class="o">-</span> <span class="n">string</span><span class="o">.</span><span class="n">size</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="mi">1</span><span class="o">..</span><span class="n">amount_to_pad</span><span class="p">)</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="n">string</span> <span class="o">=</span> <span class="n">pad</span> <span class="o">+</span> <span class="n">string</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="n">string</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="n">original_string</span> <span class="o">=</span> <span class="s2">&#34;hello&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">padded_string</span> <span class="o">=</span> <span class="n">align_right</span><span class="p">(</span><span class="n">original_string</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="s2">&#34;-&#34;</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>A primeira semelhança é que Swift possui &ldquo;Ranges&rdquo; como em Ruby embora a notação seja oposta. Usamos &ldquo;..&rdquo; em Ruby para um range que inclui ambos os números extremos e &ldquo;&hellip;&rdquo; (3 pontos) para não incluir o último número. Em Swift é o contrário.</p>
<p>Em Swift, o correto é declarar os tipos dos argumentos e do valor de retorno e o &ldquo;return&rdquo; é explícito. No Ruby não tempos tipos pré-declarados e o retorno padrão é sempre o valor da última coisa executada. E falando em Ranges, tanto em Ruby quanto Swift podemos ter pattern matching de valores em intervalos:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="n">let</span> <span class="n">count</span> <span class="o">=</span> <span class="mi">3</span><span class="n">_000_000_000_000</span>
</span></span><span class="line"><span class="cl"><span class="n">let</span> <span class="n">countedThings</span> <span class="o">=</span> <span class="s">&#34;stars in the Milky Way&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">var</span> <span class="nl">naturalCount</span><span class="p">:</span> <span class="n">String</span>
</span></span><span class="line"><span class="cl"><span class="k">switch</span> <span class="n">count</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">case</span> <span class="mi">0</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">naturalCount</span> <span class="o">=</span> <span class="s">&#34;no&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">case</span> <span class="mf">1.</span><span class="p">.</span><span class="mf">.3</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">naturalCount</span> <span class="o">=</span> <span class="s">&#34;a few&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">case</span> <span class="mf">4.</span><span class="p">.</span><span class="mf">.9</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">naturalCount</span> <span class="o">=</span> <span class="s">&#34;several&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">case</span> <span class="mf">10.</span><span class="p">.</span><span class="mf">.99</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">naturalCount</span> <span class="o">=</span> <span class="s">&#34;tens of&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">case</span> <span class="mf">100.</span><span class="p">.</span><span class="mf">.999</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">naturalCount</span> <span class="o">=</span> <span class="s">&#34;hundreds of&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">case</span> <span class="mf">1000.</span><span class="p">.</span><span class="mf">.999</span><span class="nl">_999</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">naturalCount</span> <span class="o">=</span> <span class="s">&#34;thousands of&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">default</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">naturalCount</span> <span class="o">=</span> <span class="s">&#34;millions and millions of&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nf">println</span><span class="p">(</span><span class="s">&#34;There are \(naturalCount) \(countedThings).&#34;</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Em Ruby é praticamente a mesma coisa:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">count</span> <span class="o">=</span> <span class="mi">3_000_000_000_000</span>
</span></span><span class="line"><span class="cl"><span class="n">counted_things</span> <span class="o">=</span> <span class="s2">&#34;stars in the Milky Way&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">natural_count</span> <span class="o">=</span> <span class="k">case</span> <span class="n">count</span>
</span></span><span class="line"><span class="cl"><span class="k">when</span> <span class="mi">0</span> <span class="k">then</span> <span class="s2">&#34;no&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">when</span> <span class="mi">1</span><span class="o">..</span><span class="mi">3</span> <span class="k">then</span> <span class="s2">&#34;a few&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">when</span> <span class="mi">4</span><span class="o">..</span><span class="mi">9</span> <span class="k">then</span> <span class="s2">&#34;several&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">when</span> <span class="mi">10</span><span class="o">..</span><span class="mi">99</span> <span class="k">then</span> <span class="s2">&#34;tens of&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">when</span> <span class="mi">100</span><span class="o">..</span><span class="mi">999</span> <span class="k">then</span> <span class="s2">&#34;hundreds of&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">when</span> <span class="mi">1000</span><span class="o">..</span><span class="mi">999_999</span> <span class="k">then</span> <span class="s2">&#34;thousands of&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;millions and millions of&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="nb">puts</span> <span class="s2">&#34;There are </span><span class="si">#{</span><span class="n">natural_count</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">counted_things</span><span class="si">}</span><span class="s2">.&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Swift e Ruby não precisam de &ldquo;break&rdquo; porque ele não cai para o próximo match. Ambos tem capacidade de comparar não só valores mas intervalos ou outros elementos. No caso, como Ruby tem return por default, não precisamos repetir a variável &ldquo;natural_count&rdquo; em cada ítem e o resultado geral do &ldquo;case&rdquo; vai para a única atribuição no topo.</p>
<p>Este outro trecho também é curioso:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="k">if</span> <span class="n">let</span> <span class="n">roomCount</span> <span class="o">=</span> <span class="n">john</span><span class="p">.</span><span class="n">residence</span><span class="o">?</span><span class="p">.</span><span class="n">numberOfRooms</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">println</span><span class="p">(</span><span class="s">&#34;John&#39;s residence has \(roomCount) room(s).&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">println</span><span class="p">(</span><span class="s">&#34;Unable to retrieve the number of rooms.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// prints &#34;Unable to retrieve the number of rooms.&#34;
</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O &ldquo;equivalente&rdquo; em Ruby (se estivermos no Rails) seria:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">if</span> <span class="n">room_count</span> <span class="o">=</span> <span class="n">john</span><span class="o">.</span><span class="n">residence</span><span class="o">.</span><span class="n">try</span><span class="p">(</span><span class="ss">:number_of_rooms</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nb">puts</span> <span class="s2">&#34;John&#39;s residence has </span><span class="si">#{</span><span class="n">room_count</span><span class="si">}</span><span class="s2"> room(s).&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span>
</span></span><span class="line"><span class="cl">  <span class="nb">puts</span> <span class="s2">&#34;Unable to retrieve the number of rooms.&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Não é exatamente a mesma coisa. No Swift o &ldquo;?&rdquo; denota uma propriedade opcional e enviar uma mensagem a um objeto opcional devolve &ldquo;nil&rdquo;. Na prática é quase a mesma coisa que o método <a href="http://guides.rubyonrails.org/active_support_core_extensions.html#try"target="_blank" rel="noopener">#try</a> do ActiveSupport do Rails.</p>
<p>E falando em ActiveSupport o Swift herda <a href="http://code.tutsplus.com/tutorials/objective-c-succinctly-categories-and-extensions--mobile-22016"target="_blank" rel="noopener">Categories</a> de Objective-C com o nome de Extensions, que é uma forma de estender a funcionalidade de uma classe que já existe:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="n">extension</span> <span class="n">Double</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">var</span> <span class="nl">km</span><span class="p">:</span> <span class="n">Double</span> <span class="p">{</span> <span class="k">return</span> <span class="n">self</span> <span class="o">*</span> <span class="mi">1</span><span class="n">_000</span><span class="mf">.0</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">var</span> <span class="nl">m</span><span class="p">:</span> <span class="n">Double</span> <span class="p">{</span> <span class="k">return</span> <span class="n">self</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">var</span> <span class="nl">cm</span><span class="p">:</span> <span class="n">Double</span> <span class="p">{</span> <span class="k">return</span> <span class="n">self</span> <span class="o">/</span> <span class="mf">100.0</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">var</span> <span class="nl">mm</span><span class="p">:</span> <span class="n">Double</span> <span class="p">{</span> <span class="k">return</span> <span class="n">self</span> <span class="o">/</span> <span class="mi">1</span><span class="n">_000</span><span class="mf">.0</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">var</span> <span class="nl">ft</span><span class="p">:</span> <span class="n">Double</span> <span class="p">{</span> <span class="k">return</span> <span class="n">self</span> <span class="o">/</span> <span class="mf">3.28084</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">let</span> <span class="n">oneInch</span> <span class="o">=</span> <span class="mf">25.4</span><span class="p">.</span><span class="n">mm</span>
</span></span><span class="line"><span class="cl"><span class="nf">println</span><span class="p">(</span><span class="s">&#34;One inch is \(oneInch) meters&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">// prints &#34;One inch is 0.0254 meters&#34;
</span></span></span><span class="line"><span class="cl"><span class="n">let</span> <span class="n">threeFeet</span> <span class="o">=</span> <span class="mf">3.f</span><span class="n">t</span>
</span></span><span class="line"><span class="cl"><span class="nf">println</span><span class="p">(</span><span class="s">&#34;Three feet is \(threeFeet) meters&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">// prints &#34;Three feet is 0.914399970739201 meters&#34;
</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Em Ruby podemos facilmente fazer a mesma coisa diretamente porque classes são sempre abertas:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Numeric</span>
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nf">km</span><span class="p">;</span> <span class="nb">self</span> <span class="o">*</span> <span class="mi">1_000</span><span class="o">.</span><span class="mi">0</span><span class="p">;</span> <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nf">m</span><span class="p">;</span> <span class="nb">self</span><span class="p">;</span> <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nf">cm</span><span class="p">;</span> <span class="nb">self</span> <span class="o">/</span> <span class="mi">100</span><span class="o">.</span><span class="mi">0</span><span class="p">;</span> <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nf">mm</span><span class="p">;</span> <span class="nb">self</span> <span class="o">/</span> <span class="mi">1_000</span><span class="o">.</span><span class="mi">0</span><span class="p">;</span> <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nf">ft</span><span class="p">;</span> <span class="nb">self</span> <span class="o">/</span> <span class="mi">3</span><span class="o">.</span><span class="mi">28084</span><span class="p">;</span> <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">one_inch</span> <span class="o">=</span> <span class="mi">25</span><span class="o">.</span><span class="mi">4</span><span class="o">.</span><span class="n">mm</span>
</span></span><span class="line"><span class="cl"><span class="nb">puts</span> <span class="s2">&#34;One inch is </span><span class="si">#{</span><span class="n">one_inch</span><span class="si">}</span><span class="s2"> meters&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">three_feet</span> <span class="o">=</span> <span class="mi">3</span><span class="o">.</span><span class="n">ft</span>
</span></span><span class="line"><span class="cl"><span class="nb">puts</span> <span class="s2">&#34;Three feet is </span><span class="si">#{</span><span class="n">three_feet</span><span class="si">}</span><span class="s2"> meters&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Novamente, o resultado é similar mas os princípios são diferentes. A começar que no caso do Ruby estou abrindo a classe que é pai de todos os números, não só dos Floats (Doubles), caso contrário o segundo exemplo que é um Integer não funciona (&ldquo;3.ft&rdquo;, teria que ser explicitamente &ldquo;3.0.ft&rdquo;).</p>
<p>Além disso no Swift ele declara uma variável de processamento dinâmico. Nas semelhanças veja que tanto Swift quanto Ruby usam &ldquo;self&rdquo; para se referir ao objeto interno. Ambos permitem usar a notação de underline para delimitar milhares (&ldquo;1_000&rdquo;, por exemplo).</p>
<p>Um outro exemplo mais prático em Swift seria este:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="n">extension</span> <span class="n">Int</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">func</span> <span class="nf">repetitions</span><span class="p">(</span><span class="nl">task</span><span class="p">:</span> <span class="p">()</span> <span class="o">-&gt;</span> <span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">i</span> <span class="n">in</span> <span class="mf">0.</span><span class="p">.</span><span class="n">self</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nf">task</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="mf">3.</span><span class="nf">repetitions</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="nf">println</span><span class="p">(</span><span class="s">&#34;Hello!&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="c1">// Hello!
</span></span></span><span class="line"><span class="cl"><span class="c1">// Hello!
</span></span></span><span class="line"><span class="cl"><span class="c1">// Hello!
</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E em Ruby já temos o equivalente ao método &ldquo;repetitions&rdquo; desta extension já implementada:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="mi">3</span><span class="o">.</span><span class="n">times</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="nb">puts</span> <span class="s2">&#34;Hello!&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Em particular veja que o Swift define um método que recebe uma função anônima, um bloco propriamente dito. Ele passa esse bloco entre chaves como parâmetro do método. É o equivalente no Ruby que passamos o bloco também entre chaves ou entre &ldquo;do; end&rdquo;.</p>
<p>Outras coisas que lembram muito Ruby é como ele trata tipos de coleções:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="n">var</span> <span class="n">shoppingList</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#34;Eggs&#34;</span><span class="p">,</span> <span class="s">&#34;Milk&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">shoppingList</span> <span class="o">+=</span> <span class="p">[</span><span class="s">&#34;Chocolate Spread&#34;</span><span class="p">,</span> <span class="s">&#34;Cheese&#34;</span><span class="p">,</span> <span class="s">&#34;Butter&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">shoppingList</span><span class="p">[</span><span class="mf">4.</span><span class="p">.</span><span class="mf">.6</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#34;Bananas&#34;</span><span class="p">,</span> <span class="s">&#34;Apples&#34;</span><span class="p">]</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Esse trecho quase que inteiramente se converte em como Ruby lida com arrays:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">shopping_list</span> <span class="o">=</span> <span class="o">[</span><span class="s2">&#34;Eggs&#34;</span><span class="p">,</span> <span class="s2">&#34;Milk&#34;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="n">shopping_list</span> <span class="o">+=</span> <span class="o">[</span><span class="s2">&#34;Chocolate Spread&#34;</span><span class="p">,</span> <span class="s2">&#34;Cheese&#34;</span><span class="p">,</span> <span class="s2">&#34;Butter&#34;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="n">shopping_list</span><span class="o">[</span><span class="mi">4</span><span class="o">...</span><span class="mi">6</span><span class="o">]</span> <span class="o">=</span> <span class="o">[</span><span class="s2">&#34;Bananas&#34;</span><span class="p">,</span> <span class="s2">&#34;Apples&#34;</span><span class="o">]</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O mesmo pode-se dizer de dicionários do Swift que são semelhantes a Hash no Ruby:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="n">var</span> <span class="n">airports</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#34;TYO&#34;</span><span class="o">:</span> <span class="s">&#34;Tokyo&#34;</span><span class="p">,</span> <span class="s">&#34;DUB&#34;</span><span class="o">:</span> <span class="s">&#34;Dublin&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">airports</span><span class="p">[</span><span class="s">&#34;LHR&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="s">&#34;London&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="n">airportCode</span><span class="p">,</span> <span class="n">airportName</span><span class="p">)</span> <span class="n">in</span> <span class="n">airports</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">println</span><span class="p">(</span><span class="s">&#34;\(airportCode): \(airportName)&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Em Ruby seria:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">airports</span> <span class="o">=</span> <span class="p">{</span><span class="ss">TYO</span><span class="p">:</span> <span class="s2">&#34;Tokyo&#34;</span><span class="p">,</span> <span class="ss">DUB</span><span class="p">:</span> <span class="s2">&#34;Dublin&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">airports</span><span class="o">[</span><span class="ss">:LHR</span><span class="o">]</span> <span class="o">=</span> <span class="s2">&#34;London&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">airport_code</span><span class="p">,</span> <span class="n">airport_name</span> <span class="k">in</span> <span class="n">airports</span>
</span></span><span class="line"><span class="cl">  <span class="nb">puts</span> <span class="s2">&#34;</span><span class="si">#{</span><span class="n">airport_code</span><span class="si">}</span><span class="s2">: </span><span class="si">#{</span><span class="n">airport_name</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Em particular este último trecho, em Ruby, seria mais comumente escrito como:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">airports</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">airport_code</span><span class="p">,</span> <span class="n">airport_name</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">  <span class="nb">puts</span> <span class="s2">&#34;</span><span class="si">#{</span><span class="n">airport_code</span><span class="si">}</span><span class="s2">: </span><span class="si">#{</span><span class="n">airport_name</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>A diferença é que Swift inicializa dicionários com a mesma sintaxe de arrays, com colchetes. Em Ruby diferenciamos arrays com colchetes e hashes com chaves. Além disso é comum usar chaves como strings em Swift e Objective-C pois eles são imutáveis por padrão. Em Ruby strings são tecnicamente mutáveis e o equivalente a uma &ldquo;string imutável&rdquo; em Ruby são symbols. Ao ser interpolado dentro de uma string, um symbol automaticamente se converte em string.</p>
<p>Já um tipo que Swift e outras linguagens como Python tem, e Ruby não tem, são Tuples. De forma simplificada, se trata de uma lista heterogênea (como um array) de constantes. Em Ruby usamos um Array para o mesmo fim. E temos, novamente, usos similares:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="n">let</span> <span class="n">http404Error</span> <span class="o">=</span> <span class="p">(</span><span class="mi">404</span><span class="p">,</span> <span class="s">&#34;Not Found&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">let</span> <span class="p">(</span><span class="n">statusCode</span><span class="p">,</span> <span class="n">statusMessage</span><span class="p">)</span> <span class="o">=</span> <span class="n">http404Error</span>
</span></span><span class="line"><span class="cl"><span class="nf">println</span><span class="p">(</span><span class="s">&#34;The status code is \(statusCode)&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">// prints &#34;The status code is 404&#34;
</span></span></span><span class="line"><span class="cl"><span class="nf">println</span><span class="p">(</span><span class="s">&#34;The status message is \(statusMessage)&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">// prints &#34;The status message is Not Found&#34;
</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Veja que podemos decompor um Tuple de volta em variáveis de maneira similar em Ruby:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">http_404_error</span> <span class="o">=</span> <span class="o">[</span><span class="mi">404</span><span class="p">,</span> <span class="s2">&#34;Not Found&#34;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="n">status_code</span><span class="p">,</span> <span class="n">status_message</span> <span class="o">=</span> <span class="n">http_404_error</span>
</span></span><span class="line"><span class="cl"><span class="nb">puts</span> <span class="s2">&#34;The status code is </span><span class="si">#{</span><span class="n">status_code</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">puts</span> <span class="s2">&#34;The status message is </span><span class="si">#{</span><span class="n">status_message</span><span class="si">}</span><span class="s2">&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h2>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Isso foi apenas um rápido &ldquo;tour&rdquo; sobre as partes mais superficiais da linguagem. Swift ainda tem:</p>
<ul>
<li>tipos Enum (diferente de funcionalidades de Enumeration do Ruby, não confundir)</li>
<li>propriedades (getter, setter, weak references, etc)</li>
<li>inicialização, deinicialização, ARC (procedimentos para automatic reference counting)</li>
<li>tipos (type casting, nested types, generics, extensions, protocols)</li>
</ul>
<p>Diferente de linguagens como Go ou Scala, ela não tem diretamente na linguagem nenhuma construção para abstrair atores ou outras coisas de concorrência. Isso porque no Objective-C e no Swift vamos subir para o nível dos frameworks, em particular para o <a href="https://developer.apple.com/library/mac/documentation/performance/reference/gcd_libdispatch_ref/Reference/reference.html"target="_blank" rel="noopener">Grand Central Dispatch</a> que basicamente funciona como um sistema de filas de processamento.</p>
<p>Como podem ver, Swift em si é uma linguagem bem minimalista. Sua intenção é ser um &ldquo;sugar coating&rdquo; sobre a cansada sintaxe do Objective-C, a cansativa rotina de lidar com arquivos de header e implementação, declaração estática de tipos em todos os lugares. Mas o que a linguagem não tem como &ldquo;consertar&rdquo; é a extensiva quantidade de APIs do Cocoa. Não se engane, é tudo muito bem organizado e consistente, diferente de outras plataformas.</p>
<p>Por exemplo, hoje (1 dia depois do anúncio da linguagem, para verem como a sintaxe é trivial de simples) já saiu um pequeno demo que é basicamente um <a href="https://github.com/fullstackio/FlappySwift"target="_blank" rel="noopener">clone do famigerado Flappy Bird</a>, usando o SpriteKit como fundação. E veja um trecho mais realista:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="c1">// skyline
</span></span></span><span class="line"><span class="cl"><span class="n">var</span> <span class="n">skyTexture</span> <span class="o">=</span> <span class="nf">SKTexture</span><span class="p">(</span><span class="nl">imageNamed</span><span class="p">:</span> <span class="s">&#34;sky&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">skyTexture</span><span class="p">.</span><span class="n">filteringMode</span> <span class="o">=</span> <span class="n">SKTextureFilteringMode</span><span class="p">.</span><span class="n">Nearest</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">var</span> <span class="n">moveSkySprite</span> <span class="o">=</span> <span class="n">SKAction</span><span class="p">.</span><span class="nf">moveByX</span><span class="p">(</span><span class="o">-</span><span class="n">skyTexture</span><span class="p">.</span><span class="nf">size</span><span class="p">().</span><span class="n">width</span> <span class="o">*</span> <span class="mf">2.0</span><span class="p">,</span> <span class="nl">y</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="nl">duration</span><span class="p">:</span> <span class="nf">NSTimeInterval</span><span class="p">(</span><span class="mf">0.1</span> <span class="o">*</span> <span class="n">skyTexture</span><span class="p">.</span><span class="nf">size</span><span class="p">().</span><span class="n">width</span> <span class="o">*</span> <span class="mf">2.0</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">var</span> <span class="n">resetSkySprite</span> <span class="o">=</span> <span class="n">SKAction</span><span class="p">.</span><span class="nf">moveByX</span><span class="p">(</span><span class="n">skyTexture</span><span class="p">.</span><span class="nf">size</span><span class="p">().</span><span class="n">width</span> <span class="o">*</span> <span class="mf">2.0</span><span class="p">,</span> <span class="nl">y</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="nl">duration</span><span class="p">:</span> <span class="mf">0.0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">var</span> <span class="n">moveSkySpritesForever</span> <span class="o">=</span> <span class="n">SKAction</span><span class="p">.</span><span class="nf">repeatActionForever</span><span class="p">(</span><span class="n">SKAction</span><span class="p">.</span><span class="nf">sequence</span><span class="p">([</span><span class="n">moveSkySprite</span><span class="p">,</span><span class="n">resetSkySprite</span><span class="p">]))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">var</span> <span class="nl">i</span><span class="p">:</span><span class="n">CGFloat</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mf">2.0</span> <span class="o">+</span> <span class="n">self</span><span class="p">.</span><span class="n">frame</span><span class="p">.</span><span class="n">size</span><span class="p">.</span><span class="n">width</span> <span class="o">/</span> <span class="p">(</span> <span class="n">skyTexture</span><span class="p">.</span><span class="nf">size</span><span class="p">().</span><span class="n">width</span> <span class="o">*</span> <span class="mf">2.0</span> <span class="p">);</span> <span class="o">++</span><span class="n">i</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">var</span> <span class="n">sprite</span> <span class="o">=</span> <span class="nf">SKSpriteNode</span><span class="p">(</span><span class="nl">texture</span><span class="p">:</span> <span class="n">skyTexture</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">sprite</span><span class="p">.</span><span class="nf">setScale</span><span class="p">(</span><span class="mf">2.0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">sprite</span><span class="p">.</span><span class="n">zPosition</span> <span class="o">=</span> <span class="o">-</span><span class="mi">20</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">sprite</span><span class="p">.</span><span class="n">position</span> <span class="o">=</span> <span class="nf">CGPointMake</span><span class="p">(</span><span class="n">i</span> <span class="o">*</span> <span class="n">sprite</span><span class="p">.</span><span class="n">size</span><span class="p">.</span><span class="n">width</span><span class="p">,</span> <span class="n">sprite</span><span class="p">.</span><span class="n">size</span><span class="p">.</span><span class="n">height</span> <span class="o">/</span> <span class="mf">2.0</span> <span class="o">+</span> <span class="n">groundTexture</span><span class="p">.</span><span class="nf">size</span><span class="p">().</span><span class="n">height</span> <span class="o">*</span> <span class="mf">2.0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">sprite</span><span class="p">.</span><span class="nf">runAction</span><span class="p">(</span><span class="n">moveSkySpritesForever</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">self</span><span class="p">.</span><span class="nf">addChild</span><span class="p">(</span><span class="n">sprite</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Não é nada do outro mundo, só precisa se acostumar com as APIs. A documentação da Apple é muito bem feita e fácil de usar.</p>
]]></content:encoded><category>linguagens-de-programacao</category><category>apple</category><category>aprendizado</category></item><item><title>[Off-Topic] Steve Jobs, The Lost Inverview</title><link>https://akitaonrails.github.io/2012/07/08/off-topic-steve-jobs-the-lost-inverview/</link><guid isPermaLink="true">https://akitaonrails.github.io/2012/07/08/off-topic-steve-jobs-the-lost-inverview/</guid><pubDate>Sun, 08 Jul 2012 20:43:00 -0300</pubDate><description>&lt;p&gt;Quem acompanha o mundo Mac já deve ter visto que uma entrevista antiga, dada por Steve Jobs em 1995 e tida como perdida, apareceu numa fita VHS, foi restaurada e virou o documentário &lt;em&gt;Steve Jobs: The Lost Interview&lt;/em&gt;. Agora dá para alugar no &lt;a href="http://itunes.apple.com/us/movie/steve-jobs-the-lost-interview/id536749587"target="_blank" rel="noopener"&gt;iTunes Store&lt;/a&gt;, entre outras fontes mais “geeky”, se preferir.&lt;/p&gt;
&lt;p&gt;Para quem já leu e assistiu tudo que saiu sobre Jobs, a maior parte dela não traz novidade. O interessante é ver ele mesmo dizendo essas palavras. Gostei de rever a forma como ele pensa sobre produtos, sobre gerenciar empresas e gerenciar pessoas, porque penso do mesmo jeito e gosto de trabalhar ao lado de quem também pensa assim.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Quem acompanha o mundo Mac já deve ter visto que uma entrevista antiga, dada por Steve Jobs em 1995 e tida como perdida, apareceu numa fita VHS, foi restaurada e virou o documentário <em>Steve Jobs: The Lost Interview</em>. Agora dá para alugar no <a href="http://itunes.apple.com/us/movie/steve-jobs-the-lost-interview/id536749587"target="_blank" rel="noopener">iTunes Store</a>, entre outras fontes mais “geeky”, se preferir.</p>
<p>Para quem já leu e assistiu tudo que saiu sobre Jobs, a maior parte dela não traz novidade. O interessante é ver ele mesmo dizendo essas palavras. Gostei de rever a forma como ele pensa sobre produtos, sobre gerenciar empresas e gerenciar pessoas, porque penso do mesmo jeito e gosto de trabalhar ao lado de quem também pensa assim.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2012/7/8/Screen%20Shot%202012-07-08%20at%208.41.47%20PM_original.png" alt=""  loading="lazy" /></p>
<p>Dito isso, vamos às palavras do próprio Steve Jobs:</p>
<h2>Entrevista Perdida, faltando 37:15min<span class="hx:absolute hx:-mt-20" id="entrevista-perdida-faltando-3715min"></span>
    <a href="#entrevista-perdida-faltando-3715min" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><strong>Entrevistador:</strong> O que sempre aparece é sua paixão, sua visão. Como você organiza suas prioridades? O que é importante para você no desenvolvimento de um produto?</p>
<p><strong>Steve:</strong> (depois de longa pausa) Uma das coisas que machucou a Apple depois que eu saí foi que John Sculley pegou uma doença séria. E essa doença – e eu vi outras pessoas pegarem também – é a doença de pensar que uma grande ideia é 90% do trabalho. E se você simplesmente disser às pessoas <em>“essa é a grande ideia”</em>, então é óbvio que agora elas podem simplesmente e facilmente implementar essa idéia. E o problema com isso é que existe uma tremenda quantidade de habilidade e perícia (“craftsmanship”) entre uma grande idéia e um grande produto. E à medida que você evolui essa grande idéia, ela muda e cresce, nunca sai como você imaginou no começo, porque você aprende muito mais à medida que entra nas sutilezas.</p>
<p>Você também aprende que existem tremendos compromissos, “trade-offs” (escolhas entre o que é desejável e o que é possível), existem certas coisas que simplesmente não dá pra um elétron fazer, certas coisas que não dá para plástico fazer, ou vidro fazer, ou fábricas fazerem, robôs fazerem, e quando você vê tudo isso, desenvolver um produto é manter 5 mil dessas coisas em seu cérebro, esses conceitos, e encaixar todos eles juntos, continuar a empurrá-los, a encaixá-los juntos, de maneiras diferentes para fazer o que você quer. E todo dia você descobre alguma coisa nova, tem um novo problema ou uma nova oportunidade, você encaixa as coisas um pouco diferente, e é esse processo que é a mágica. Então tivemos várias grandes idéias quando começamos, mas o que eu sempre acreditei que é uma equipe de pessoas faz o que acredita é … (pausa, mudando pra próxima ideia pra explicar)</p>
<p>Quando eu era criança, havia um homem viúvo que vivia na rua de cima, e ele estava lá pelos seus 80 anos de idade, com aparência um pouco de dar medo, e eu o conheci um pouco – talvez tenha me pagado pra cortar a grama ou coisa assim – e um dia ele disse <em>“venha até minha garagem, quero te mostrar uma coisa”</em> e ele me mostrou esse velho tambor giratório de pedras, era um moldador, com uma lata de café, amarrado junto. Nós fomos pra trás e pegamos algumas pedras, pedras feias, normais, e colocamos no tambor, com um pouco de líquido, um pouco de areia, e fechamos a lata. Ele ligou o motor e ele disse <em>“volte amanhã”</em> e a lata ficou fazendo barulho enquanto as pedras rolavam. E eu voltei no outro dia, abrimos a lata, e retiramos essas maravilhosas pedras polidas, as mesmas pedras comuns, ficaram batendo umas nas outras, criando um pouco de fricção, criando um pouco de barulho, e saíram essas pedras polidas lindas. E essa tem sido, na minha mente, minha metáfora para uma equipe trabalhando realmente duro em alguma coisa pela qual tem paixão. É através da equipe, desse grupo de pessoas talentosas, esbarrando umas nas outras, discutindo, brigando às vezes, fazendo algum barulho, e trabalhando juntas, elas acabam se polindo, e eles polem as idéias, e o que sai são essas lindas pedras.</p>
<p>Então, é difícil explicar, e certamente não é o resultado de uma única pessoa, quero dizer, pessoas gostam de símbolos, eu sou um símbolo de certas coisas, mas realmente foi um trabalho de equipe no Mac. Agora, na minha vida eu observei algumas coisas desde cedo na Apple, que eu não sabia como explicar na época, mas pensei muito desde então. Muitas coisas na vida, a “distância dinâmica” entre a média e o melhor é de no máximo 2 para 1. Por exemplo, se estiver em Nova Iorque e comparar o taxista médio com o melhor taxista, você vai chegar ao seu destino com o melhor taxista talvez 30% mais rápido? Um automóvel, qual a diferença do médio pro melhor? Talvez 20%? O melhor tocador de CD e o médio? Não sei, 20%? Então 2 para 1 é uma enorme distância dinâmica na maior parte da vida. Em software – e costumava ser o caso em hardware – a diferença entre o médio e o melhor é 50 para 1, talvez 100 para 1. Ok? Muitas poucas coisas na vida são assim, mas onde eu tive sorte de gastar minha vida é assim. Então eu construí muito do meu sucesso encontrando pessoas assim, e não me acomodando em ficar com pessoas nível “C”, mas realmente procurando pelos nível “A”. E eu descobri uma coisa, descobri que se você tem suficientes níveis “A” juntos – e você tem um enorme trabalho pra encontrar 5 desses níveis “A” -, eles realmente gostam de trabalhar uns com os outros, porque nunca tiveram chance de fazer isso antes, e eles não querem trabalhar com níveis “B” e “C”, então eles se autopoliciam, só querem contratar mais níveis “A”, então você constrói esses grupos de níveis “A” e isso propaga. E é assim que a equipe Mac era. Eles eram todos nível “A”, eram pessoas extraordinariamente talentosas.</p>
<p>…</p>
<p><strong>Entrevistador:</strong> O que significa quando você diz a alguém <em>“seu trabalho é uma merda”</em>?</p>
<p><strong>Steve:</strong> Ah, normalmente significa <em>“seu trabalho é uma merda”</em>, algumas vezes significa <em>“acho que seu trabalho é uma merda, mas posso estar errado”</em>, mas normalmente significa <em>“seu trabalho não está nem perto de ser bom o suficiente.”</em></p>
<p><strong>Entrevistador:</strong> Tem uma citação de Bill Atkinson que diz que significa <em>“eu não entendo bem o que significa, poderia explicar para mim?”</em></p>
<p><strong>Steve:</strong> (risos) Não é normalmente o que eu quero dizer. Quando eu tenho pessoas boas, eles sabem que são realmente bons, e você não tem que ficar massageando o ego das pessoas demais, e o que importa é o trabalho. Todos sabem disso, é tudo que importa: o trabalho. Então contamos mesmo com essas pessoas para fazer pedaços específicos do quebra cabeça, e a coisa mais importante que eu posso fazer para uma pessoa que é realmente boa, e que realmente estamos contando, é apontar a elas quando seu trabalho não é bom o suficiente. E fazer isso bem claramente, articular o porquê, e trazê-los de volta aos trilhos. E você precisa fazer isso de uma maneira que não coloca em questão sua habilidade, mas que não deixe muito espaço para interpretação de que esse certo trabalho específico não foi feito de uma maneira boa o suficiente para suportar o objetivo da equipe. E isso é uma coisa difícil de fazer, e eu sempre usei uma forma bem direta. E se falar com as pessoas que trabalharam comigo, as pessoas realmente boas acharam que isso as beneficiou, mas algumas odiavam. E eu não me importo muito de estar certo, só me importo pelo sucesso. Vai encontrar muitas pessoas que vão dizer que eu tinha uma opinião muito forte e que elas apresentaram evidências do contrário e 5 minutos depois eu completamente mudei de idéia, porque eu sou assim: não me importo de estar errado, e eu admito que estive errado muitas vezes, mas isso não importa muito, o que importa é que fizemos a coisa certa.</p>
<h2>Opinião Pessoal<span class="hx:absolute hx:-mt-20" id="opinião-pessoal"></span>
    <a href="#opini%c3%a3o-pessoal" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Reforço por que cito esses trechos: o fato de Steve ter dito não faz nada disso virar verdade absoluta. Minha opinião é que a maioria das pessoas <em>“average”</em>, a minha odiada “média”, imagina as coisas da forma romântica, em que uma grande ideia já é a solução.</p>
<p>Mesmo nessa nova geração que se autointitula “empreendedores”, ainda reina a noção ridícula de que ter uma “grande ideia” é tudo, e que o resto, a implementação, é mero detalhe. Já vi gente querendo registrar a ideia, achando que precisa protegê-la. Todo mundo acha que a própria ideia vale alguma coisa.</p>
<p>Vou dizer da forma mais elegante que já ouvi, dita pelo meu sócio: uma ideia não implementada vale exatamente zero. E uma ideia que, ao ser ouvida, é facilmente replicada vale menos ainda, é lixo. Não tem talvez, nem meio talvez: uma ideia é vazia até ser implementada. Duvido que alguém tenha a cura do câncer na cabeça e “só falte implementar”.</p>
<p>A implementação de qualquer coisa que vale a pena, um produto, um serviço, o que for, é sempre difícil. Se fosse simples, qualquer um faria.</p>
<p>Isso tem uma consequência. Quando as pessoas a bordo, empregados, parceiros, colaboradores, têm orgulho do próprio trabalho e da própria habilidade, o dia a dia tende a ser de atritos, esbarrões, problemas e frustrações. E é assim mesmo, porque se trata de algo que vale a pena. Se fosse trivial, rotineiro e tranquilo, eu não teria vontade de fazer parte.</p>
<p>Brigamos porque nos importamos, discutimos porque queremos fazer melhor, temos atrito porque perseguimos um amanhã melhor do que o hoje. E de quem não tem essa paixão, essa ambição de ser melhor amanhã do que é hoje, sinceramente não sei nem por que acorda de manhã.</p>
<p>Eu sempre disse que <em>“pessoas nível A contratam mais gente A, mas gente nível B contrata C, e os C contratam o lixo”</em>. Não sei qual era a definição do Steve, mas, na minha, a pessoa nível “A” nunca é a tecnicamente mais habilidosa. A habilidade conta, só que está longe de ser o principal.</p>
<p>Alguém extremamente habilidoso que na hora “H” desaparece (o que eu chamo de “Ninja”, o cara que, quando o problema esquenta, joga a bomba de fumaça e some), em quem não dá para confiar, que não leva as próprias responsabilidades a sério, é nível “D”, ponto final. Já alguém com habilidade ainda não tão boa, por falta de experiência ou o que seja, mas que responde à altura dos desafios, não foge, não inventa desculpa, corre atrás com as próprias pernas e só para quando acha a solução, esse é nível “A”.</p>
]]></content:encoded><category>apple</category><category>engenharia-de-software</category><category>off-topic</category></item><item><title>[Off-Topic] Comprei meu primeiro Mac, e agora? (Edição 2012)</title><link>https://akitaonrails.github.io/2012/04/20/off-topic-comprei-meu-primeiro-mac-e-agora-edicao-2012/</link><guid isPermaLink="true">https://akitaonrails.github.io/2012/04/20/off-topic-comprei-meu-primeiro-mac-e-agora-edicao-2012/</guid><pubDate>Fri, 20 Apr 2012 19:15:46 -0300</pubDate><description>&lt;p&gt;Um dos artigos mais lidos do meu blog é o &lt;a href="http://akitaonrails.com/2009/07/19/off-topic-comprei-meu-primeiro-mac-e-agora"target="_blank" rel="noopener"&gt;Comprei meu primeiro Mac, e agora?&lt;/a&gt;, que escrevi em Julho de 2009. Já atualizei ele uma vez e sempre achei que precisava atualizar de novo. O artigo inteiro, revisado, está no link acima. Para quem já leu, a seguir está só o que acrescentei hoje.&lt;/p&gt;
&lt;p&gt;Se você tem outras boas dicas, comente para compartilhar com todos. O foco aqui são usuários normais e Power Users, já que bons desenvolvedores sabem encontrar seu caminho sozinhos. Serve também para aquele amigo não-desenvolvedor que comprou um Mac e fica te perturbando toda hora com &lt;em&gt;“como faz isso? como faz aquilo?”&lt;/em&gt;. Agora é só passar o link acima para o artigo inteiro :-)&lt;/p&gt;</description><content:encoded><![CDATA[<p>Um dos artigos mais lidos do meu blog é o <a href="http://akitaonrails.com/2009/07/19/off-topic-comprei-meu-primeiro-mac-e-agora"target="_blank" rel="noopener">Comprei meu primeiro Mac, e agora?</a>, que escrevi em Julho de 2009. Já atualizei ele uma vez e sempre achei que precisava atualizar de novo. O artigo inteiro, revisado, está no link acima. Para quem já leu, a seguir está só o que acrescentei hoje.</p>
<p>Se você tem outras boas dicas, comente para compartilhar com todos. O foco aqui são usuários normais e Power Users, já que bons desenvolvedores sabem encontrar seu caminho sozinhos. Serve também para aquele amigo não-desenvolvedor que comprou um Mac e fica te perturbando toda hora com <em>“como faz isso? como faz aquilo?”</em>. Agora é só passar o link acima para o artigo inteiro :-)</p>
<p>Aproveitem!</p>
<h2>Edição 2012<span class="hx:absolute hx:-mt-20" id="edição-2012"></span>
    <a href="#edi%c3%a7%c3%a3o-2012" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><ul>
<li>Assim como no Windows e em outros sistemas, no Mac a velocidade de repetição do teclado vem configurada meio lenta por padrão. Abra qualquer editor de texto, use as setas para posicionar o cursor e vai notar como é demorado. Eu prefiro a velocidade no máximo: vá em “System Preferences, opção Keyboard”, deixe “Key Repeat” em “Fast” e “Delay Until Repeat” em “Short”. Você vai me agradecer:</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2012/4/20/Screen%20Shot%202012-04-20%20at%206.02.32%20PM_original.png?1334956028" alt=""  loading="lazy" /></p>
<ul>
<li>Antes do Lion existia uma função para encriptar seus arquivos em tempo real, chamada FileVault, e ela era ruim o suficiente para ser ignorada. A partir do Lion surgiu o <strong>FileVault 2</strong>, completamente diferente e bom o bastante para virar item obrigatório. Abra “System Preferences, Security &amp; Privacy”, aba “FileVault”, e habilite a encriptação total do seu HD. <strong>MUITO CUIDADO:</strong> ele vai gerar chaves de recuperação que permitem descriptografar os dados. Anote num local seguro e <strong>nunca perca</strong>. Uma dica é pegar seu iPhone ou qualquer smartphone com câmera e fotografar a tela quando ele exibir as chaves.</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2012/4/20/Screen%20Shot%202012-04-20%20at%206.29.06%20PM_original.png?1334957491" alt=""  loading="lazy" /></p>
<ul>
<li>A partir do Lion existe o <a href="http://web.archive.org/web/20120522082049/http://www.apple.com/br/macosx/whats-new/mission-control.html"target="_blank" rel="noopener">Mission Control</a>, que você ativa colocando quatro dedos no touchpad e arrastando pra cima. Ele é o substituto do antigo Exposé e fica bem prático quando você se acostuma. Aplicativos “maximizados” viram seu próprio “Space” paralelo, e você navega entre eles arrastando três dedos no touchpad para a direita ou para a esquerda. O incômodo é a configuração padrão: os Spaces se rearranjam dinamicamente conforme o uso. Eu gosto de manter meus aplicativos e desktops sempre na mesma posição, então desabilito isso em “System Preferences, opção Mission Control”, na opção “Automatically rearrange spaces based on most recent use” (você ainda pode arrastar os Spaces para a ordem que preferir).</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2012/4/20/Screen%20Shot%202012-04-20%20at%205.57.35%20PM_original.png?1334955644" alt=""  loading="lazy" /></p>
<ul>
<li>O Lion também mudou bastante a forma de salvar arquivos, com o novo recurso de “Auto Save”. Se acontecer um crash inesperado, se você precisar desligar a máquina no braço ou qualquer situação drástica dessas, não perde o que estava editando, porque o sistema salva sozinho. O incômodo é que o arquivo às vezes recebe um “Lock” que impede a edição. Dá para desbloquear manualmente, mas prefiro desligar isso em “System Preferences, Time Machine”, botão “options”, opção “Lock documents”. Aproveite a foto abaixo para ver onde fica e também o que eu coloco na lista de exclusão do Time Machine, coisas que prefiro não incluir no backup por não serem importantes (Software Images) ou por preferir fazer o backup na mão (iPhoto).</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2012/4/20/Screen%20Shot%202012-04-20%20at%206.38.10%20PM_original.png?1334958088" alt=""  loading="lazy" /></p>
<ul>
<li>
<p>Ainda sobre a forma como o Lion lida com documentos e versões: nos aplicativos novos apareceu a opção “Save a version”, que grava momentos no tempo caso você precise voltar e recuperar algo feito antes. Pense nisso como um mini Time Machine, um backup granulado. Em compensação, o antigo “Save As”, que salvava o mesmo arquivo com outro nome, sumiu. Agora a operação é mais chata: primeiro “Duplicate” e depois “Save” (tudo no menu principal “File”) para gravar com outro nome. É chato no começo, mas vira rotina rápido.</p>
</li>
<li>
<p>O <a href="https://github.com/mxcl/homebrew"target="_blank" rel="noopener">HomeBrew</a> é o melhor instalador de softwares de código-livre como MySQL, PostgreSQL, Redis, Git, Android SDK e muito mais. Em alguns casos ele baixa direto o binário pra Mac, mas na maioria das vezes pega o código-fonte, aplica os patches necessários e compila. Para isso você precisa de compiladores e outras ferramentas, e a forma mais simples é baixar o XCode pela <strong>App Store</strong>. Esta dica é mais para desenvolvedores; se você não for, pode ignorar.</p>
</li>
<li>
<p>O Lion é a versão mais prática na hora de se recuperar de desastres. Acabou o DVD de boot: agora todo Mac tem uma partição escondida com o instalador, caso você precise reinstalar, checar discos e coisas assim. Basta dar boot segurando (Command-R) ⌘-R, ou segurar a tecla (Option) ⌥ durante o boot para abrir o menu de partições disponíveis e escolher “Recovery HD”.</p>
</li>
</ul>
<p><a href="http://www.apple.com/macosx/recovery/"target="_blank" rel="noopener"><img src="http://s3.amazonaws.com/akitaonrails/assets/2012/4/20/commandr_original.jpg?1334958455" alt=""  loading="lazy" /></a></p>
<h3>Aplicações<span class="hx:absolute hx:-mt-20" id="aplicações"></span>
    <a href="#aplica%c3%a7%c3%b5es" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Alguns dos aplicativos a seguir estão no Mac App Store, e recomendo sempre procurar por lá primeiro. Quando não estiverem, use os links e baixe manualmente. No fim da seção tem uma dica para manter tudo sempre atualizado.</p>
<ul>
<li>
<p>Se tiver um iPad, dá para usá-lo como um segundo monitor ligado ao Mac via Wi-Fi (os dois precisam estar na mesma rede). Para isso, compre o programa <a href="http://web.archive.org/web/20120420081551/http://avatron.com/apps/air-display"target="_blank" rel="noopener">Air Display</a>.</p>
</li>
<li>
<p>Se tiver um novo Apple TV (o modelo pequeno preto), dá para espelhar a tela do iPhone 4S, iPad 2 ou superior via Wi-Fi usando o <a href="http://support.apple.com/kb/HT4437?viewlocale=pt_PT&amp;locale=pt_PT"target="_blank" rel="noopener">Air Play</a> do iOS. A próxima versão do Mac, o Mountain Lion, vai permitir fazer o mesmo a partir do Mac. Até lá, você ainda pode espelhar o Mac numa HDTV via Apple TV comprando o <a href="http://airparrot.com/"target="_blank" rel="noopener">Air Parrot</a>. É a forma mais simples de assistir a filmes e vídeos do seu Mac direto na TV.</p>
</li>
<li>
<p>Eu gosto muito de ler os vários feeds RSS e Atom cadastrados na minha conta do Google Reader, e o melhor aplicativo para Mac e iOS é o <a href="http://reederapp.com/mac/"target="_blank" rel="noopener">Reeder</a>.</p>
</li>
<li>
<p>Com tanto conteúdo na internet, você baixa muita coisa e nem sempre sabe quais arquivos estão consumindo mais espaço em disco. Para encontrá-los com facilidade (dica: na maioria das vezes são os vídeo podcasts no iTunes), existem ótimos aplicativos pagos como o <a href="http://www.daisydiskapp.com/"target="_blank" rel="noopener">DaisyDisk</a>, mas eu ainda gosto do gratuito <a href="http://grandperspectiv.sourceforge.net/"target="_blank" rel="noopener">GrandPerspective</a>.</p>
</li>
<li>
<p>O OS X sozinho dá conta de formatos comprimidos como zip e gz. Para descompactar formatos mais chatos como 7-zip e rar, instale o <a href="http://wakaba.c3.cx/s/apps/unarchiver.html"target="_blank" rel="noopener">The Unarchiver</a>.</p>
</li>
<li>
<p>A última dica é criar uma conta no <a href="http://www.macupdate.com/"target="_blank" rel="noopener">MacUpdate</a> e baixar o <a href="http://www.macupdate.com/desktop/"target="_blank" rel="noopener">MacUpdate Desktop</a>. De vez em quando abra o programa e ele mostra tudo que está desatualizado na máquina, deixando você escolher o que quer atualizar:</p>
</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2012/4/20/Screen%20Shot%202012-04-20%20at%206.14.40%20PM_original.png?1334956624" alt=""  loading="lazy" /></p>
]]></content:encoded><category>apple</category><category>produtividade</category><category>tutoriais</category><category>off-topic</category></item><item><title>[Off-Topic] Tributo a Steve Jobs</title><link>https://akitaonrails.github.io/2011/10/06/off-topic-tributo-a-steve-jobs/</link><guid isPermaLink="true">https://akitaonrails.github.io/2011/10/06/off-topic-tributo-a-steve-jobs/</guid><pubDate>Thu, 06 Oct 2011 01:41:00 -0300</pubDate><description>&lt;p&gt;&lt;a href="http://www.apple.com/stevejobs"target="_blank" rel="noopener"&gt;&lt;img src="http://s3.amazonaws.com/akitaonrails/assets/2011/10/6/the_hero_original.png?1317872992" alt="" loading="lazy" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Como todos já sabem, 5 de outubro de 2011 marca o fim de uma era com a morte do visionário e empreendedor Steve Jobs. Nos próximos dias, todos os meios de comunicação vão publicar artigos e mais artigos sobre sua vida e seu legado, e sua biografia oficial deve sair em breve. Por isso não vou me alongar repetindo a mesma história que hoje já é conhecida por todos.&lt;/p&gt;</description><content:encoded><![CDATA[<p><a href="http://www.apple.com/stevejobs"target="_blank" rel="noopener"><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/10/6/the_hero_original.png?1317872992" alt=""  loading="lazy" /></a></p>
<p>Como todos já sabem, 5 de outubro de 2011 marca o fim de uma era com a morte do visionário e empreendedor Steve Jobs. Nos próximos dias, todos os meios de comunicação vão publicar artigos e mais artigos sobre sua vida e seu legado, e sua biografia oficial deve sair em breve. Por isso não vou me alongar repetindo a mesma história que hoje já é conhecida por todos.</p>
<p>Acredito que é a primeira vez que fiquei chocado e momentaneamente sem reação com a morte de alguém. Não se fala de outra coisa no Twitter e outras redes sociais neste momento. Muita gente está desolada. Muitos estão pessimistas que a Apple não vai sobreviver sem seu líder.</p>
<p>Pessoalmente, me sinto contente e com muita sorte por ter vivido a geração seguinte a nomes como Steve Jobs. A Apple foi fundada em 1976 e incorporada em 1977. Quando o iPhone original foi lançado, em 2007, tanto a Apple quanto eu comemorávamos 30 anos.</p>
<p>Da mesma forma, minha história com computadores e tecnologia começou em 1984, no mesmo momento em que o Macintosh original estava nascendo.</p>
<p>Assim como Steve Jobs subiu nos ombros de gigantes como Robert Noyce, Hewlett-Packard e outros das primeiras gerações da informática, nós desta geração tivemos a chance de observar um gigante trabalhando. É muito tentador tentar reduzir os feitos de Steve a “receitas mágicas”, como todos gostam de fazer com grandes biografias. Porém nenhuma das conclusões que todos querem tirar vai fazer muito sentido.</p>
<p>Talvez a mensagem que melhor resume a filosofia que Steve Jobs popularizou com a Apple é o que foi ilustrado no icônico comercial de 1997 (<a href="http://akitaonrails.com/2007/01/27/off-topic-heres-to-the-crazy-ones"target="_blank" rel="noopener">bloguei sobre isso em 2007</a>):</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/eUMFt_OImjA"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Obviamente, a que mais chega próximo à filosofia de vida de Steve é seu agora lendário discurso em Stanford de 2005 (<a href="http://akitaonrails.com/2007/06/13/off-topic-steve-jobs-discurso-em-stanford-2005"target="_blank" rel="noopener">bloguei sobre isso em 2007 também</a>):</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/yw5fuDMblYg"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>No começo do ano legendei o documentário da Discovery Channel que conta a história do retorno de Steve à Apple até o sucesso do iTunes + iPod (<a href="http://akitaonrails.com/2011/01/30/documentario-the-ipod-revolution"target="_blank" rel="noopener">foi em Janeiro deste ano</a>):</p>
<video controls>
<source src="https://s3.us-east-2.amazonaws.com/blip.tv/Akitaonrails-iPodRevolutionPtBR748.m4v.mp4">
Your browser does not support the video tag. [Direct Link](https://s3.us-east-2.amazonaws.com/blip.tv/Akitaonrails-iPodRevolutionPtBR748.m4v.mp4)
</source></video>
<p>Se você não conhece esta história, vale a pena assistir. Se já viu, vale a pena rever. Coincidentemente, a história de Steve segue o <a href="http://en.wikipedia.org/wiki/Monomyth"target="_blank" rel="noopener">Monomito, ou a jornada do herói</a>, a receita das grandes histórias detalhada por Joseph Campbell na sua famosa obra <a href="http://en.wikipedia.org/wiki/Joseph_Campbell#The_Hero_with_a_Thousand_Faces"target="_blank" rel="noopener">O Herói de Mil Caras</a>. Ele resume:</p>
<blockquote>
  <p>“Um herói se aventura a partir do mundo rotineiro comum a uma região de maravilha sobrenatural: forças fabulosas são encontradas lá e uma vitória decisiva é ganha: o herói retorna dessa aventura misteriosa com o poder de conceder bênção a seus semelhantes”</p>

</blockquote>
<p>A Jornada do Herói descrita por Campbell se divide em 3 partes: a Partida (Jobs e Wozniak na garagem iniciando a Apple); a Iniciação (a queda de Steve da Apple nos anos 90, seus desafios e aprendizados com a NeXT e a Pixar) e o Retorno (o retorno à Apple em 1997 e os sucessivos lançamentos que tiraram a Apple da quase-falência até a posição de empresa mais valiosa dos Estados Unidos).</p>
<p>Para mim, o sinal de que “O Império Contra Ataca” havia se transformado em “Retorno de Jedi” estava na simbólica aliança com sua arqui-inimiga Microsoft em 1997, que expliquei no post <a href="http://akitaonrails.com/2007/10/23/para-eu-ganhar-o-outro-precisa-perder"target="_blank" rel="noopener">Para eu ganhar, o outro precisa perder …</a>.</p>
<p>E no fim, é exatamente isso que todos deveriam almejar, como Steve Jobs e outros gigantes: caminhar pelos passos da jornada do herói. Sair do comum, da mediocridade, do conformismo e arriscar, explorar, cair muitas vezes e se levantar quantas forem necessárias.</p>
<p>Nenhum esforço, nenhum suor ou sangue derramado é garantia de sucesso. Retornando ao comercial de 1997, lembre-se:</p>
<blockquote>
  <p>“Porque aqueles que são loucos o suficiente para achar que podem mudar o mundo, são os que conseguem.”</p>

</blockquote>
<p>Que, para mim, é o avesso de outra frase famosa (de autoria desconhecida, mas atribuída a Einstein, Ben Franklin, Rita Mae Brown, a um provérbio chinês e outros):</p>
<blockquote>
  <p>“A definição de insanidade é repetir as mesmas coisas dia após dia e esperar resultados diferentes.”</p>

</blockquote>
<p>Steve Jobs foi o exemplo moderno dos grandes exploradores: os navegantes que atravessaram oceanos para encontrar o novo mundo, os cientistas que quebraram crenças antigas, e assim por diante. Ninguém mandou que fizessem aquilo. Fizeram por conta própria, para sustentar crenças que, na época, só eles defendiam, mesmo que os chamassem de loucos e transgressores. E o tempo provou que os loucos eram justamente os que os chamavam de loucos.</p>
<p>Steve Jobs foi um exemplo moderno de como a visão de um único indivíduo é capaz de moldar grandes porções de uma sociedade inteira, como <a href="http://www.akitaonrails.com/2011/02/04/off-topic-the-fountainhead-defesa-de-howard-roark"target="_blank" rel="noopener">expliquei em fevereiro</a>. Ele foi um dos candidatos mais próximos de um <a href="http://fvdb.wordpress.com/2011/08/25/steve-jobs-the-howard-roark-in-business/"target="_blank" rel="noopener">Howard Roark</a> moderno.</p>
<!-- dead Flash embed removed (service offline): http://blip.tv/play/AYKhnigA -->
<p>Também coincidentemente, Steve trabalhou até perto de um mês antes de morrer, mais do que eu e mais do que você, tenha certeza. Trabalhou durante os sete anos em que enfrentou o câncer. Finalizou seu trabalho repassando o bastão a pessoas de confiança que entendem sua filosofia, como Tim Cook e Phil Schiller. Conseguiu até terminar sua biografia, e só tirou “férias”, forçadas, no último mês de vida.</p>
<p>Não lembro onde vi isto certa vez, mas uma frase combina perfeitamente com tudo isso:</p>
<blockquote>
  <p>“Se não for para se tornar o melhor naquilo que faz, para que fazer?”</p>

</blockquote>
<p>Para terminar, deixo os tweets que lancei logo que soube que Steve havia falecido, ensaiando para este tributo pessoal:</p>
<blockquote>
  <p>“Don’t despair or moan too much. Be thankful to have lived in the same generation as Steve. Now, what will do you do with this privilege?” – <a href="https://twitter.com/akitaonrails/status/121741343386107904"target="_blank" rel="noopener">4 horas atrás</a></p>

</blockquote>
<blockquote>
  <p>“Did you slow down because of Steve’s death? That’s not how you honor him: speed up your own accomplishments, that’s what he would’ve done.” – <a href="https://twitter.com/akitaonrails/status/121743234618753024"target="_blank" rel="noopener">4 horas atrás</a></p>

</blockquote>
<blockquote>
  <p>“U ppl that are sad. U had the chance to witness ‘miracles’. Stand up. Steve is daring u to live up to what he has started. What will u do?” – <a href="https://twitter.com/akitaonrails/status/121750887558414336"target="_blank" rel="noopener">3 horas atrás</a></p>

</blockquote>
<blockquote>
  <p>“Steve Jobs was great because he lived for himself. It didn’t matter what others complained. And in the process everybody benefitted.” – <a href="https://twitter.com/akitaonrails/status/121752058167701504"target="_blank" rel="noopener">3 horas atrás</a></p>

</blockquote>
]]></content:encoded><category>apple</category><category>historia-da-computacao</category><category>biografias</category><category>off-topic</category></item><item><title>[Off-Topic] Disney, História do Computador e o Encarte Perdido</title><link>https://akitaonrails.github.io/2011/09/25/off-topic-disney-historia-do-computador-e-o-encarte-perdido/</link><guid isPermaLink="true">https://akitaonrails.github.io/2011/09/25/off-topic-disney-historia-do-computador-e-o-encarte-perdido/</guid><pubDate>Sun, 25 Sep 2011 02:41:00 -0300</pubDate><description>&lt;p&gt;Nos últimos eventos em que palestrei, apresento uma seção meio “nostálgica” onde um dos itens que mostro é sobre a seguinte revista em quadrinhos:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://s3.amazonaws.com/akitaonrails/assets/2011/9/25/SCAN0001_original.png" alt="" loading="lazy" /&gt; &lt;img src="http://s3.amazonaws.com/akitaonrails/assets/2011/9/25/SCAN0024_original.png?1316928230" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;Esta revista foi lançada em novembro de 1984. Não lembro exatamente quando meu pai a comprou para mim, mas provavelmente foi entre novembro e dezembro daquele ano, quando ainda estava em circulação. Não fazia nem um ano que a Apple tinha lançado o primeiro Macintosh, que inaugurou a primeira geração de desktops com interface gráfica e mouse.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Nos últimos eventos em que palestrei, apresento uma seção meio “nostálgica” onde um dos itens que mostro é sobre a seguinte revista em quadrinhos:</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/9/25/SCAN0001_original.png" alt=""  loading="lazy" /> <img src="http://s3.amazonaws.com/akitaonrails/assets/2011/9/25/SCAN0024_original.png?1316928230" alt=""  loading="lazy" /></p>
<p>Esta revista foi lançada em novembro de 1984. Não lembro exatamente quando meu pai a comprou para mim, mas provavelmente foi entre novembro e dezembro daquele ano, quando ainda estava em circulação. Não fazia nem um ano que a Apple tinha lançado o primeiro Macintosh, que inaugurou a primeira geração de desktops com interface gráfica e mouse.</p>
<p>Eu ainda era criança nessa época, mas já tinha apreciação por computadores, especialmente a “atividade” de controlar a máquina pelo teclado. Minha brincadeira era trocar a sensação de digitar num teclado pela de datilografar numa máquina de escrever mecânica, exercício que até hoje me mantém <a href="http://en.wikipedia.org/wiki/Touch_typing"target="_blank" rel="noopener">touch-typist</a>.</p>
<p>Esta revista foi especial por um motivo. A maioria dos “hackers” se foca em controlar o computador, em programá-lo, em “hackeá-lo”. A revista me abriu para um horizonte maior: a história dos computadores.</p>
<p>Naquela época não tínhamos Google e muito menos Wikipedia. Felizmente meus pais, sempre preocupados com educação, já tinham a enciclopédia Mirador, de onde eu pude aprofundar o assunto. Foi assim que, nos anos 80, alguns dos meus “heróis de infância” viraram <a href="http://en.wikipedia.org/wiki/Charles_babbage"target="_blank" rel="noopener">Charles Babbage</a>, <a href="http://en.wikipedia.org/wiki/Konrad_Zuse"target="_blank" rel="noopener">Konrad Zuse</a>, <a href="http://en.wikipedia.org/wiki/John_Von_Neumann"target="_blank" rel="noopener">John von Neumann</a> e <a href="http://en.wikipedia.org/wiki/Robert_Noyce"target="_blank" rel="noopener">Robert Noyce</a>. Somados a outros nomes que ajudaram a formar meu raciocínio, como Carl Sagan, essa revista foi um pilar importante na minha formação nos anos seguintes.</p>
<p>Recomendo como leitura para qualquer criança. É leve e instrutiva, com um toque Disney. Eu ainda guardo meu exemplar, já razoavelmente surrado depois de mais de 26 anos. Nos últimos dias resolvi escanear suas páginas e montar um PDF, que você pode baixar <a href="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260909160124_disney_historia_do_computador.pdf"target="_blank" rel="noopener">neste link</a>. Fiz também uma versão em <a href="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260909160124_disney_historia_do_computador.epub"target="_blank" rel="noopener">EPUB</a>, boa pra ler duas páginas lado a lado num monitor widescreen. Não sei quanto a direitos autorais depois de tanto tempo, ainda mais sem a chance de encontrar uma cópia para comprar hoje em dia. Se alguém me enviar uma notificação de <em>cease and desist</em>, eu retiro. Até lá, divirtam-se.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/9/25/SCAN0001%202_original.png?1316928247" alt=""  loading="lazy" /></p>
<p>Um dos motivos para publicar isso é encontrar outras pessoas da mesma época que tenham comprado e ainda guardem seu exemplar. A revista tinha um encarte central em papel glossy, com 32 páginas, detalhando o lançamento do Macintosh original, com artigos sobre o MacPaint e outras coisas. Se alguém tiver, eu adoraria pelo menos os scans dessas páginas. Na época eu gostava tanto do encarte que acabei destacando ele da revista, e, soltas, essas páginas se perderam. Não deixem de comentar aqui embaixo se tiverem um exemplar!</p>
<p>Aproveitem!</p>
]]></content:encoded><category>historia-da-computacao</category><category>retrocomputacao</category><category>apple</category><category>off-topic</category></item><item><title>[Objective-C] Distribuindo sua Static Library</title><link>https://akitaonrails.github.io/2011/04/24/objective-c-distribuindo-sua-static-library/</link><guid isPermaLink="true">https://akitaonrails.github.io/2011/04/24/objective-c-distribuindo-sua-static-library/</guid><pubDate>Sun, 24 Apr 2011 00:46:00 -0300</pubDate><description>&lt;p&gt;Se você não leu meus &lt;a href="http://www.akitaonrails.com/2011/04/23/objective-c-it%27s-a-unix-system-i-know-this"target="_blank" rel="noopener"&gt;dois&lt;/a&gt; &lt;a href="http://www.akitaonrails.com/2011/04/23/objective-c-categories-static-libraries-e-pegadinhas"target="_blank" rel="noopener"&gt;últimos artigos&lt;/a&gt;, recomendo fortemente que leia antes de continuar, porque vou usar o mesmo pet project, &lt;a href="http://www.akitaonrails.com/2011/04/23/objective-c-it%27s-a-unix-system-i-know-this"target="_blank" rel="noopener"&gt;ObjC Rubyfication&lt;/a&gt;, como exemplo neste artigo. A ideia é simples: você está escrevendo código reutilizável e quer aproveitar isso em mais de um projeto.&lt;/p&gt;
&lt;p&gt;A maior parte do que vou mostrar foi baseada no artigo do &lt;a href="http://www.cocoanetics.com/2010/04/universal-static-libraries/"target="_blank" rel="noopener"&gt;Cocoanetics&lt;/a&gt; sobre universal static libraries. Então, se você prestou atenção no &lt;a href="http://www.akitaonrails.com/2011/04/23/objective-c-categories-static-libraries-e-pegadinhas"target="_blank" rel="noopener"&gt;artigo anterior&lt;/a&gt;, viu este screenshot:&lt;/p&gt;
&lt;!-- broken image (host offline/expired): http://s3.amazonaws.com/akitaonrails/assets/2011/4/23/Screen%20shot%202011-04-23%20at%2011.41.27%20PM_original.png --&gt;
&lt;p&gt;Eu disse que tinha apenas estes targets configurados: CocoaOniguruma, Kiwi, Rubyfication e RubyficationTests. Mas existem mais 3: CocoaOniguruma SIM, Rubyfication SIM e Build &amp;amp; Merge Libraries. O motivo é simples:&lt;/p&gt;</description><content:encoded><![CDATA[<p>Se você não leu meus <a href="http://www.akitaonrails.com/2011/04/23/objective-c-it%27s-a-unix-system-i-know-this"target="_blank" rel="noopener">dois</a> <a href="http://www.akitaonrails.com/2011/04/23/objective-c-categories-static-libraries-e-pegadinhas"target="_blank" rel="noopener">últimos artigos</a>, recomendo fortemente que leia antes de continuar, porque vou usar o mesmo pet project, <a href="http://www.akitaonrails.com/2011/04/23/objective-c-it%27s-a-unix-system-i-know-this"target="_blank" rel="noopener">ObjC Rubyfication</a>, como exemplo neste artigo. A ideia é simples: você está escrevendo código reutilizável e quer aproveitar isso em mais de um projeto.</p>
<p>A maior parte do que vou mostrar foi baseada no artigo do <a href="http://www.cocoanetics.com/2010/04/universal-static-libraries/"target="_blank" rel="noopener">Cocoanetics</a> sobre universal static libraries. Então, se você prestou atenção no <a href="http://www.akitaonrails.com/2011/04/23/objective-c-categories-static-libraries-e-pegadinhas"target="_blank" rel="noopener">artigo anterior</a>, viu este screenshot:</p>
<!-- broken image (host offline/expired): http://s3.amazonaws.com/akitaonrails/assets/2011/4/23/Screen%20shot%202011-04-23%20at%2011.41.27%20PM_original.png -->
<p>Eu disse que tinha apenas estes targets configurados: CocoaOniguruma, Kiwi, Rubyfication e RubyficationTests. Mas existem mais 3: CocoaOniguruma SIM, Rubyfication SIM e Build &amp; Merge Libraries. O motivo é simples:</p>
<ul>
<li>O Target &ldquo;CocoaOniguruma&rdquo; gera o binário <tt>libCocoaOniguruma.a</tt>, compatível com o processador ARM do iOS</li>
<li>O Target &ldquo;CocoaOniguruma SIM&rdquo; gera o binário <tt>libCocoaOnigurumaSimulator.a</tt>, compatível com o processador i386 do iPhone Simulator local</li>
<li>O Target &ldquo;Rubyfication&rdquo; gera o binário <tt>libRubyfication.a</tt>, compatível com o processador ARM do iOS</li>
<li>O Target &ldquo;Rubyfication SIM&rdquo; gera o binário <tt>libRubyficationSimulator.a</tt>, compatível com o processador i386 do iPhone Simulator local</li>
<li>O Target &ldquo;Build &amp; Merge Libraries&rdquo; junta os binários específicos de cada target em um único Universal (Fat) Binary, fácil de distribuir e reutilizar.</li>
</ul>
<h2>Conceitos e História<span class="hx:absolute hx:-mt-20" id="conceitos-e-história"></span>
    <a href="#conceitos-e-hist%c3%b3ria" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Cabe uma explicação aqui. Quando você desenvolve aplicações iOS, pode testar diretamente no seu iPhone ou dentro do Simulator. Apple foi muito esperta nesse ponto: qualquer outro fabricante do mercado começaria criando um emulador de processador ARM para rodar em cima do seu i386. Aí pegaria os binários ARM e os executaria dentro desse emulador. O sistema operacional continuaria compilado para ARM, rodando dentro do emulador.</p>
<p>Só que isso é absurdamente lento, impraticável. Quem já experimentou um ambiente de emulação assim sabe o quanto é ridículo. E não confunda com soluções tipo VMWare ou Parallels, que são rápidas porque emulam <strong>o mesmo processador</strong>. Você consegue rodar Windows em cima do Mac porque os processadores e sistemas operacionais hoje suportam VT-x, ou seja, você quase não precisa emular o processador. Agora, todo smartphone e tablet do mercado usa processador ARM, que não tem nada a ver com i386.</p>
<p>Então, como a Apple entregou um emulador de iPhone/iPad super rápido que roda em tempo real no seu Mac? Simples: ela não entregou. Ele se chama &ldquo;Simulator&rdquo; e não &ldquo;Emulator&rdquo; por um motivo: tudo que roda dentro do Simulator é compilado para i386, e não para ARM. Ou seja, o que está rodando ali é um binário real, executando nativamente no seu Mac! Sem emulação alguma. O iOS é bem portável. Da mesma forma que o Mac OS X conseguiu fazer a transição do PowerPC para Intel lá em 2005, o iOS faz o mesmo truque, já que basicamente são o mesmo sistema operacional.</p>
<p>Quando você escolhe o scheme do iPhone no XCode, ele compila para ARM e sobe os bits no seu iPhone para rodar a aplicação. Quando você escolhe o scheme do Simulator no XCode, ele compila para i386, sobe os bits no Simulator e roda nativamente como qualquer outra aplicação no seu Mac.</p>
<p>Voltando ao ponto principal: quando eu distribuo um binário da minha Static Library, tenho que lembrar que o desenvolvedor vai linkar contra ela tanto para deploy no device ARM (iPhone/iPad) quanto no Simulator (i386). Ou seja, eu teria que entregar pelo menos 2 arquivos binários. Mas a Apple foi ainda mais esperta. Aliás, a NeXT foi. Quando eles fizeram a primeira transição do NeXTStep dos processadores Motorola para Intel lá no fim dos anos 80, criaram os <a href="http://en.wikipedia.org/wiki/Fat_binary"target="_blank" rel="noopener">Fat Binaries</a>, que basicamente são um único binário contendo os bits específicos de cada processador num só pacote. Quando a Apple fez a transição do PowerPC para Intel, rebatizaram para <a href="http://en.wikipedia.org/wiki/Universal_binary"target="_blank" rel="noopener">Universal Binaries</a>. E é exatamente isso que precisamos construir agora.</p>
<h2>Operações<span class="hx:absolute hx:-mt-20" id="operações"></span>
    <a href="#opera%c3%a7%c3%b5es" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Já entendemos o que é um Universal Binary. Para facilitar, eu cliquei com o botão direito sobre os targets &ldquo;Rubyfication&rdquo; e &ldquo;CocoaOniguruma&rdquo; e dupliquei. Eles aparecem como &ldquo;Rubyfication copy&rdquo; e &ldquo;CocoaOniguruma copy&rdquo;. Podemos mudar o &ldquo;Product Name&rdquo; nas build settings de cada um para algo mais razoável:</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/4/24/Screen%20shot%202011-04-24%20at%2012.21.02%20AM_original.png?1303615270" alt=""  loading="lazy" /></p>
<p>No meu caso, renomeei para &ldquo;RubyficationSimulator&rdquo; e &ldquo;CocoaOnigurumaSimulator&rdquo;. Isso vai me dar tanto &ldquo;libRubyficationSimulator.a&rdquo; quanto &ldquo;libCocoaOnigurumaSimulator.a&rdquo;. Como dá para ver no grupo Products:</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/4/24/Screen%20shot%202011-04-24%20at%2012.23.16%20AM_original.png?1303615348" alt=""  loading="lazy" /></p>
<p><strong>Importante:</strong> lembre que o target Rubyfication tinha o CocoaOniguruma como dependência. Você vai precisar mudar o target &ldquo;Rubyfication SIM&rdquo; para apontar para o novo target &ldquo;CocoaOniguruma SIM&rdquo;! Outra coisa: você precisa forçar os dois novos targets a compilar para &ldquo;Latest Mac OS X&rdquo; na opção <tt>&ldquo;Base <span class="caps">SDK</span>&quot;</tt> do Build Settings de cada um, e &ldquo;32-bit Intel&rdquo; na opção <tt>&ldquo;Architectures&rdquo;</tt>. Isso faz com que sejam compilados para processadores i386. Os targets originais devem ter o <tt>&ldquo;Base <span class="caps">SDK</span>&quot;</tt> em &ldquo;Latest iOS&rdquo; e <tt>&ldquo;Architectures&rdquo;</tt> em &ldquo;Standard (armv6 armv7)&rdquo;.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/4/24/Screen%20shot%202011-04-24%20at%2012.54.21%20AM_original.png?1303617223" alt=""  loading="lazy" /></p>
<p>Agora precisamos criar um novo target do tipo &ldquo;Aggregate&rdquo;:</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/4/24/Screen%20shot%202011-04-24%20at%2012.24.00%20AM_original.png?1303615407" alt=""  loading="lazy" /></p>
<p>Eu chamei de &ldquo;Build &amp; Merge Libraries&rdquo;. Na aba &ldquo;Build Phases&rdquo;, você começa apenas com a fase &ldquo;Target Dependencies&rdquo;. Basta adicionar os novos targets &ldquo;Rubyfication SIM&rdquo; e &ldquo;CocoaOniguruma SIM&rdquo;. Em seguida, adicione mais 3 fases: uma &ldquo;Run Script&rdquo;, uma &ldquo;Copy Files&rdquo; e mais uma &ldquo;Run Script&rdquo; no final.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/4/24/Screen%20shot%202011-04-24%20at%2012.25.13%20AM_original.png?1303615678" alt=""  loading="lazy" /></p>
<p>Na fase &ldquo;Copy Files&rdquo; eu adicionei todos os public headers que quero distribuir junto com a universal binary library. O motivo é que outros desenvolvedores vão precisar adicionar esses headers nos próprios projetos para conseguir compilar contra a minha biblioteca. Repare que estou copiando para um &ldquo;Absolute Path&rdquo; definido como <tt>${TARGET_BUILD_DIR}/../Rubyfication</tt>.</p>
<p>E é aí que entra a fase &ldquo;Run Script&rdquo; anterior, que deve ter o seguinte código:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 1. cria uma nova pasta de saída</span>
</span></span><span class="line"><span class="cl">mkdir -p <span class="si">${</span><span class="nv">TARGET_BUILD_DIR</span><span class="si">}</span>/../Rubyfication
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 2. combina os arquivos lib das várias plataformas em um só</span>
</span></span><span class="line"><span class="cl">lipo create <span class="s2">&#34;</span><span class="si">${</span><span class="nv">TARGET_BUILD_DIR</span><span class="si">}</span><span class="s2">/../Debug-iphoneos/libRubyfication.a&#34;</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">TARGET_BUILD_DIR</span><span class="si">}</span><span class="s2">/../Debug-iphonesimulator/libRubyfication.a&#34;</span> -output <span class="s2">&#34;</span><span class="si">${</span><span class="nv">TARGET_BUILD_DIR</span><span class="si">}</span><span class="s2">/../Rubyfication/libRubyfication</span><span class="si">${</span><span class="nv">BUILD_STYLE</span><span class="si">}</span><span class="s2">.a&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>A primeira coisa que ele faz é criar esse novo diretório &ldquo;Rubyfication&rdquo;. O segundo comando usa o <a href="http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/lipo.1.html"target="_blank" rel="noopener">lipo</a>, que junta 2 binários dependentes de processador num único universal binary. Preste atenção nos PATHs se for reutilizar esse script em outro lugar. Pelo menos no XCode 4, é nesses caminhos que ele cria os binários de cada target:</p>
<ul>
<li>${TARGET_BUILD_DIR}/../Debug-iphoneos/libRubyfication.a – a versão ARM</li>
<li>${TARGET_BUILD_DIR}/../Debug-iphonesimulator/libRubyfication.a – a versão i386</li>
<li>${TARGET_BUILD_DIR}/../Rubyfication/libRubyfication-Debug.a – o universal binary resultante que criamos</li>
</ul>
<p>Por fim, o último &ldquo;Run Script&rdquo;, depois da fase &ldquo;Copy Files&rdquo; descrita acima, precisa do seguinte script:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ditto c -k --keepParent <span class="s2">&#34;</span><span class="si">${</span><span class="nv">TARGET_BUILD_DIR</span><span class="si">}</span><span class="s2">/../Rubyfication&#34;</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">TARGET_BUILD_DIR</span><span class="si">}</span><span class="s2">/../Rubyfication.zip&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>&ndash;</p>
<p>Ele apenas cria um arquivo ZIP com a universal binary library e seus public headers companheiros. Qualquer outro desenvolvedor pode pegar esse zip, descompactar e adicionar os arquivos no próprio projeto. Se quiser saber onde esse ZIP foi parar, o jeito mais fácil é ir no project viewer (painel da esquerda) do XCode, abrir o grupo &ldquo;Products&rdquo;, clicar com botão direito no arquivo &ldquo;libRubyfication.a&rdquo; (ou qualquer outro arquivo gerado) e escolher &ldquo;Show in Finder&rdquo;. Daí navegue uma pasta acima na hierarquia (até a pasta &ldquo;Products&rdquo;) e você vai ver algo assim:</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/4/24/Screen%20shot%202011-04-24%20at%2012.39.02%20AM_original.png?1303616300" alt=""  loading="lazy" /></p>
<p>E pronto: aí está o seu ZIP com seu universal binary redistribuível novinho em folha!</p>
<h2>Usando o Universal Binary<span class="hx:absolute hx:-mt-20" id="usando-o-universal-binary"></span>
    <a href="#usando-o-universal-binary" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Para demonstrar como usar esse ZIP distribuível, eu criei um projeto iOS bem simples e enxuto chamado <a href="https://github.com/akitaonrails/ObjC_OnigurumaDemo"target="_blank" rel="noopener">ObjC_OnigurumaDemo</a>, que você pode baixar do Github e rodar no seu próprio device iOS.</p>
<p>Como dá para ver no screenshot abaixo, eu simplesmente descompactei o ZIP dentro de uma pasta &ldquo;Dependencies&rdquo; no meu projeto iOS e adicionei o universal binary &ldquo;libRubyfication-Debug.a&rdquo; na Library Linking Build Phase:</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/4/24/Screen%20shot%202011-04-24%20at%2012.42.09%20AM_original.png?1303616506" alt=""  loading="lazy" /></p>
<p>Isso me permite usar qualquer coisa dessa biblioteca no meu projeto, em particular um trecho de código que usa as expressões regulares do Oniguruma:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="p">-</span> <span class="p">(</span><span class="kt">IBAction</span><span class="p">)</span><span class="nf">runRegex:</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="nv">sender</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">OnigRegexp</span><span class="o">*</span> <span class="n">regex</span> <span class="o">=</span> <span class="p">[</span><span class="n">OnigRegexp</span> <span class="nl">compile</span><span class="p">:[</span><span class="n">regexPattern</span> <span class="n">text</span><span class="p">]];</span>
</span></span><span class="line"><span class="cl">    <span class="n">OnigResult</span><span class="o">*</span> <span class="n">res</span> <span class="o">=</span> <span class="p">[</span><span class="n">regex</span> <span class="nl">match</span><span class="p">:[</span><span class="n">initialText</span> <span class="n">text</span><span class="p">]];</span>
</span></span><span class="line"><span class="cl">    <span class="n">NSMutableString</span><span class="o">*</span> <span class="n">tmpResult</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSMutableString</span> <span class="nl">stringWithString</span><span class="p">:</span><span class="s">@&#34;&#34;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="p">[</span><span class="n">res</span> <span class="n">count</span><span class="p">];</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="p">[</span><span class="n">tmpResult</span> <span class="nl">appendString</span><span class="p">:</span><span class="s">@&#34;(&#34;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="p">[</span><span class="n">tmpResult</span> <span class="nl">appendString</span><span class="p">:[</span><span class="n">res</span> <span class="nl">stringAt</span><span class="p">:</span><span class="n">i</span><span class="p">]];</span>
</span></span><span class="line"><span class="cl">        <span class="p">[</span><span class="n">tmpResult</span> <span class="nl">appendString</span><span class="p">:</span><span class="s">@&#34;)&#34;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">[</span><span class="n">result</span> <span class="nl">setText</span><span class="p">:</span><span class="n">tmpResult</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Essa aplicação de demonstração tem um text-field chamado &ldquo;initialText&rdquo;, onde você pode digitar qualquer string. Aí você prepara uma expressão regular no text-field &ldquo;regexPattern&rdquo; e, ao apertar o botão &ldquo;Run&rdquo;, ele dispara a action acima, que roda a expressão regular contra o texto inicial e escreve os matches entre parênteses na text view &ldquo;result&rdquo;. A aplicação fica assim:</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/4/24/Screen%20shot%202011-04-24%20at%2012.46.19%20AM_original.png?1303616748" alt=""  loading="lazy" /></p>
<p>E, <em>voilá</em>! Expressão regular ao estilo Ruby 1.9, direto do Oniguruma, dentro de uma aplicação iOS!</p>
]]></content:encoded><category>apple</category><category>programacao</category><category>tutoriais</category></item><item><title>[Objective-C] Categories, Static Libraries e Pegadinhas</title><link>https://akitaonrails.github.io/2011/04/23/objective-c-categories-static-libraries-e-pegadinhas/</link><guid isPermaLink="true">https://akitaonrails.github.io/2011/04/23/objective-c-categories-static-libraries-e-pegadinhas/</guid><pubDate>Sat, 23 Apr 2011 23:44:00 -0300</pubDate><description>&lt;p&gt;Como alguns de vocês já sabem, eu tenho um pequeno pet project chamado &lt;a href="https://github.com/akitaonrails/ObjC_Rubyfication"target="_blank" rel="noopener"&gt;ObjC Rubyfication&lt;/a&gt;, um exercício pessoal de escrever uma sintaxe parecida com Ruby dentro de Objective-C. A maior parte do projeto se aproveita do fato de que dá pra reabrir as classes padrão do Objective-C – muito parecido com Ruby, diferente do Java – e inserir nosso próprio código – através de &lt;a href="http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocCategories.html%23//apple_ref/doc/uid/TP30001163-CH20"target="_blank" rel="noopener"&gt;Categories&lt;/a&gt;, que são parecidas com os módulos do Ruby.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Como alguns de vocês já sabem, eu tenho um pequeno pet project chamado <a href="https://github.com/akitaonrails/ObjC_Rubyfication"target="_blank" rel="noopener">ObjC Rubyfication</a>, um exercício pessoal de escrever uma sintaxe parecida com Ruby dentro de Objective-C. A maior parte do projeto se aproveita do fato de que dá pra reabrir as classes padrão do Objective-C – muito parecido com Ruby, diferente do Java – e inserir nosso próprio código – através de <a href="http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocCategories.html%23//apple_ref/doc/uid/TP30001163-CH20"target="_blank" rel="noopener">Categories</a>, que são parecidas com os módulos do Ruby.</p>
<p>A ideia desse pet project é ser uma Static Library que eu possa adicionar facilmente em qualquer outro projeto e ter todas as suas funcionalidades disponíveis. Nesse artigo eu queria mostrar como estou organizando os vários subprojetos dentro de um projeto só (e estou aberto a sugestões e dicas pra melhorar isso, já que ainda estou aprendendo a organizar as coisas dentro de projetos Obj-C) e falar sobre uma pegadinha que me tomou horas pra descobrir e que talvez ajude alguém.</p>
<p>Pra deixar esse exercício ainda mais divertido, eu também adicionei um target separado pra minha suíte de testes unitários (e ver como o XCode dá suporte a testes), depois outro target pro framework BDD <a href="http://kiwi-lib.info/"target="_blank" rel="noopener">Kiwi</a> pra Obj-C, e mais um pro <a href="http://limechat.net/cocoaoniguruma/"target="_blank" rel="noopener">CocoaOniguruma</a> que eu acabei de explicar no <a href="http://www.akitaonrails.com/2011/04/23/objective-c-it%27s-a-unix-system-i-know-this"target="_blank" rel="noopener">artigo anterior</a>.</p>
<p>Eu venho brincando com formas de reorganizar o meu projeto e percebi que estava fazendo errado. Eu estava adicionando todos os arquivos fonte do meu target “Rubyfication” dentro do target Specs. Então tudo compilava direitinho, todas as specs passavam, mas a forma como eu definia as dependências estava errada. É meio complicado de entender no começo, mas deveria ser algo assim:</p>
<ul>
<li>Target CocoaOniguruma: deveria ser uma static library, sem dependências de target e sem bibliotecas binárias pra linkar, apenas com uma dependência do framework Foundation padrão. Ele expõe os headers OnigRegexp.h, OnigRegexpUtility.h e oniguruma.h como public headers.</li>
<li>Target Kiwi: deveria ser outra static library, sem dependências de target e sem bibliotecas binárias pra linkar, apenas com as dependências dos frameworks Foundation e UIKit.</li>
<li>Rubyfication: deveria ser outra static library, com CocoaOniguruma como dependência de target, linkando contra o binário libCocoaOniguruma.a e dependendo do framework Foundation também. Ele expõe todos os seus arquivos <tt>.h</tt> como public headers.</li>
<li>RubyficationTests: deveria ser um Bundle criado junto com o target Rubyfication (você pode especificar se quer um target de testes unitários quando cria novos targets), com Kiwi e Rubyfication como dependências de target, linkando contra os binários libKiwi.a e libRubyfication.a, e os frameworks Foundation e UIKit também.</li>
</ul>
<p>Se você ficar criando novos targets manualmente, o XCode 4 também vai criar um monte de Schemes que você nem precisa. Eu mantenho os meus limpos com apenas o scheme Rubyfication. Você pode acessar o menu “Product” e a opção “Edit Scheme”. Aí o meu Scheme fica assim:</p>
<!-- broken image (host offline/expired): http://s3.amazonaws.com/akitaonrails/assets/2011/4/23/Screen%20shot%202011-04-23%20at%2011.26.25%20PM_original.png -->
<p>Eu costumo configurar todos os meus build settings pra usar “LLVM Compiler 2.0” pras configurações de Debug e “LLVM GCC 4.2” pras configurações de Release (na verdade, eu faço isso por precaução porque não sei se o pessoal está realmente fazendo deploy de binários em produção compilados com LLVM).</p>
<p>Eu também configuro o <tt>“Targeted Device Family”</tt> pra “iPhone/iPad” e tento deixar o <tt>“iOS Deployment Target”</tt> em “iOS 3.0” sempre que possível. O pessoal normalmente deixa o padrão, que vai ser o release mais recente – atualmente 4.3. Cuidado porque o seu projeto pode não rodar em dispositivos mais antigos desse jeito.</p>
<p>Por fim, eu também garanto que os <tt>“Framework Search Paths”</tt> apontem pra estas opções:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>&#34;$(SDKROOT)/Developer/Library/Frameworks&#34;  
&#34;${DEVELOPER_LIBRARY_DIR}/Frameworks&#34;  </code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Tudo compila numa boa desse jeito. Aí eu posso apertar “Command-U” (ou ir no menu “Product”, opção “Test”) pra fazer o build do target “RubyficationTests”. Ele compila todas as dependências de target, linka tudo junto e roda o script final pra executar os testes (você precisa garantir que está selecionando o “Rubyfication – iPhone 4.3 Simulator” no menu de Schemes). Ele vai abrir o Simulator pra rodar as specs.</p>
<p>Mas aí eu estava recebendo:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>Test Suite &#39;/Users/akitaonrails/Library/Developer/Xcode/DerivedData/Rubyfication-gfqxbgyxicfpxugauehktilpmwzv/Build/Products/Debug-iphonesimulator/RubyficationTests.octest(Tests)&#39; started at 2011-04-24 02:16:27 &#43;0000  
Test Suite &#39;CollectionSpec&#39; started at 2011-04-24 02:16:27 &#43;0000  
Test Case &#39;-[CollectionSpec runSpec]&#39; started.  
2011-04-23 23:16:27.506 otest[40298:903] [__NSArrayI each:]: unrecognized selector sent to instance 0xe51a30  
2011-04-23 23:16:27.508 otest[40298:903] ***** Terminating app due to uncaught exception &#39;NSInvalidArgumentException&#39;, reason: &#39;[__NSArrayI each:]: unrecognized selector sent to instance 0xe51a30&#39;  </code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Ele diz que uma instância de <tt>NSArray</tt> não está reconhecendo o selector <tt>each:</tt> enviado pra ela no arquivo <tt>CollectionSpec</tt>. Provavelmente é esse trecho:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="cp"># import &#34;Kiwi.h&#34;  
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp"># import &#34;NSArray+functional.h&#34;  
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp"># import &#34;NSArray+helpers.h&#34;  
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp"># import &#34;NSArray+activesupport.h&#34;
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">SPEC_BEGIN</span><span class="p">(</span><span class="n">CollectionSpec</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">describe</span><span class="p">(</span><span class="s">@&#34;NSArray&#34;</span><span class="p">,</span> <span class="o">^</span><span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="k">__block</span> <span class="n">NSArray</span><span class="o">*</span> <span class="n">list</span> <span class="o">=</span> <span class="nb">nil</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">context</span><span class="p">(</span><span class="s">@&#34;Functional&#34;</span><span class="p">,</span> <span class="o">^</span><span class="p">{</span> <span class="n">beforeEach</span><span class="p">(</span><span class="o">^</span><span class="p">{</span> <span class="n">list</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSArray</span> <span class="nl">arrayWithObjects</span><span class="p">:</span><span class="s">@&#34;a&#34;</span><span class="p">,</span> <span class="s">@&#34;b&#34;</span><span class="p">,</span> <span class="s">@&#34;c&#34;</span><span class="p">,</span> <span class="nb">nil</span><span class="p">];</span> <span class="p">});</span> 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">it</span><span class="p">(</span><span class="s">@&#34;should iterate sequentially through the entire collection of items&#34;</span><span class="p">,</span> <span class="o">^</span><span class="p">{</span> <span class="n">NSMutableArray</span><span class="o">*</span> <span class="n">output</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></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="n">list</span> <span class="nl">each</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="kt">id</span> <span class="n">item</span><span class="p">)</span> <span class="p">{</span> <span class="p">[</span><span class="n">output</span> <span class="nl">addObject</span><span class="p">:</span><span class="n">item</span><span class="p">];</span> <span class="p">}];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">[[</span><span class="n">theValue</span><span class="p">([</span><span class="n">output</span> <span class="n">count</span><span class="p">])</span> <span class="n">should</span><span class="p">]</span> <span class="nl">equal</span><span class="p">:</span><span class="n">theValue</span><span class="p">([</span><span class="n">list</span> <span class="n">count</span><span class="p">])];</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="err">…</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Referência: <a href="https://github.com/akitaonrails/ObjC_Rubyfication/blob/master/RubyficationTests/CollectionSpec.m#L1-22"target="_blank" rel="noopener">CollectionSpec.m</a></p>
<p>Repare que na linha 3 está o import correto onde a category <tt>NSArray(Helpers)</tt> está definida com o método <tt>each:</tt> declarado certinho. O erro está acontecendo na spec da linha 18 do trecho acima.</p>
<p>Agora, isso não era um erro de compilação, era um erro de runtime. Então o import está achando o arquivo correto e compilando, mas algo na fase de linking não está indo bem e em runtime a category <tt>NSArray(Helpers)</tt>, e provavelmente outras categories, não estão disponíveis.</p>
<p>Levou algumas horas de pesquisa, mas finalmente descobri uma flag simples que mudou tudo, a flag de linker <a href="http://developer.apple.com/library/mac/#qa/qa1490/_index.html"target="_blank" rel="noopener">-all_load</a>. Como a documentação diz:</p>
<blockquote>
  <p><strong>Importante:</strong> Para aplicações de 64-bit e iPhone OS, existe um bug no linker que impede o <tt>-ObjC</tt> de carregar arquivos de objeto de static libraries que contêm apenas categories e nenhuma classe. O workaround é usar as flags <tt>-all_load</tt> ou <tt>-force_load</tt>.</p>
<p><tt>-all_load</tt> força o linker a carregar todos os arquivos de objeto de cada archive que ele encontra, mesmo aqueles sem código Objective-C. <tt>-force_load</tt> está disponível no Xcode 3.2 e posteriores. Ele permite um controle mais granular do carregamento de archives. Cada opção <tt>-force_load</tt> deve ser seguida por um caminho pra um archive, e cada arquivo de objeto naquele archive vai ser carregado.</p>

</blockquote>
<p>Então todo target que depende de static libraries externas que carregam Categories tem que adicionar essa flag <tt>-all_load</tt> em “Other Linker Flags”, na categoria “Linking” dentro de “Build Settings” do target, assim:</p>
<!-- broken image (host offline/expired): http://s3.amazonaws.com/akitaonrails/assets/2011/4/23/Screen%20shot%202011-04-23%20at%2011.41.27%20PM_original.png -->
<p>Então tanto o meu target <tt>RubyficationTests</tt> quanto o <tt>Rubyfication</tt> tiveram que receber essa nova flag. E agora todos os testes passam sem problema!</p>
]]></content:encoded><category>apple</category><category>programacao</category><category>tutoriais</category></item><item><title>[Objective-C] É um sistema Unix! Eu sei mexer nisso!</title><link>https://akitaonrails.github.io/2011/04/23/objective-c-e-um-sistema-unix-eu-sei-mexer-nisso/</link><guid isPermaLink="true">https://akitaonrails.github.io/2011/04/23/objective-c-e-um-sistema-unix-eu-sei-mexer-nisso/</guid><pubDate>Sat, 23 Apr 2011 22:47:00 -0300</pubDate><description>&lt;p&gt;Enquanto experimentava formas de usar Objective-C de um jeito mais parecido com como eu programo em Ruby, duas coisas me incomodaram um pouco. Primeiro, formatação de datas e, segundo, expressões regulares.&lt;/p&gt;
&lt;p&gt;O framework Cocoa tem ambos implementados como &lt;a href="http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/DataFormatting/Articles/dfDateFormatting10_4.html%23//apple_ref/doc/uid/TP40002369-SW1"target="_blank" rel="noopener"&gt;NSDateFormatter&lt;/a&gt; e &lt;a href="http://developer.apple.com/library/iOS/#documentation/Foundation/Reference/NSRegularExpression_Class/Reference/Reference.html"target="_blank" rel="noopener"&gt;NSRegularExpression&lt;/a&gt;, que por acaso também estão disponíveis para desenvolvimento iOS.&lt;/p&gt;
&lt;p&gt;Você pode formatar datas assim:&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;NSDateFormatter&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;dateFormatter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;NSDateFormatter&lt;/span&gt; &lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dateFormatter&lt;/span&gt; &lt;span class="nl"&gt;setDateStyle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;NSDateFormatterMediumStyle&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dateFormatter&lt;/span&gt; &lt;span class="nl"&gt;setTimeStyle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;NSDateFormatterNoStyle&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;NSDate&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NSDate&lt;/span&gt; &lt;span class="nl"&gt;dateWithTimeIntervalSinceReferenceDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;162000&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;NSString&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;formattedDateString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dateFormatter&lt;/span&gt; &lt;span class="nl"&gt;stringFromDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;NSLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;formattedDateString: %`&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;formattedDateString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Saída&lt;/span&gt; &lt;span class="n"&gt;para&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="n"&gt;locale&lt;/span&gt; &lt;span class="nl"&gt;en_US&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;formattedDateString: Jan 2, 2001&amp;#34;&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="Copy code"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;E você pode usar expressões regulares assim:&lt;/p&gt;</description><content:encoded><![CDATA[<p>Enquanto experimentava formas de usar Objective-C de um jeito mais parecido com como eu programo em Ruby, duas coisas me incomodaram um pouco. Primeiro, formatação de datas e, segundo, expressões regulares.</p>
<p>O framework Cocoa tem ambos implementados como <a href="http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/DataFormatting/Articles/dfDateFormatting10_4.html%23//apple_ref/doc/uid/TP40002369-SW1"target="_blank" rel="noopener">NSDateFormatter</a> e <a href="http://developer.apple.com/library/iOS/#documentation/Foundation/Reference/NSRegularExpression_Class/Reference/Reference.html"target="_blank" rel="noopener">NSRegularExpression</a>, que por acaso também estão disponíveis para desenvolvimento iOS.</p>
<p>Você pode formatar datas assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="n">NSDateFormatter</span> <span class="o">*</span><span class="n">dateFormatter</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSDateFormatter</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="n">dateFormatter</span> <span class="nl">setDateStyle</span><span class="p">:</span><span class="n">NSDateFormatterMediumStyle</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="n">dateFormatter</span> <span class="nl">setTimeStyle</span><span class="p">:</span><span class="n">NSDateFormatterNoStyle</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">NSDate</span> <span class="o">*</span><span class="n">date</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSDate</span> <span class="nl">dateWithTimeIntervalSinceReferenceDate</span><span class="p">:</span><span class="mi">162000</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">NSString</span> <span class="o">*</span><span class="n">formattedDateString</span> <span class="o">=</span> <span class="p">[</span><span class="n">dateFormatter</span> <span class="nl">stringFromDate</span><span class="p">:</span><span class="n">date</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"><span class="n">NSLog</span><span class="p">(</span><span class="err">`</span><span class="s">&#34;formattedDateString: %`&#34;</span><span class="p">,</span> <span class="n">formattedDateString</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"><span class="o">//</span> <span class="n">Saída</span> <span class="n">para</span> <span class="n">o</span> <span class="n">locale</span> <span class="nl">en_US</span><span class="p">:</span> <span class="s">&#34;formattedDateString: Jan 2, 2001&#34;</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E você pode usar expressões regulares assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">NSError</span> <span class="o">*</span><span class="n">error</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"><span class="n">NSRegularExpression</span> <span class="o">*</span><span class="n">regex</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSRegularExpression</span> <span class="nl">regularExpressionWithPattern</span><span class="p">:</span><span class="s">@&#34;</span><span class="se">\\</span><span class="s">b(a|b)(c|d)</span><span class="se">\\</span><span class="s">b&#34;</span>
</span></span><span class="line"><span class="cl"> <span class="nl">options</span><span class="p">:</span><span class="n">NSRegularExpressionCaseInsensitive</span>  
</span></span><span class="line"><span class="cl"> <span class="nl">error</span><span class="p">:</span><span class="o">&amp;</span><span class="n">error</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">NSUInteger</span> <span class="n">numberOfMatches</span> <span class="o">=</span> <span class="p">[</span><span class="n">regex</span> <span class="nl">numberOfMatchesInString</span><span class="p">:</span><span class="n">string</span>  
</span></span><span class="line"><span class="cl"> <span class="nl">options</span><span class="p">:</span><span class="mi">0</span>  
</span></span><span class="line"><span class="cl"> <span class="nl">range</span><span class="p">:</span><span class="n">NSMakeRange</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="n">string</span> <span class="n">length</span><span class="p">])];</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Mas eu tenho problemas com os dois. O equivalente em Ruby para o exemplo de formatação de datas seria:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;activesupport&#39;</span>  
</span></span><span class="line"><span class="cl"><span class="n">date</span> <span class="o">=</span> <span class="no">Time</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="s2">&#34;2001-01-01&#34;</span><span class="p">)</span> <span class="o">+</span> <span class="mi">162000</span><span class="o">.</span><span class="n">seconds</span>  
</span></span><span class="line"><span class="cl"><span class="n">date</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">&#34;%b %d, %Y&#34;</span><span class="p">)</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E o exemplo de expressão regular seria assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">number_of_matches</span> <span class="o">=</span> <span class="sr">/\W*[a|b][c|d]\W*/</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="n">string</span><span class="p">)</span><span class="o">.</span><span class="n">size</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Tem 2 coisas específicas que me incomodam:</p>
<ul>
<li>as versões em Obj-C parecem desnecessariamente verbosas. Eu entendo que elas são de mais baixo nível e provavelmente permitem mais flexibilidade, mas acho que deveriam ter versões mais &ldquo;porcelana&rdquo;, mais diretas.</li>
<li>em Obj-C, a formatação de datas usa o padrão <a href="http://unicode.org/reports/tr35/tr35-10.html#Date_Format_Patterns"target="_blank" rel="noopener">Unicode TR-35</a> e as expressões regulares usam o padrão <a href="http://userguide.icu-project.org/strings/regexp"target="_blank" rel="noopener">ICU</a>, que é inspirado nas expressões regulares de Perl com suporte a Unicode e vagamente baseado no java.util.regex do JDK 1.4.</li>
</ul>
<p>Então, a solução ideal para mim seria:</p>
<ul>
<li>ter versões de mais alto nível dessas funcionalidades;</li>
<li>ter formatação de datas com strftime compatível com C e expressões regulares no nível do Oniguruma do Ruby 1.9.</li>
</ul>
<h2>É um sistema Unix<span class="hx:absolute hx:-mt-20" id="é-um-sistema-unix"></span>
    <a href="#%c3%a9-um-sistema-unix" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Foi aí que me caiu a ficha do óbvio: Objective-C nada mais é que um superset de C, então qualquer coisa compatível com C é automaticamente compatível com Objective-C. Mais que isso, o <strong>iOS é um sistema Unix</strong>! Ou seja, ele tem todas as gostosuras do suporte Posix.</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/dFUlAQZB9Ng"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Então, como eu pego o <a href="http://www.cplusplus.com/reference/clibrary/ctime/strftime/"target="_blank" rel="noopener">strftime compatível com C</a>? Fácil:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="cp"># import &#34;time.h&#34;  
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">…</span>  
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">-</span> <span class="p">(</span><span class="n">NSString</span><span class="o">*</span><span class="p">)</span> <span class="nl">toFormattedString</span><span class="p">:(</span><span class="n">NSString</span><span class="o">*</span><span class="p">)</span><span class="n">format</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="n">time_t</span> <span class="n">unixTime</span> <span class="o">=</span> <span class="p">(</span><span class="n">time_t</span><span class="p">)</span> <span class="p">[</span><span class="nb">self</span> <span class="n">timeIntervalSince1970</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"> <span class="k">struct</span> <span class="n">tm</span> <span class="n">timeStruct</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"> <span class="n">localtime_r</span><span class="p">(</span><span class="o">&amp;</span><span class="n">unixTime</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">timeStruct</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="mi">30</span><span class="p">];</span> 
</span></span><span class="line"><span class="cl"><span class="n">strftime</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="mi">30</span><span class="p">,</span> <span class="p">[[</span><span class="n">NSDate</span> <span class="nl">formatter</span><span class="p">:</span><span class="n">format</span><span class="p">]</span> <span class="nl">cStringUsingEncoding</span><span class="p">:[</span><span class="n">NSString</span> <span class="n">defaultCStringEncoding</span><span class="p">]],</span> <span class="o">&amp;</span><span class="n">timeStruct</span><span class="p">);</span> <span class="n">NSString</span><span class="o">*</span> <span class="n">output</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSString</span> <span class="nl">stringWithCString</span><span class="p">:</span><span class="n">buffer</span> <span class="nl">encoding</span><span class="p">:[</span><span class="n">NSString</span> <span class="n">defaultCStringEncoding</span><span class="p">]];</span> 
</span></span><span class="line"><span class="cl"><span class="k">return</span> <span class="n">output</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Referência: <a href="https://github.com/akitaonrails/ObjC_Rubyfication/blob/master/Rubyfication/NSDate&#43;helpers.m#L71-80"target="_blank" rel="noopener">NSDate+helpers.m</a></p>
<p>Agora siga cada linha pra entender:</p>
<ul>
<li>Na linha 4 ele retorna o tempo atual representado como o número de segundos desde 1970. Esse método na verdade retorna um <tt>NSTimeInterval</tt>, que é um número essencialmente igual ao equivalente em C <tt>time_t</tt></li>
<li>Na linha 6 a função C <tt>localtime_r</tt> converte o número <tt>unitTime</tt> na estrutura C <tt>timeStruct</tt></li>
<li>Na linha 9 chamamos um método customizado que criei chamado <tt>formatter</tt>, que apenas devolve uma string de formato compatível com <tt>strftime</tt>. A string Obj-C (quando criamos com o símbolo &ldquo;@&rdquo;) é um objeto que precisamos converter para um array de chars usando <tt>cStringUsingEncoding:</tt>. Funções C não entendem string Obj-C, daí a conversão. Aí finalmente chamamos o próprio <tt>strftime</tt>, que vai armazenar o resultado no array de char <tt>buffer</tt> que declaramos antes.</li>
<li>Na linha 10 fazemos o caminho inverso e convertemos a C-string resultante (array de chars) de volta em uma String Obj-C.</li>
</ul>
<p>Agora isso fica muito bom. Adicionei alguns outros métodos auxiliares que agora me permitem usar assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="n">it</span><span class="p">(</span><span class="err">`</span><span class="s">&#34;should convert the date to the rfc822 format&#34;</span><span class="p">,</span> <span class="o">^</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">[[[</span><span class="n">ref</span> <span class="nl">toFormattedString</span><span class="p">:</span><span class="err">`</span><span class="s">&#34;rfc822&#34;</span><span class="p">]</span> <span class="n">should</span><span class="p">]</span> <span class="nl">equal</span><span class="p">:</span><span class="s">@&#34;Fri, 01 Jan 2010 10:15:30&#34;</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"><span class="p">});</span> </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Referência: <a href="https://github.com/akitaonrails/ObjC_Rubyfication/blob/master/RubyficationTests/DateSpec.m#L69"target="_blank" rel="noopener">DateSpec.m</a></p>
<p>E a string <tt>“rfc822”</tt> vai ser internamente convertida para <tt>@&quot;%a, %d %b %Y %H:%M:%S&quot;</tt> pelo seletor <a href="https://github.com/akitaonrails/ObjC_Rubyfication/blob/master/Rubyfication/NSDate&#43;helpers.m#L82-100"target="_blank" rel="noopener"><tt>formatter:</tt></a> na classe <tt>NSDate</tt>.</p>
<p>Agora, pra ter expressões regulares no nível do Ruby 1.9 você pode ir direto na fonte e usar o próprio <a href="http://www.geocities.jp/kosako3/oniguruma/"target="_blank" rel="noopener">Oniguruma</a> original baseado em C, exatamente o que o Ruby faz. Existem várias formas de integrar uma biblioteca C em um projeto Cocoa, mas alguém já fez todo o trabalho pesado. Satoshi Nakagawa escreveu um wrapper em Obj-C chamado <a href="http://limechat.net/cocoaoniguruma/"target="_blank" rel="noopener">CocoaOniguruma</a> que torna a integração no seu projeto absurdamente fácil.</p>
<p>Existem várias formas de integrar uma biblioteca externa no seu projeto. A forma mais fácil (embora não exatamente a melhor) que mostro aqui é criando um novo Static Library Target dentro do meu projeto, chamado <em>CocoaOniguruma</em>:</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/4/23/Screen%20shot%202011-04-23%20at%2010.33.47%20PM_original.png?1303608817" alt=""  loading="lazy" /></p>
<p>Isso vai criar um novo Group chamado <em>CocoaOniguruma</em> no seu projeto. Depois é só adicionar todos os arquivos da <a href="https://github.com/psychs/cocoaoniguruma/tree/master/framework/core"target="_blank" rel="noopener">pasta core do CocoaOniguruma</a> nesse grupo, selecionar o novo target e todos os arquivos fonte e headers serão devidamente adicionados ao projeto, assim:</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/4/23/Screen%20shot%202011-04-23%20at%2010.37.19%20PM_original.png?1303608987" alt=""  loading="lazy" /></p>
<p>Por fim, você precisa ir no target principal original da sua aplicação e adicionar tanto o novo target nas dependências de target quanto o binário <tt>.a</tt> na seção de linking de binários, assim:</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/4/23/Screen%20shot%202011-04-23%20at%2010.39.07%20PM_original.png?1303609098" alt=""  loading="lazy" /></p>
<p>Com tudo isso configurado, recomendo explorar o <tt>OnigRegexp.m</tt> e o <tt>OnigRegexpUtility.m</tt>, que são wrappers Obj-C para a biblioteca Oniguruma. O autor já deixou uma sintaxe bem ao estilo Ruby pra você usar.</p>
<p>Embrulhei esses helpers nas minhas próprias classes assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="p">-</span> <span class="p">(</span><span class="n">NSString</span><span class="o">*</span><span class="p">)</span> <span class="nf">gsub:</span><span class="p">(</span><span class="n">NSString</span><span class="o">*</span><span class="p">)</span><span class="nv">pattern</span> <span class="nf">with:</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="nv">replacement</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">([</span><span class="n">replacement</span> <span class="nl">isKindOfClass</span><span class="p">:[</span><span class="n">NSString</span> <span class="k">class</span><span class="p">]])</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">[</span><span class="nb">self</span> <span class="nl">replaceAllByRegexp</span><span class="p">:</span><span class="n">pattern</span> <span class="nl">with</span><span class="p">:</span><span class="n">replacement</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">([</span><span class="n">replacement</span> <span class="nl">isKindOfClass</span><span class="p">:[</span><span class="n">NSArray</span> <span class="k">class</span><span class="p">]])</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="k">__block</span> <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">[</span><span class="nb">self</span> <span class="nl">replaceAllByRegexp</span><span class="p">:</span><span class="n">pattern</span> <span class="nl">withBlock</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="n">OnigResult</span><span class="o">*</span> <span class="n">obj</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">[</span><span class="n">NSString</span><span class="o">*</span><span class="p">](</span><span class="n">replacement</span> <span class="nl">objectAtIndex</span><span class="p">:(</span><span class="o">++</span><span class="n">i</span><span class="p">));</span>  
</span></span><span class="line"><span class="cl"> <span class="p">}];</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>  
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nb">nil</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">-</span> <span class="p">(</span><span class="n">NSString</span><span class="o">*</span><span class="p">)</span> <span class="nf">gsub:</span><span class="p">(</span><span class="n">NSString</span><span class="o">*</span><span class="p">)</span><span class="nv">pattern</span> <span class="nf">withBlock:</span><span class="p">(</span><span class="n">NSString</span><span class="o">*</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">OnigResult</span><span class="o">*</span><span class="p">))</span><span class="nv">replacement</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">[</span><span class="nb">self</span> <span class="nl">replaceAllByRegexp</span><span class="p">:</span><span class="n">pattern</span> <span class="nl">withBlock</span><span class="p">:</span><span class="n">replacement</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Referência: <a href="https://github.com/akitaonrails/ObjC_Rubyfication/blob/master/Rubyfication/NSString&#43;helpers.m#L176-190"target="_blank" rel="noopener">NSString+helpers.m</a></p>
<p>O que agora me permite usar essa sintaxe mais agradável:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="n">context</span><span class="p">(</span><span class="err">`</span><span class="s">&#34;Regular Expressions&#34;</span><span class="p">,</span> <span class="o">^</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">it</span><span class="p">(</span><span class="err">`</span><span class="s">&#34;should replace all substrings that match the pattern&#34;</span><span class="p">,</span> <span class="o">^</span><span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="p">[[[</span><span class="err">`</span><span class="s">&#34;hello world, heyho!&#34;</span> <span class="nl">gsub</span><span class="p">:</span><span class="err">`</span><span class="s">&#34;h</span><span class="se">\\</span><span class="s">w+&#34;</span> <span class="nl">with</span><span class="p">:</span><span class="err">`</span><span class="s">&#34;hi&#34;</span><span class="p">]</span> <span class="n">should</span><span class="p">]</span> <span class="nl">equal</span><span class="p">:</span><span class="err">`</span><span class="s">&#34;hi world, hi!&#34;</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">it</span><span class="p">(</span><span class="s">@&#34;should replace each substrings with one corresponding replacement in the array&#34;</span><span class="p">,</span> <span class="o">^</span><span class="p">{</span> <span class="n">NSArray</span><span class="o">*</span> <span class="n">replacements</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSArray</span> <span class="nl">arrayWithObjects</span><span class="p">:</span><span class="s">@&#34;hi&#34;</span><span class="p">,</span> <span class="s">@&#34;everybody&#34;</span><span class="p">,</span> <span class="nb">nil</span><span class="p">];</span> <span class="p">[[[</span><span class="err">`</span><span class="s">&#34;hello world, heyho!&#34;</span> <span class="nl">gsub</span><span class="p">:</span><span class="err">`</span><span class="s">&#34;h</span><span class="se">\\</span><span class="s">w+&#34;</span> <span class="nl">with</span><span class="p">:</span><span class="n">replacements</span><span class="p">]</span> <span class="n">should</span><span class="p">]</span> <span class="nl">equal</span><span class="p">:</span><span class="s">@&#34;hi world, everybody!&#34;</span><span class="p">];</span> <span class="p">});</span> <span class="n">it</span><span class="p">(</span><span class="s">@&#34;should replace each substring with the return of the block&#34;</span><span class="p">,</span> <span class="o">^</span><span class="p">{</span> <span class="p">[[[</span><span class="err">`</span><span class="s">&#34;hello world, heyho!&#34;</span> <span class="nl">gsub</span><span class="p">:</span><span class="err">`</span><span class="s">&#34;h</span><span class="se">\\</span><span class="s">w+&#34;</span> <span class="nl">withBlock</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="n">OnigResult</span><span class="o">*</span> <span class="n">obj</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="s">@&#34;foo&#34;</span><span class="p">;</span> <span class="p">}]</span> <span class="n">should</span><span class="p">]</span> <span class="nl">equal</span><span class="p">:</span><span class="s">@&#34;foo world, foo!&#34;</span><span class="p">];</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Referência: <a href="https://github.com/akitaonrails/ObjC_Rubyfication/blob/master/RubyficationTests/StringSpec.m#L86-102"target="_blank" rel="noopener">StringSpec.m</a></p>
<p>Se você está achando estranho um trecho de código Objective-C ter palavras-chave como <tt>context</tt> ou <tt>it</tt>, elas vêm do <a href="http://www.kiwi-lib.info/"target="_blank" rel="noopener">Kiwi</a>, que constrói um framework de testes BDD ao estilo RSpec em cima do SenTesting Kit para desenvolvimento Objective-C, e que você definitivamente deveria conferir. Mas o código acima deve ser fácil de entender mesmo sem conhecer o Kiwi. Se você é desenvolvedor Ruby, provavelmente vai notar que a sintaxe tem certa semelhança com o que você já está acostumado.</p>
<p>Então, linkar com bibliotecas C padrão existentes ou até com bibliotecas C open source de terceiros é moleza pra esses casos simples, sem precisar recorrer a nenhum tunelamento de &ldquo;Native Interface&rdquo; entre máquinas virtuais ou qualquer outra encanação. Se você quer C, ele está aí pra você integrar e usar facilmente.</p>
]]></content:encoded><category>apple</category><category>programacao</category><category>tutoriais</category></item><item><title>[Off-Topic] iOS Development and Open Source Libraries</title><link>https://akitaonrails.github.io/2011/03/26/off-topic-ios-development-and-open-source-libraries/</link><guid isPermaLink="true">https://akitaonrails.github.io/2011/03/26/off-topic-ios-development-and-open-source-libraries/</guid><pubDate>Sat, 26 Mar 2011 15:59:00 -0300</pubDate><description>&lt;p&gt;I&amp;rsquo;ve been following the evolution of iOS development, and it keeps getting easier to assemble a quality application. Apple just released iOS 4.3.1 and Xcode 4.0.1, and the new Xcode is a big step forward. I think this is the first major IDE to support Git as a first class citizen in the development workflow. Every serious IDE should do that, and any serious developer should be comfortable with Git by now.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I&rsquo;ve been following the evolution of iOS development, and it keeps getting easier to assemble a quality application. Apple just released iOS 4.3.1 and Xcode 4.0.1, and the new Xcode is a big step forward. I think this is the first major IDE to support Git as a first class citizen in the development workflow. Every serious IDE should do that, and any serious developer should be comfortable with Git by now.</p>
<p>The new LLVM Compiler 2.0 is impressive and helps a lot in writing memory leak free applications. I don&rsquo;t buy the <em>&ldquo;it is too difficult doing memory management&rdquo;</em> complaint, which usually just means <em>&ldquo;I&rsquo;m too lazy and cheap&rdquo;</em>. Come on, there are thousands of quality apps for both OS X and iOS.</p>
<p>Memory management is a bit harder than leaning on a full featured generational garbage collector, but it&rsquo;s nowhere near as hard as some people claim. Any reasonable developer can handle it with minimal effort.</p>
<p>The community keeps releasing great libraries that push productivity even further. Let me list a few of my favorites:</p>
<ul>
<li><a href="http://web.archive.org/web/20110326193919/http://www.flurry.com/"target="_blank" rel="noopener">Flurry</a> is the iOS equivalent of Google Analytics. Everything is trackable now: who is using your app, how they use it, which features get the most and least use, and in which regions. You feed that data back into the product to refine it. It ships SDKs for Java ME, Blackberry, Android, Windows Phone and iOS. You sign up, register your application, and get a unique application key that you hard code into the app. It is literally as easy as this:</li>
</ul>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="cp">#import &#34;FlurryAPI.h&#34;
</span></span></span><span class="line"><span class="cl"><span class="p">...</span>
</span></span><span class="line"><span class="cl"><span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="nl">applicationDidFinishLaunching</span><span class="p">:(</span><span class="n">NSNotification</span><span class="o">*</span><span class="p">)</span> <span class="n">notice</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">[</span><span class="n">FlurryAPI</span> <span class="nl">startSession</span><span class="p">:</span><span class="s">@&#34;your_unique_app_key&#34;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">...</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>There are several other methods to count events, log page views, log exceptions and errors, and even location. Mandatory for every app.</p>
<ul>
<li><a href="https://allseeing-i.com/ASIHTTPRequest/"target="_blank" rel="noopener">ASIHTTPRequest</a> handles the fact that most apps integrate with some web based back-end. Twitter, Facebook, LinkedIn, everything logs into some cloud service to grab information and collaborate. Cocoa Touch has a rich set of networking capabilities, but they sit at a lower level than most people want. Making background connections, tracking success or failure, triggering events and loading cues for the user, it all gets tedious. ASIHTTPRequest makes reliable connections to any web endpoint strikingly easy. The documentation is good enough and the code is even simpler:</li>
</ul>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="p">-</span> <span class="p">(</span><span class="kt">IBAction</span><span class="p">)</span><span class="nf">grabURLInTheBackground:</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="nv">sender</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="p">[</span><span class="nb">self</span> <span class="n">queue</span><span class="p">])</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="p">[</span><span class="nb">self</span> <span class="nl">setQueue</span><span class="p">:[[[</span><span class="n">NSOperationQueue</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">]</span> <span class="n">autorelease</span><span class="p">]];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">NSURL</span> <span class="o">*</span><span class="n">url</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSURL</span> <span class="nl">URLWithString</span><span class="p">:</span><span class="s">@&#34;http://allseeing-i.com&#34;</span><span class="p">];</span> <span class="n">ASIHTTPRequest</span> <span class="o">*</span><span class="n">request</span> <span class="o">=</span> <span class="p">[</span><span class="n">ASIHTTPRequest</span> <span class="nl">requestWithURL</span><span class="p">:</span><span class="n">url</span><span class="p">];</span> <span class="p">[</span><span class="n">request</span> <span class="nl">setDelegate</span><span class="p">:</span><span class="nb">self</span><span class="p">];</span> <span class="p">[</span><span class="n">request</span> <span class="nl">setDidFinishSelector</span><span class="p">:</span><span class="k">@selector</span><span class="p">(</span><span class="nl">requestDone</span><span class="p">:)];</span> <span class="p">[</span><span class="n">request</span> <span class="nl">setDidFailSelector</span><span class="p">:</span><span class="k">@selector</span><span class="p">(</span><span class="nl">requestWentWrong</span><span class="p">:)];</span> <span class="p">[[</span><span class="nb">self</span> <span class="n">queue</span><span class="p">]</span> <span class="nl">addOperation</span><span class="p">:</span><span class="n">request</span><span class="p">];</span> <span class="c1">//queue is an NSOperationQueue
</span></span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">requestDone:</span><span class="p">(</span><span class="n">ASIHTTPRequest</span> <span class="o">*</span><span class="p">)</span><span class="nv">request</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">NSString</span> <span class="o">*</span><span class="n">response</span> <span class="o">=</span> <span class="p">[</span><span class="n">request</span> <span class="n">responseString</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">requestWentWrong:</span><span class="p">(</span><span class="n">ASIHTTPRequest</span> <span class="o">*</span><span class="p">)</span><span class="nv">request</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">NSError</span> <span class="o">*</span><span class="n">error</span> <span class="o">=</span> <span class="p">[</span><span class="n">request</span> <span class="n">error</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The library creates network queues, so you can fire as many requests as you want and it manages the queue in the background. There are use case examples in the <a href="https://allseeing-i.com/ASIHTTPRequest/How-to-use/"target="_blank" rel="noopener">documentation</a>. You can skip the low level base classes and delegate all HTTP requests to it. Highly recommended.</p>
<ul>
<li><a href="http://web.archive.org/web/20110423000036/https://github.com/TouchCode/TouchJSON"target="_blank" rel="noopener">TouchJSON</a>: if you consume online HTTP data, you will probably get a JSON payload (another trend of the moment) that you need to parse into meaningful Objective-C objects. Objective-C is dynamic and flexible in its type system, so converting anything is easy. The parsing itself is tedious, and this library takes care of it. Use ASIHTTPRequest to connect to the server, and once it returns, parse the response blob like this:</li>
</ul>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="p">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">requestDone:</span><span class="p">(</span><span class="n">ASIHTTPRequest</span> <span class="o">*</span><span class="p">)</span><span class="nv">request</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">NSString</span> <span class="o">*</span><span class="n">response</span> <span class="o">=</span> <span class="p">[</span><span class="n">request</span> <span class="n">responseString</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="n">NSError</span> <span class="o">*</span><span class="n">theError</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">NSDictionary</span> <span class="o">*</span><span class="n">theDictionary</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSDictionary</span> <span class="nl">dictionaryWithJSONString</span><span class="p">:</span><span class="n">response</span> <span class="nl">error</span><span class="p">:</span><span class="o">&amp;</span><span class="n">theError</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Super easy. It deserializes a JSON string into a graph of Objective-C objects, and it goes the other way too, turning objects back into JSON so you can POST it somewhere or save it to a local file.</p>
<ul>
<li>ShareKit rides the trend that every piece of app content should be shareable. Whenever your users share something with their friends, your app gets more visibility, which is great marketing. You want the app to share content through email, Twitter, Facebook and other social networks. The <a href="http://web.archive.org/web/20110319200447/http://www.getsharekit.com/docs"target="_blank" rel="noopener">documentation</a> is good, the views are all customizable, and it takes care of the boring details of logging into each service and making the connections. It is also extensible, so adding a new online service later is easy. Follow the <a href="http://web.archive.org/web/20110321130554/http://getsharekit.com/install"target="_blank" rel="noopener">installation instructions</a>; in the end it comes down to adding a UIBarButtonItem like this:</li>
</ul>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="p">[[</span><span class="n">UIBarButtonItem</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithBarButtonSystemItem</span><span class="p">:</span><span class="n">UIBarButtonSystemItemAction</span>
</span></span><span class="line"><span class="cl">    <span class="nl">target</span><span class="p">:</span><span class="nb">self</span>
</span></span><span class="line"><span class="cl">    <span class="nl">action</span><span class="p">:</span><span class="k">@selector</span><span class="p">(</span><span class="n">share</span><span class="p">)]</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And adding the event handler code:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="p">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">myButtonHandlerAction</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// Create the item to share (in this example, a url)
</span></span></span><span class="line"><span class="cl">    <span class="n">NSURL</span> <span class="o">*</span><span class="n">url</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSURL</span> <span class="nl">URLWithString</span><span class="p">:</span><span class="s">@&#34;http://getsharekit.com&#34;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="n">SHKItem</span> <span class="o">*</span><span class="n">item</span> <span class="o">=</span> <span class="p">[</span><span class="n">SHKItem</span> <span class="nl">URL</span><span class="p">:</span><span class="n">url</span> <span class="nl">title</span><span class="p">:</span><span class="s">@&#34;ShareKit is Awesome!&#34;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Get the ShareKit action sheet
</span></span></span><span class="line"><span class="cl">    <span class="n">SHKActionSheet</span> <span class="o">*</span><span class="n">actionSheet</span> <span class="o">=</span> <span class="p">[</span><span class="n">SHKActionSheet</span> <span class="nl">actionSheetForItem</span><span class="p">:</span><span class="n">item</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Display the action sheet
</span></span></span><span class="line"><span class="cl">    <span class="p">[</span><span class="n">actionSheet</span> <span class="nl">showFromToolbar</span><span class="p">:</span><span class="n">navigationController</span><span class="p">.</span><span class="n">toolbar</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Can&rsquo;t get easier than that.</p>
<ul>
<li><a href="https://code.google.com/archive/p/simple-iphone-image-processing"target="_blank" rel="noopener">simple-iphone-image-processing</a> covers another important area: dealing with images. Every new smartphone has a camera, and it pays to leverage it. Snapping a picture and saving the file is just the start; you will often want to process the image to extract meaningful information.</li>
</ul>
<p>Want to be inspired? Look at this <a href="https://www.youtube.com/watch?v=oImMJ6p6mKE"target="_blank" rel="noopener">Sudoku application demo</a> built on this image processing library. You point the camera at any Sudoku printed in a newspaper, and the app parses the image, detects the grid, and builds a fully functional digital representation you can then solve with well known algorithms. How cool is that?</p>
<p>One caveat: the library is old, with its last commit from 2009, so I am not sure how it behaves on current iOS releases. The documentation is close to none, so you will have to dig through the source. I haven&rsquo;t tried it myself; I&rsquo;m adding it here as a note to run further experiments later.</p>
<ul>
<li>
<p><a href="http://cocos2d.org/"target="_blank" rel="noopener">cocos2d</a> steps in when simple list based apps get boring and you want animation and interactivity. You can use Apple&rsquo;s standard Core Graphics and Core Animation APIs, or go crazy with cocos2d. It is an OpenGL accelerated 2D API, so great effects are easy to build, and the cross platform wrappers let you carry the knowledge to other platforms. There are plenty of tutorials online, such as this Box2D data tool writeup, <a href="http://web.archive.org/web/20110325002808/http://maniacdev.com/2011/02/cross-platform-cocos2d-game-engine-using-cpp/"target="_blank" rel="noopener">this cross platform engine</a>, and <a href="http://bit.ly/eKHOqw"target="_blank" rel="noopener">more</a>. Worth studying.</p>
</li>
<li>
<p><a href="http://web.archive.org/web/20110317060458/http://www.iphonear.org/"target="_blank" rel="noopener">iPhone AR Kit</a> is not entirely mature yet, I think, but plenty of apps already use it and it should evolve fast. The idea is to turn on the camera, process the image frames, and lay 2D or 3D animation on top, so the digital objects seem to interact with the real time background. Pair that with the device&rsquo;s motion sensors (compass, gyroscope, accelerometer) and you can build genuinely impressive apps. Worth studying.</p>
</li>
<li>
<p><a href="https://github.com/allending/Kiwi"target="_blank" rel="noopener">Kiwi</a> and Gh-Unit: unfortunately, testing is not well understood or practiced in the Objective-C community. Many Rubyists who also write Objective-C are trying to bring over the practices we take for granted in Ruby, so I hope this helps. Cocoa and Xcode ship basic unit testing tools like SenTestingKit. Documentation is close to zero; you can read Apple&rsquo;s official <a href="http://web.archive.org/web/20110411203656/http://developer.apple.com/library/ios/DOCUMENTATION/Xcode/Conceptual/iphone_development/135-Unit_Testing_Applications/unit_testing_applications.html"target="_blank" rel="noopener">logic testing</a> article and this <a href="http://www.grokkingcocoa.com/how_to_debug_iphone_unit_te.html"target="_blank" rel="noopener">blog post</a>. The default tools are basic, so it is worth checking out other frameworks like Gh-Unit and Kiwi. Kiwi in particular looks impressive, following an RSpec-like syntax:</p>
</li>
</ul>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="n">describe</span><span class="p">(</span><span class="s">@&#34;Team&#34;</span><span class="p">,</span> <span class="o">^</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">context</span><span class="p">(</span><span class="s">@&#34;when newly created&#34;</span><span class="p">,</span> <span class="o">^</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">it</span><span class="p">(</span><span class="s">@&#34;should have a name&#34;</span><span class="p">,</span> <span class="o">^</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="kt">id</span> <span class="n">team</span> <span class="o">=</span> <span class="p">[</span><span class="n">Team</span> <span class="n">team</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">            <span class="p">[[</span><span class="n">team</span><span class="p">.</span><span class="n">name</span> <span class="n">should</span><span class="p">]</span> <span class="nl">equal</span><span class="p">:</span><span class="s">@&#34;Black Hawks&#34;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">it</span><span class="p">(</span><span class="s">@&#34;should have 11 players&#34;</span><span class="p">,</span> <span class="o">^</span><span class="p">{</span> <span class="kt">id</span> <span class="n">team</span> <span class="o">=</span> <span class="p">[</span><span class="n">Team</span> <span class="n">team</span><span class="p">];</span> <span class="p">[[[</span><span class="n">team</span> <span class="n">should</span><span class="p">]</span> <span class="nl">have</span><span class="p">:</span><span class="mi">11</span><span class="p">]</span> <span class="n">players</span><span class="p">];</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Both are worth checking out. We should push more testing technique and tooling into Objective-C development. We did it in Ruby land, and there is no reason we can&rsquo;t do the same here.</p>
<p>That&rsquo;s it for now. There are many more great libraries and tools out there, and iOS is evolving fast, so all of this is exciting to follow and practice. I hope to contribute back soon.</p>
]]></content:encoded><category>mobile</category><category>apple</category><category>programacao</category><category>off-topic</category></item><item><title>[Documentário] The iPod Revolution</title><link>https://akitaonrails.github.io/2011/01/30/documentario-the-ipod-revolution/</link><guid isPermaLink="true">https://akitaonrails.github.io/2011/01/30/documentario-the-ipod-revolution/</guid><pubDate>Sun, 30 Jan 2011 12:23:00 -0200</pubDate><description>&lt;p&gt;Pelo que consegui pesquisar, em 27 de dezembro de 2006 o Discovery Channel apresentou o documentário “The iPod Revolution: Inside Story of the Apple iPod and Steve Jobs”.&lt;/p&gt;
&lt;p&gt;Esse documentário é muito bem produzido. Em 40 minutos ele resume a história da Apple de 1997 a 2006, cobrindo quase uma década que vai do retorno de Steve Jobs ao lançamento do iPod e ao sucesso gigantesco da iTunes Music Store. E isso é só metade da história: o iPhone só seria revelado em janeiro de 2007, então o enredo é ainda maior.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Pelo que consegui pesquisar, em 27 de dezembro de 2006 o Discovery Channel apresentou o documentário “The iPod Revolution: Inside Story of the Apple iPod and Steve Jobs”.</p>
<p>Esse documentário é muito bem produzido. Em 40 minutos ele resume a história da Apple de 1997 a 2006, cobrindo quase uma década que vai do retorno de Steve Jobs ao lançamento do iPod e ao sucesso gigantesco da iTunes Music Store. E isso é só metade da história: o iPhone só seria revelado em janeiro de 2007, então o enredo é ainda maior.</p>
<p>Sempre recomendo pesquisar essa história porque ela é muito interessante e engajante. Para mais detalhes leiam os livros:</p>
<ul>
<li><a href="http://www.amazon.com/Perfect-Thing-Shuffles-Commerce-Coolness/dp/B001GVJCF6/ref=pd_sim_b_46"target="_blank" rel="noopener">The Perfect Thing: How the iPod Shuffles Commerce, Culture, and Coolness</a> – do Steven Levy.</li>
<li><a href="http://www.amazon.com/Cult-iPod-Leander-Kahney/dp/1593270666/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1296395947&amp;sr=8-1"target="_blank" rel="noopener">The Cult of the iPod</a> – do Leander Kahney que também aparece no documentário.</li>
<li><a href="http://www.amazon.com/iCon-Steve-Jobs-Greatest-Business/dp/0471787841/ref=sr_1_1?s=books&amp;ie=UTF8&amp;qid=1296396002&amp;sr=1-1"target="_blank" rel="noopener">iCon Steve Jobs: The Greatest Second Act in the History of Business</a> – do Jeffrey Young e William Simon.</li>
</ul>
<p>Como sempre mostro esse vídeo aos amigos que se interessam, resolvi que já passava da hora de legendar. Nem todo mundo a quem mostro é da área de tecnologia e, pra variar, inglês é um problema, mas isso é outro assunto. Se quiserem o arquivo de legenda, <a href="https://gist.github.com/802874"target="_blank" rel="noopener">criei um Gist</a> com ele. Para legendar usei o <a href="http://www.fluffalopefactory.com/miyu/download.html"target="_blank" rel="noopener">Miyu</a>, para renderizar a legenda no vídeo usei o <a href="http://www.bitfield.se/submerge/"target="_blank" rel="noopener">Submerge</a>, e por fim subi tudo na minha conta no Blip.tv. Assistam a seguir:</p>
<script type="text/javascript">
    jwplayer('playermbIDnNDsKnnR').setup({
        file: 'https://s3.amazonaws.com/videos-akitaonrails/Akitaonrails-iPodRevolutionPtBR748.m4v.mp4',
        title: 'Discovery Documentary - iPod Revolution (pt-BR)',
        width: '100%',
        aspectratio: '4:3',
        fallback: 'false'
    });
</script>
<p>Claro, o vídeo é propriedade da Discovery Channel, com todos os direitos reservados. Este material não deve ser usado para fins lucrativos. Ele já está disponível em vários outros sites, mas retiro o vídeo se for preciso. Caso eu retire, ainda há outras fontes, por exemplo no YouTube:</p>
<ul>
<li><a href="http://www.youtube.com/watch?v=iYumjyXEFms"target="_blank" rel="noopener">The iPod Revolution – Part One</a></li>
<li><a href="http://www.youtube.com/watch?v=K4rFh62Q1Rg"target="_blank" rel="noopener">The iPod Revolution – Part Two</a></li>
<li><a href="http://www.youtube.com/watch?v=b9rG_NOr44Q"target="_blank" rel="noopener">The iPod Revolution – Part Three</a></li>
<li><a href="http://www.youtube.com/watch?v=ZCriPTBlKQk"target="_blank" rel="noopener">The iPod Revolution – Part Four</a></li>
<li><a href="http://www.youtube.com/watch?v=QDTUFHJHEt4"target="_blank" rel="noopener">The iPod Revolution – Part Five</a></li>
</ul>
<p>Mas a história é bem mais interessante que isso. Já li e assisti todo o material disponível sobre o assunto desde 1983. Pesquisando, encontrei alguns pedaços dessa história no YouTube também. Seguem mais links de vídeos:</p>
<ul>
<li>
<p><a href="http://www.youtube.com/watch?v=lSiQA6KKyJo"target="_blank" rel="noopener">1983</a> – Neste keynote, um jovem Steve Jobs, que acabara de transformar a Apple numa superpotência, fala sobre seus planos para um novo computador que seria lançado em 1984. É um discurso épico. No final, ele apresenta o comercial mais famoso do mundo, o <a href="http://www.youtube.com/watch?v=OYecfV3ubP8"target="_blank" rel="noopener">1984</a>, dirigido por Ridley Scott e exibido uma única vez, no Super Bowl do ano seguinte.</p>
</li>
<li>
<p><a href="http://www.youtube.com/watch?v=PEHNrqPkefI"target="_blank" rel="noopener">Boston Macworld 1997</a> – Steve Jobs foi afastado da Apple em 1985 e retorna mais de 11 anos depois a uma Apple devastada, perdendo US$ 1 bilhão por ano, com gente como Michael Dell dizendo <a href="http://www.nytimes.com/2006/01/16/technology/16apple.html"target="_blank" rel="noopener">Se eu fosse a Apple, fecharia tudo e devolveria o dinheiro aos acionistas</a>. Ele expõe os problemas, aponta os pontos ainda fortes da Apple e traça uma estratégia de recuperação totalmente contrária à de todos os “analistas”. Recomendo a qualquer um que se preocupe com gestão: como se reerguer de uma queda.</p>
</li>
<li>
<p><a href="http://www.youtube.com/watch?v=0BHPtoTctDY"target="_blank" rel="noopener">Macworld 1998</a> – Um ano depois do retorno, Steve já reformou toda a Apple e lança o primeiro produto que marca esse recomeço: o iMac colorido. Era um computador voltado principalmente ao nascente mercado de internet para consumidores. Lembrando que ainda é o começo da primeira bolha da internet.</p>
</li>
<li>
<p><a href="http://www.youtube.com/watch?v=vy01RzqA5RA"target="_blank" rel="noopener">iPod Introduction 2001</a> – Trecho da apresentação em que Steve mostra o iPod pela primeira vez. Foi um evento fechado, dentro do campus da Apple, apenas para jornalistas convidados. O primeiro dia de uma revolução como nenhum dos presentes poderia imaginar.</p>
</li>
<li>
<p><a href="http://www.youtube.com/watch?v=B2n86TROxzY"target="_blank" rel="noopener">iTunes Store Introduction 2003</a> – Com softwares como Napster e Limewire permitindo baixar músicas de graça, como vender um sistema em que você precisa pagar pela música? Esse vídeo mostra como Steve conseguiu. O mais importante foi dobrar os Big 5 da indústria musical a aceitar um preço único e fixo para faixas avulsas e álbuns, e convencer os artistas a fragmentar os álbuns para vender músicas individuais.</p>
</li>
<li>
<p>“iPhone Introduction 2007” – Este é genial. Depois de dois anos e meio trabalhando em segredo, em meio a rumores crescentes sobre um iPod-phone, veja como Steve redefiniu o mercado de smartphones. Um ponto fundamental: o controle dos aparelhos sempre foi dos carriers, mas Steve negociou um contrato inédito com a Cingular (hoje AT&amp;T) em que o aparelho continuava sob controle da Apple. Ou seja, nada de aplicativos de marketing pré-instalados e coisas do tipo. Neste ano acabou a exclusividade com a AT&amp;T, e a Apple acaba de anunciar o iPhone em versão CDMA para os potenciais 93 milhões de clientes da Verizon.</p>
</li>
<li>
<p><a href="http://www.youtube.com/watch?v=ASkis57blsc"target="_blank" rel="noopener">Part 1</a></p>
</li>
<li>
<p><a href="http://www.youtube.com/watch?v=9VLb5XdxRm8"target="_blank" rel="noopener">Part 2</a></p>
</li>
<li>
<p><a href="http://www.youtube.com/watch?v=EeWj_6OeCTU"target="_blank" rel="noopener">Part 3</a></p>
</li>
<li>
<p><a href="http://www.youtube.com/watch?v=8awh59s0nEs"target="_blank" rel="noopener">Part 4</a></p>
</li>
<li>
<p><a href="http://www.youtube.com/watch?v=qIJoCw679ks"target="_blank" rel="noopener">Part 5</a></p>
</li>
<li>
<p><a href="http://www.youtube.com/watch?v=WKuM8lVOCg8"target="_blank" rel="noopener">Part 6</a></p>
</li>
<li>
<p><a href="http://www.youtube.com/watch?v=VPs8ECaZ__E"target="_blank" rel="noopener">Part 7</a></p>
</li>
<li>
<p><a href="http://www.youtube.com/watch?v=q_XXP32vchE"target="_blank" rel="noopener">Part 8</a></p>
</li>
<li>
<p><a href="http://www.youtube.com/watch?v=R42IOcYbKhU"target="_blank" rel="noopener">Part 9</a></p>
</li>
<li>
<p>“iPad Introduction 2010” – Aqui ele revela o iPad, que todos diziam que seria ruim, que não pegaria, que não teria graça. Hoje virou recorde de vendas e foi eleito produto do ano.</p>
</li>
<li>
<p><a href="http://www.youtube.com/watch?v=Tw8tljgZ30A"target="_blank" rel="noopener">Part 1</a></p>
</li>
<li>
<p><a href="http://www.youtube.com/watch?v=-o5NUcvKv1E"target="_blank" rel="noopener">Part 2</a></p>
</li>
<li>
<p><a href="http://www.youtube.com/watch?v=MQ5jaSqVTjk"target="_blank" rel="noopener">Part 3</a></p>
</li>
<li>
<p><a href="http://www.youtube.com/watch?v=gcIOrnQc3nU"target="_blank" rel="noopener">Part 4</a></p>
</li>
<li>
<p>“The Fall and Rise of Apple” – Este é um resumo da história de queda e como a Apple se reergueu, no contexto geral do mercado e de seus produtos:</p>
</li>
<li>
<p><a href="https://web.archive.org/web/20110525104838/http://www.roughlydrafted.com/RD/Q4.06/9FD12E37-8DC7-4AD1-872F-2021BEDE6D96.html"target="_blank" rel="noopener">Artigo 1</a></p>
</li>
<li>
<p><a href="https://web.archive.org/web/20101203183039/http://www.roughlydrafted.com/RD/Q4.06/469013E9-454C-42F0-AFB1-FA75871A028B.html"target="_blank" rel="noopener">Artigo 2</a></p>
</li>
<li>
<p><a href="https://web.archive.org/web/20111008215116/http://www.roughlydrafted.com/RD/Q4.06/8F4B780E-674F-4421-A44D-7B1EAE9C1BA6.html"target="_blank" rel="noopener">Artigo 3</a></p>
</li>
<li>
<p><a href="https://web.archive.org/web/20100516153401/http://www.roughlydrafted.com/RD/Q4.06/4BC7D963-7B31-47B7-A6ED-2706BD472377.html"target="_blank" rel="noopener">Artigo 4</a></p>
</li>
<li>
<p><a href="https://web.archive.org/web/20111101185216/http://www.roughlydrafted.com/RD/Q4.06/1DDD598A-7CE0-479E-A6F9-912777CAB484.html"target="_blank" rel="noopener">Artigo 5</a></p>
</li>
<li>
<p><a href="https://web.archive.org/web/20111121131217/http://www.roughlydrafted.com/RD/Q4.06/D61CFB13-4A09-4F0A-9B5A-4DCB8977503C.html"target="_blank" rel="noopener">Artigo 6</a></p>
</li>
</ul>
<p>Para fechar: no documentário, a Apple começa 1996 em péssimo estado, perdendo US$ 1 bilhão por ano, com as ações caindo para US$ 17 cada. Agora, no fechamento do <a href="http://business.financialpost.com/2011/01/18/apple-reports-record-breaking-quarterly-results-again/"target="_blank" rel="noopener">último trimestre de 2010</a>, ela vendeu 16,24 milhões de iPhones só nesse trimestre, além de 7,33 milhões de iPads, 19,45 milhões de iPods e 4,13 milhões de Macs. Repetindo: só no trimestre.</p>
<p>Até agora a Apple já vendeu mais de 14 milhões de iPads desde o lançamento, em abril do ano passado. E a ação está em US$ 340. Quem comprou em 1996 e segurou viu o capital crescer quase 80 vezes em 15 anos, contando os splits que a Apple fez em 2000 e 2005 (via comentário do @cassiozen, abaixo). Um excelente investimento.</p>
]]></content:encoded><category>apple</category><category>historia-da-computacao</category><category>off-topic</category></item><item><title>[Objective-C] Method Missing!</title><link>https://akitaonrails.github.io/2010/12/06/objective-c-method-missing/</link><guid isPermaLink="true">https://akitaonrails.github.io/2010/12/06/objective-c-method-missing/</guid><pubDate>Mon, 06 Dec 2010 02:55:00 -0200</pubDate><description>&lt;p&gt;&lt;strong&gt;Obs:&lt;/strong&gt; Código disponível no &lt;a href="https://github.com/akitaonrails/ObjC_XmlBuilder"target="_blank" rel="noopener"&gt;Github&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Uma das funcionalidades mais interessantes do Ruby é sem dúvida o famoso &lt;tt&gt;method_missing&lt;/tt&gt;. Graças a ele podemos enviar mensagens arbitrárias a um objeto e ainda assim fazer com que responda como queremos. Por exemplo, o seguinte código dará uma exceção:&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ruby" data-lang="ruby"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;object:0x0000010092ac60&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="ss"&gt;NoMethodError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;undefined&lt;/span&gt; &lt;span class="nb"&gt;method&lt;/span&gt; &lt;span class="sb"&gt;`foo&amp;#39; for #&amp;lt;object:0x0000010092ac60&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt; from (irb):2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt; from /Users/akitaonrails/.rvm/rubies/ruby-1.9.2-p0/bin/irb:17:in `&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/object:0x0000010092ac60&amp;gt;&amp;lt;/o&lt;/span&gt;&lt;span class="ss"&gt;bject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mh"&gt;0x0000010092ac60&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="Copy code"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Agora, podemos redefinir o método &lt;tt&gt;method_missing&lt;/tt&gt; do &lt;tt&gt;Object&lt;/tt&gt; e veja o que acontece:&lt;/p&gt;</description><content:encoded><![CDATA[<p><strong>Obs:</strong> Código disponível no <a href="https://github.com/akitaonrails/ObjC_XmlBuilder"target="_blank" rel="noopener">Github</a></p>
<p>Uma das funcionalidades mais interessantes do Ruby é sem dúvida o famoso <tt>method_missing</tt>. Graças a ele podemos enviar mensagens arbitrárias a um objeto e ainda assim fazer com que responda como queremos. Por exemplo, o seguinte código dará uma exceção:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">&gt;</span> <span class="n">obj</span> <span class="o">=</span> <span class="no">Object</span><span class="o">.</span><span class="n">new</span>  
</span></span><span class="line"><span class="cl"> <span class="o">=&gt;</span> <span class="c1">#&lt;object:0x0000010092ac60&gt;</span>
</span></span><span class="line"><span class="cl"><span class="o">&gt;</span> <span class="n">obj</span><span class="o">.</span><span class="n">foo</span>
</span></span><span class="line"><span class="cl"><span class="ss">NoMethodError</span><span class="p">:</span> <span class="n">undefined</span> <span class="nb">method</span> <span class="sb">`foo&#39; for #&lt;object:0x0000010092ac60&gt;
</span></span></span><span class="line"><span class="cl"><span class="sb"> from (irb):2
</span></span></span><span class="line"><span class="cl"><span class="sb"> from /Users/akitaonrails/.rvm/rubies/ruby-1.9.2-p0/bin/irb:17:in `</span><span class="o">&lt;</span><span class="n">main</span><span class="o">&gt;</span><span class="err">&#39;</span>
</span></span><span class="line"><span class="cl"><span class="o">&lt;</span><span class="sr">/object:0x0000010092ac60&gt;&lt;/o</span><span class="ss">bject</span><span class="p">:</span><span class="mh">0x0000010092ac60</span><span class="o">&gt;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Agora, podemos redefinir o método <tt>method_missing</tt> do <tt>Object</tt> e veja o que acontece:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">&gt;</span> <span class="k">def</span> <span class="nf">method_missing</span><span class="p">(</span><span class="nb">method</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl"><span class="o">&gt;</span> <span class="s2">&#34;</span><span class="si">#{</span><span class="nb">method</span><span class="si">}</span><span class="s2">:</span><span class="si">#{</span><span class="n">args</span><span class="o">.</span><span class="n">size</span><span class="si">}</span><span class="s2">&#34;</span>  
</span></span><span class="line"><span class="cl"><span class="o">&gt;</span> <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">&gt;</span> <span class="n">obj</span><span class="o">.</span><span class="n">foo</span>  
</span></span><span class="line"><span class="cl"><span class="o">=&gt;</span> <span class="s2">&#34;foo:0&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">&gt;</span> <span class="n">obj</span><span class="o">.</span><span class="n">foo</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl"><span class="o">=&gt;</span> <span class="s2">&#34;foo:3&#34;</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Este foi um resumo rápido, recomendo que se ainda não estiver familiarizado com esse conceito leia meu <a href="/2008/11/10/micro-tutorial-de-ruby-parte-ii/">Micro-Tutorial de Ruby – Parte II</a> onde eu explico isso em mais detalhes.</p>
<p>Um exemplo que gosto de usar é a classe Builder::XmlMarkup. Diferente de plataformas que fazem ou concatenação manual de Strings (péssimo) ou manipulação burocrática de nós (DOM), em Ruby temos essa excelente classe que minimiza a quantidade de código e ao mesmo tempo gera XML bem formatado e válido. Este é um exemplo:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;builder&#39;</span>  
</span></span><span class="line"><span class="cl"><span class="n">x</span> <span class="o">=</span> <span class="no">Builder</span><span class="o">::</span><span class="no">XmlMarkup</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">:target</span> <span class="o">=&gt;</span> <span class="vg">$stdout</span><span class="p">,</span> <span class="ss">:indent</span> <span class="o">=&gt;</span> <span class="mi">1</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl"><span class="n">x</span><span class="o">.</span><span class="n">html</span> <span class="k">do</span> <span class="o">|</span><span class="n">h</span><span class="o">|</span>  
</span></span><span class="line"><span class="cl"> <span class="n">h</span><span class="o">.</span><span class="n">body</span> <span class="k">do</span> <span class="o">|</span><span class="n">b</span><span class="o">|</span>  
</span></span><span class="line"><span class="cl"> <span class="n">b</span><span class="o">.</span><span class="n">h1</span> <span class="s2">&#34;Hello World&#34;</span>  
</span></span><span class="line"><span class="cl"> <span class="n">b</span><span class="o">.</span><span class="n">p</span> <span class="s2">&#34;This is a paragraph.&#34;</span>  
</span></span><span class="line"><span class="cl"> <span class="n">b</span><span class="o">.</span><span class="n">table</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>  
</span></span><span class="line"><span class="cl"> <span class="n">t</span><span class="o">.</span><span class="n">tr</span> <span class="k">do</span> <span class="o">|</span><span class="n">tr</span><span class="o">|</span>  
</span></span><span class="line"><span class="cl"> <span class="n">tr</span><span class="o">.</span><span class="n">td</span> <span class="s2">&#34;column&#34;</span>  
</span></span><span class="line"><span class="cl"> <span class="k">end</span>  
</span></span><span class="line"><span class="cl"> <span class="k">end</span>  
</span></span><span class="line"><span class="cl"> <span class="k">end</span>  
</span></span><span class="line"><span class="cl"><span class="k">end</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Esse código irá gerar diretamente este XML:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Hello World
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">This is a paragraph.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">| column |</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Se nunca tinha visto isso, pare por um segundo e contemple a beleza desta API. A partir do objeto XmlMarkup enviamos mensagens como <tt>html</tt> e ele vai acumulando as tags. Usamos blocos exatamente para blocos de XML, garantindo que eles terão as tags corretas de fechamento.</p>
<p>Pensando nisso, resolvi tentar fazer algo semelhante em Objective-C. A funcionalidade que permite esse tipo de API no Ruby é o <tt>method_missing</tt>, algo que imaginamos que somente linguagens dinâmicas conseguem ter. Porém, ao final deste artigo, quero fazer este código funcionar:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="n">XmlBuilder</span><span class="o">*</span> <span class="n">xml</span> <span class="o">=</span> <span class="p">[[</span><span class="n">XmlBuilder</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="n">xml</span> <span class="nl">htmlBlock</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="n">XmlBuilder</span><span class="o">*</span> <span class="n">h</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="n">h</span> <span class="nl">bodyBlock</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="n">XmlBuilder</span><span class="o">*</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="n">b</span> <span class="nl">h1</span><span class="p">:</span><span class="err">`</span><span class="s">&#34;Hello World&#34;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="p">[</span><span class="n">b</span> <span class="nl">p</span><span class="p">:</span><span class="err">`</span><span class="s">&#34;This is a paragraph.&#34;</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="n">b</span> <span class="nl">tableBlock</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="n">XmlBuilder</span><span class="o">*</span> <span class="n">t</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="n">t</span> <span class="nl">trBlock</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="n">XmlBuilder</span><span class="o">*</span> <span class="n">tr</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="n">tr</span> <span class="nl">td</span><span class="p">:</span><span class="s">@&#34;column&#34;</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"> <span class="p">}];</span>  
</span></span><span class="line"><span class="cl"> <span class="p">}];</span>
</span></span><span class="line"><span class="cl"> <span class="p">}];</span>  
</span></span><span class="line"><span class="cl"><span class="p">}];</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>É bem mais <em>verbose</em> do que Ruby, obviamente, mas ainda assim bem mais interessante do que o jeito de manipular DOMs com métodos como <tt>createElement</tt>, <tt>appendElement</tt>, etc. De uma certa maneira dá pra ficar bastante semelhante à versão em Ruby. Mas como isso é possível?</p>
<p>Antes de continuar, leia meu artigo sobre <a href="/2010/11/28/objective-c-brincando-com-categorias-e-blocos/">Categorias e Blocos</a> pois este artigo usará blocos.</p>
<h2>Seletores<span class="hx:absolute hx:-mt-20" id="seletores"></span>
    <a href="#seletores" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Recapitulando, em Ruby, quando chamamos um método de um objeto, por exemplo:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">obj</span><span class="o">.</span><span class="n">foo</span><span class="p">(</span><span class="s2">&#34;Hello World&#34;</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Na realidade podemos dizer que estamos <em>“enviando a mensagem :foo ao objeto ‘obj’”</em> ou seja, seria o mesmo que:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">obj</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="ss">:foo</span><span class="p">,</span> <span class="s2">&#34;Hello World&#34;</span><span class="p">)</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Em Obj-C temos algo semelhante. Quando fazemos:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="n">obj</span> <span class="nl">foo</span><span class="p">:</span><span class="s">@&#34;Hello World&#34;</span><span class="p">];</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Seria o equivalente a fazer:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="n">obj</span> <span class="nl">performSelector</span><span class="p">:</span><span class="err">`</span><span class="n">selector</span><span class="p">(</span><span class="nl">foo</span><span class="p">:)</span> <span class="nl">withObject</span><span class="p">:</span><span class="err">`</span><span class="s">&#34;Hello World&#34;</span><span class="p">];</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>A diferença é que em Ruby temos Symbols e em Obj-C temos <a href="http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocSelectors.html"target="_blank" rel="noopener">Selectors</a>, que é semelhante, uma forma de não desperdiçar espaço com Strings. Porém, selectores são mais do que apenas métodos: eles representam o nome do método e seus atributos que em Obj-C são nomeados. Por exemplo, um método <tt>foo</tt>, com dois argumentos, poderia ser assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="p">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="nf">foo:</span><span class="p">(</span><span class="n">NSString</span><span class="o">*</span><span class="p">)</span><span class="nv">bar</span> <span class="nf">value:</span><span class="p">(</span><span class="n">NSString</span><span class="o">*</span><span class="p">)</span><span class="nv">xyz</span><span class="p">;</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Esse método seria enviado ao objeto assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="p">[</span><span class="n">obj</span> <span class="nl">foo</span><span class="p">:</span><span class="err">`</span><span class="s">&#34;Hello&#34;</span> <span class="nl">value</span><span class="p">:</span><span class="err">`</span><span class="s">&#34;World&#34;</span><span class="p">];</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E seu seletor seria assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="kt">SEL</span> <span class="n">t</span> <span class="o">=</span> <span class="k">@selector</span><span class="p">(</span><span class="nl">foo</span><span class="p">:</span><span class="nl">value</span><span class="p">:);</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Se o método tivesse apenas o primeiro argumento (que não tem nome), o seletor seria assim: <tt>foo:</tt> – note o “:” no final. Se não tiver nenhum argumento, não tem nenhum “:”. Isso é importante não confundir. Alguns erros podem passar em branco pela falta desse “:” na hora de montar o seletor.</p>
<p>Agora, quando se envia uma mensagem a um objeto e o método correspondente não está implementado, o Obj-C fará duas coisas: primeiro vai chamar o método <tt>methodSignatureForSelector:</tt>, que devolve um objeto <tt><a href="http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSMethodSignature_Class/Reference/Reference.html%23//apple_ref/doc/c_ref/NSMethodSignature">NSMethodSignature</a></tt>. Em seguida vai criar um objeto <tt><a href="http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSInvocation_Class/Reference/Reference.html">NSInvocation</a></tt> a partir disso e passará como argumento ao método <tt>forwardInvocation:</tt>. Este último é quem mais ou menos faz o papel do <tt>method_missing</tt> de Ruby.</p>
<p>Na realidade, em Obj-C essa técnica é chamada de <a href="http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtForwarding.html"target="_blank" rel="noopener">Message Forwarding</a>. O objetivo na realidade é criar objetos que são Proxy para outros objetos. Nesse caso o framework facilita as coisas para passar mensagens que realmente existem no objeto de destino.</p>
<p>O pseudo-código seria mais ou menos assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="p">-</span> <span class="p">(</span><span class="n">NSMethodSignature</span> <span class="o">*</span><span class="p">)</span><span class="nf">methodSignatureForSelector:</span><span class="p">(</span><span class="kt">SEL</span><span class="p">)</span><span class="nv">aSelector</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">[</span><span class="n">anotherObject</span> <span class="nl">methodSignatureForSelector</span><span class="p">:</span><span class="n">aSelector</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">forwardInvocation:</span><span class="p">(</span><span class="n">NSInvocation</span> <span class="o">*</span><span class="p">)</span><span class="nv">anInvocation</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="n">anotherObject</span> <span class="nl">performSelector</span><span class="p">:[</span><span class="n">anInvocation</span> <span class="n">selector</span><span class="p">]];</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Os métodos são chamados nessa sequência mesmo. No primeiro ele consegue a assinatura do método no objeto destino com o método <tt>methodSignatureForSelector</tt>. A assinatura é um array que representa o tipo do valor de retorno e os tipos dos argumentos. Essa assinatura é usada em conjunto com o seletor para criar o <tt>NSInvocation</tt>. Daí no segundo método o seletor é enviado ao objeto de destino, sendo assim executado.</p>
<p>Se precisar criar Proxies ou Adapters, esse é o padrão para fazê-lo.</p>
<h2>Proxy Dinâmico<span class="hx:absolute hx:-mt-20" id="proxy-dinâmico"></span>
    <a href="#proxy-din%c3%a2mico" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O problema é que o padrão anterior pressupõe que o objeto de destino possui os métodos definidos a partir dos quais podemos extrair suas assinaturas. Porém, no nosso caso queremos um objeto que aceite qualquer tipo de mensagem representando tags arbitrários de um XML.</p>
<p>Para começar, quero definir uma classe chamada <tt>XmlBuilder</tt> e as variáveis internas que vão acumular o XML e controlar o nível de indentação:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="cp"># import &lt;Foundation/Foundation.h&gt;
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">@interface</span> <span class="nc">XmlBuilder</span> : <span class="nc">NSObject</span>  
</span></span><span class="line"><span class="cl"><span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="n">NSMutableString</span><span class="o">*</span> <span class="n">buffer</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">indentationLevel</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>  
</span></span><span class="line"><span class="cl"><span class="k">@property</span> <span class="p">(</span><span class="k">retain</span><span class="p">)</span> <span class="n">NSMutableString</span><span class="o">*</span> <span class="n">buffer</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"><span class="k">@property</span> <span class="p">(</span><span class="k">assign</span><span class="p">)</span> <span class="kt">int</span> <span class="n">indentationLevel</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"><span class="k">@end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">@implementation</span> <span class="nc">XmlBuilder</span>  
</span></span><span class="line"><span class="cl"><span class="k">@synthesize</span> <span class="n">buffer</span><span class="p">,</span> <span class="n">indentationLevel</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">-</span> <span class="p">(</span><span class="kt">id</span><span class="p">)</span> <span class="nf">init</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="nb">self</span> <span class="o">=</span> <span class="p">[</span><span class="nb">super</span> <span class="n">init</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="nb">self</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="nb">self</span><span class="p">.</span><span class="n">buffer</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSMutableString</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"> <span class="nb">self</span><span class="p">.</span><span class="n">indentationLevel</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"> <span class="p">}</span>  
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nb">self</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="nf">dealloc</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="n">buffer</span> <span class="k">release</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="nb">super</span> <span class="n">dealloc</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>  
</span></span><span class="line"><span class="cl"><span class="err">…</span>  
</span></span><span class="line"><span class="cl"><span class="k">@end</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Até aqui nada de mais, apenas definição de interface, implementação, propriedades, construtor e destrutor. Coisa padrão.</p>
<p>Agora a coisa começa a esquentar:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="p">-</span> <span class="p">(</span><span class="n">NSMethodSignature</span> <span class="o">*</span><span class="p">)</span><span class="nf">methodSignatureForSelector:</span><span class="p">(</span><span class="kt">SEL</span><span class="p">)</span><span class="nv">aSelector</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="c1">// não importa o retorno porque não vamos usar essa assinatura  
</span></span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">[</span><span class="n">NSMethodSignature</span> <span class="nl">signatureWithObjCTypes</span><span class="p">:</span><span class="s">&#34;v@:@&#34;</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Esta primeira versão de implementação não precisa se preocupar com a assinatura. Vamos usar uma convenção para extrair os argumentos e não precisamos de assinaturas, então apenas devolvemos uma genérica qualquer.</p>
<p>Para começar, quero entender mensagens mais ou menos desse tipo:</p>
<p>Convenção para métodos dinâmicos:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">-</span> <span class="p">(</span><span class="kt">id</span><span class="p">)</span> <span class="nf">entity:</span><span class="p">(</span><span class="n">NSString</span><span class="o">*</span><span class="p">)</span><span class="nv">value</span><span class="p">;</span> <span class="o">-</span> <span class="p">(</span><span class="kt">id</span><span class="p">)</span> <span class="nl">entityBlock</span><span class="p">:(</span><span class="kt">id</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="kt">id</span><span class="p">))</span><span class="n">block</span><span class="p">;</span> <span class="err">*/</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Ou seja, mensagens assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="p">[</span><span class="n">xml</span> <span class="nl">p</span><span class="p">:</span><span class="s">@&#34;Hello World&#34;</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="n">xml</span> <span class="nl">tableBlock</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="n">XmlBuilder</span><span class="o">*</span> <span class="n">t</span><span class="p">)</span> <span class="p">{</span> <span class="err">…</span> <span class="p">}];</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Agora, vamos definir o método principal:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">forwardInvocation:</span><span class="p">(</span><span class="n">NSInvocation</span> <span class="o">**</span><span class="p">)</span><span class="nv">anInvocation</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="c1">// #1  
</span></span></span><span class="line"><span class="cl"> <span class="n">NSString</span><span class="o">**</span> <span class="n">method</span> <span class="o">=</span> <span class="n">NSStringFromSelector</span><span class="p">([</span><span class="n">anInvocation</span> <span class="n">selector</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">//</span> <span class="err">#</span><span class="mi">2</span><span class="kt">BOOL</span> <span class="n">hasBlock</span> <span class="o">=</span> <span class="p">[</span><span class="n">method</span> <span class="nl">hasSuffix</span><span class="p">:</span><span class="s">@&#34;Block:&#34;</span><span class="p">];</span> <span class="n">method</span> <span class="o">=</span> <span class="p">[</span><span class="n">method</span> <span class="nl">stringByReplacingOccurrencesOfString</span><span class="p">:</span><span class="s">@&#34;Block&#34;</span> <span class="nl">withString</span><span class="p">:</span><span class="s">@&#34;&#34;</span><span class="p">];</span> <span class="n">method</span> <span class="o">=</span> <span class="p">[</span><span class="n">method</span> <span class="nl">stringByReplacingOccurrencesOfString</span><span class="p">:</span><span class="s">@&#34;:&#34;</span> <span class="nl">withString</span><span class="p">:</span><span class="s">@&#34;&#34;</span><span class="p">];</span> <span class="o">//</span> <span class="err">#</span><span class="mi">3</span> <span class="kt">int</span> <span class="n">tabsLength</span> <span class="o">=</span> <span class="nb">self</span><span class="p">.</span><span class="n">indentationLevel</span> <span class="o">*</span> <span class="mi">2</span><span class="p">;</span> <span class="n">NSMutableString</span><span class="o">*</span> <span class="n">tabs</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSMutableString</span> <span class="nl">stringWithCapacity</span><span class="p">:</span><span class="n">tabsLength</span><span class="p">];</span> <span class="kt">int</span> <span class="n">i</span><span class="p">;</span> <span class="k">for</span> <span class="p">(</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span> <span class="p">;</span> <span class="n">i</span> <span class="err">\</span><span class="o">&lt;</span> <span class="n">tabsLength</span><span class="p">;</span> <span class="n">i</span> <span class="o">++</span> <span class="p">)</span> <span class="p">{</span> <span class="p">[</span><span class="n">tabs</span> <span class="nl">appendString</span><span class="p">:</span><span class="s">@&#34; &#34;</span><span class="p">];</span> <span class="p">}</span> <span class="err">…</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Vamos ver até a metade do método:</p>
<ol>
<li>Primeiro extraímos o nome do seletor em forma de String para conseguirmos manipulá-lo</li>
<li>Nesta primeira versão, por convenção, assumimos que se seletor terminar com “Block:” significa que receberemos um bloco como argumento. Em seguida limpamos isso no nome do seletor para ficar só o nome da tag. Por exemplo: “htmlBlock:” ficaria “html” apenas. Eu faço isso porque ainda não aprendi a identificar o tipo do argumento recebido, pois se eu puder identificar que recebi um bloco, não preciso da convenção (fica como um TODO).</li>
<li>Aqui geramos uma String com espaços em branco representando o nível de identação atual do XML, para que o resultado final esteja bonito.</li>
</ol>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="err">…</span> <span class="k">if</span> <span class="p">(</span><span class="n">hasBlock</span><span class="p">)</span> <span class="p">{</span> 
</span></span><span class="line"><span class="cl"><span class="c1">// #4 id (^block)(id); 
</span></span></span><span class="line"><span class="cl"><span class="p">[</span><span class="n">anInvocation</span> <span class="nl">getArgument</span><span class="p">:</span><span class="o">&amp;</span><span class="n">block</span> <span class="nl">atIndex</span><span class="p">:</span><span class="mi">2</span><span class="p">];</span> 
</span></span><span class="line"><span class="cl"><span class="c1">// #5 [buffer appendFormat:`&#34;%`\&lt;%@\&gt;\n&#34;, tabs, method]; 
</span></span></span><span class="line"><span class="cl"><span class="nb">self</span><span class="p">.</span><span class="n">indentationLevel</span> <span class="o">=</span> <span class="nb">self</span><span class="p">.</span><span class="n">indentationLevel</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl"><span class="n">block</span><span class="p">(</span><span class="nb">self</span><span class="p">);</span> 
</span></span><span class="line"><span class="cl"><span class="nb">self</span><span class="p">.</span><span class="n">indentationLevel</span> <span class="o">=</span> <span class="nb">self</span><span class="p">.</span><span class="n">indentationLevel</span> <span class="err">–</span> <span class="mi">1</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="n">buffer</span> <span class="nl">appendFormat</span><span class="p">:</span><span class="err">`</span><span class="s">&#34;%`\&lt;/%@\&gt;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">tabs</span><span class="p">,</span> <span class="n">method</span><span class="p">];</span> <span class="p">}</span> 
</span></span><span class="line"><span class="cl"><span class="k">else</span> <span class="p">{</span> 
</span></span><span class="line"><span class="cl"><span class="c1">// #6 NSString* value; 
</span></span></span><span class="line"><span class="cl"><span class="p">[</span><span class="n">anInvocation</span> <span class="nl">getArgument</span><span class="p">:</span><span class="o">&amp;</span><span class="n">value</span> <span class="nl">atIndex</span><span class="p">:</span><span class="mi">2</span><span class="p">];</span> <span class="p">[</span><span class="n">buffer</span> <span class="nl">appendFormat</span><span class="p">:</span><span class="err">`</span><span class="s">&#34;%`\&lt;%`&gt;</span><span class="se">\n</span><span class="s">%`%`%`</span><span class="se">\n</span><span class="s">%`&lt;/%`\&gt;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">tabs</span><span class="p">,</span> <span class="n">method</span><span class="p">,</span> <span class="n">tabs</span><span class="p">,</span> <span class="s">@&#34; &#34;</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">tabs</span><span class="p">,</span> <span class="n">method</span><span class="p">];</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Continuando a partir da metade do código:</p>
<ol>
<li>Se a convenção disser que existe um bloco, assumimos que ele foi passado como argumento no 3o ítem do array do <tt>NSInvocation</tt>. Por convenção o primeiro elemento desse array (0) é o self e o segundo (1) o método, portanto o 3o. elemento (2) é o equivalente ao primeiro argumento.</li>
<li>Agora vem a sequência para criar a tag que abre o bloco, depois aumentamos o nível de identação para o bloco; daí chamamos o bloco passado passando nós mesmos como parâmetro; o bloco é executado e quando retorna podemos diminuir o nível de identação; finalmente criamos a tag que fecha o bloco.</li>
<li>Caso não tenha sido passado um bloco então é uma tag simples com um valor simples dentro. Agora no 3o. elemento do array, em vez de esperar um bloco podemos esperar um String. Finalmente basta criar a tag com o valor String dentro e acertar a identação de acordo.</li>
</ol>
<p>Fazendo isso, podemos agora fazer chamadas assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span> <span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">argv</span><span class="p">[])</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="n">NSAutoreleasePool</span> <span class="o">*</span> <span class="n">pool</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSAutoreleasePool</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">XmlBuilder</span><span class="o">*</span> <span class="n">xml</span> <span class="o">=</span> <span class="p">[[</span><span class="n">XmlBuilder</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">];</span> <span class="p">[</span><span class="n">xml</span> <span class="nl">htmlBlock</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="n">XmlBuilder</span><span class="o">*</span> <span class="n">h</span><span class="p">)</span> <span class="p">{</span> <span class="p">[</span><span class="n">h</span> <span class="nl">bodyBlock</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="n">XmlBuilder</span><span class="o">*</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span> <span class="p">[</span><span class="n">b</span> <span class="nl">h1</span><span class="p">:</span><span class="s">@&#34;Hello World&#34;</span><span class="p">];</span> 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="n">b</span> <span class="nl">p</span><span class="p">:</span><span class="s">@&#34;This is a paragraph.&#34;</span><span class="p">];</span> 
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="n">b</span> <span class="nl">tableBlock</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="n">XmlBuilder</span><span class="o">*</span> <span class="n">t</span><span class="p">)</span> <span class="p">{</span> <span class="p">[</span><span class="n">t</span> <span class="nl">trBlock</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="n">XmlBuilder</span><span class="o">*</span> <span class="n">tr</span><span class="p">)</span> <span class="p">{</span> <span class="p">[</span><span class="n">tr</span> <span class="nl">td</span><span class="p">:</span><span class="s">@&#34;column&#34;</span><span class="p">];</span> <span class="p">}];</span> <span class="p">}];</span> <span class="p">}];</span> <span class="p">}];</span> 
</span></span><span class="line"><span class="cl"><span class="n">NSLog</span><span class="p">(</span><span class="err">`</span><span class="s">&#34;%`&#34;</span><span class="p">,</span> <span class="p">[</span><span class="n">xml</span> <span class="n">buffer</span><span class="p">]);</span> <span class="p">[</span><span class="n">pool</span> <span class="n">drain</span><span class="p">];</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Impressionantemente, se abrirmos o Console (Shift+Command+R) ao executar teremos exatamente esta saída do comando <tt>NSLog</tt>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Hello World
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">This is a paragraph.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">| column |</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Que é o que queríamos e é semelhante ao gerado pelo equivalente Builder::XmlMarkup do Ruby. Claro, esta é uma versão hiper-simplificada, mas que pode ser o esqueleto para uma versão completa. O próximo passo é fazer a classe aceitar atributos de tags. E outra coisa é ver se é possível não precisar da convenção de “tableBlock:” para identificar se o argumento passado é um bloco e checar se é possível verificar o tipo do argumento passado em tempo de execução.</p>
<p>De qualquer forma, com isso podemos ver o quanto o Obj-C pode ser dinâmico e flexível mesmo em se tratando de uma linguagem de baixo nível como é C. Com um pouco de criatividade podemos criar bibliotecas que lembram em muito o que usamos em Ruby.</p>
]]></content:encoded><category>apple</category><category>programacao</category><category>tutoriais</category></item><item><title>[Objective-C] Brincando com Categorias e Blocos</title><link>https://akitaonrails.github.io/2010/11/28/objective-c-brincando-com-categorias-e-blocos/</link><guid isPermaLink="true">https://akitaonrails.github.io/2010/11/28/objective-c-brincando-com-categorias-e-blocos/</guid><pubDate>Sun, 28 Nov 2010 18:58:00 -0200</pubDate><description>&lt;p&gt;Continuando meus estudos com Objective-C, existem algumas funcionalidades que me deixam realmente surpreso. Duas delas são Categorias e Blocos.&lt;/p&gt;
&lt;p&gt;Para facilitar, vamos ver um código Ruby para dar um exemplo do que quero fazer:&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ruby" data-lang="ruby"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;each_element&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;elem&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;end&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="Copy code"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Sabemos que em Ruby, todas as classes podem ser abertas e extendidas, incluindo classes padrão da linguagem como Array ou String. Isso permite extender a própria linguagem e é o que o pacote ActiveSupport do Rails faz, ao adicionar métodos como &lt;tt&gt;#days&lt;/tt&gt; à classe &lt;tt&gt;Fixnum&lt;/tt&gt;, permitindo operações como &lt;tt&gt;2.days – 1.day&lt;/tt&gt;, por exemplo.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Continuando meus estudos com Objective-C, existem algumas funcionalidades que me deixam realmente surpreso. Duas delas são Categorias e Blocos.</p>
<p>Para facilitar, vamos ver um código Ruby para dar um exemplo do que quero fazer:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Array</span>  
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="nf">each_element</span>  
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">elem</span> <span class="k">in</span> <span class="nb">self</span>  
</span></span><span class="line"><span class="cl"> <span class="k">yield</span><span class="p">(</span><span class="n">elem</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl"> <span class="k">end</span>  
</span></span><span class="line"><span class="cl"> <span class="k">end</span>  
</span></span><span class="line"><span class="cl"><span class="k">end</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Sabemos que em Ruby, todas as classes podem ser abertas e extendidas, incluindo classes padrão da linguagem como Array ou String. Isso permite extender a própria linguagem e é o que o pacote ActiveSupport do Rails faz, ao adicionar métodos como <tt>#days</tt> à classe <tt>Fixnum</tt>, permitindo operações como <tt>2.days – 1.day</tt>, por exemplo.</p>
<p>Em linguagens como Java isso não é possível porque as classes são fechadas, e inclusive muitas delas são <em>finals</em> o que impedem criar sub-classes a partir delas. Por exemplo, não se pode criar uma classe herdando de <tt>String</tt>. Isso acaba dando origem a muitas classes acessórias como <tt><a href="http://commons.apache.org/lang/api-2.5/org/apache/commons/lang/StringUtils.html">StringUtils</a></tt>, o que eu acho particularmente não elegante.</p>
<p>No exemplo acima, reabri a classe padrão <tt>Array</tt> do Ruby e fiz minha própria versão do método <tt>each</tt>, que já existe, chamando-o de <tt>each_element</tt> somente com objetivos didáticos para este artigo. Agora podemos pegar um array normal e chamar esse método nele:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">list</span> <span class="o">=</span> <span class="o">[</span><span class="s2">&#34;a&#34;</span><span class="p">,</span> <span class="s2">&#34;b&#34;</span><span class="p">,</span> <span class="s2">&#34;c&#34;</span><span class="o">]</span>  
</span></span><span class="line"><span class="cl"><span class="n">list</span><span class="o">.</span><span class="n">each_element</span> <span class="k">do</span> <span class="o">|</span><span class="n">elem</span><span class="o">|</span>  
</span></span><span class="line"><span class="cl"> <span class="nb">puts</span> <span class="n">elem</span>  
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Mais do que extender classes, o Ruby possui outra funcionalidade muito flexível chamada blocos ou closures/fechamentos (eu já escrevi sobre <a href="http://rubylearning.com/blog/2007/11/30/akitaonrails-on-anatomy-of-ruby-blocksclosures/"target="_blank" rel="noopener">blocos e closures</a> antes pra RubyLearning. Sugiro ler para entender o conceito)</p>
<p>Essas são duas funcionalidades que muitos poderiam imaginar que só seriam possíveis em linguagens altamente dinâmicas como Ruby, Python ou Smalltalk. Já Objective-C é uma extensão da linguagem C, algo considerado por muitos como tão baixo nível que nem se imaginariam ser possível. Será?</p>
<h2>Categorias<span class="hx:absolute hx:-mt-20" id="categorias"></span>
    <a href="#categorias" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O Objective-C tem uma funcionalidade chamada <a href="http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocCategories.html%23//apple_ref/doc/uid/TP30001163-CH20-SW1"target="_blank" rel="noopener">Categories</a>. Essencialmente isso permite “reabrir” classes já existentes e extendê-las com mais métodos.</p>
<p>Na minha interpretação o Obj-C, assim como Ruby, são linguagens orientadas a objeto mas, mais importante, eu diria que elas são <strong>orientadas a protocolo</strong>. Em vez de pensar em interfaces estáticas e “chamar um método” o correto é pensar em “enviar mensagens”. Protocolos definem quais mensagens o objeto sabe responder. A diferença é que você não busca uma coerência em tempo de compilação mas sim em tempo de execução. Você pode mandar mensagens que o objeto não entende se quiser sem receber um erro de compilação.</p>
<p>Uma convenção de nomenclatura que podemos usar é criar o arquivo header e a implementação usando o nome da classe a ser extendida, o símbolo “+”, e o nome da Categoria que queremos implementar. Por exemplo, digamos que eu queira a mesma funcionalidade do método <tt>each</tt> de Array do Ruby no equivalente <tt>NSArray</tt> do Obj-C, podemos fazer assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="c1">// NSArray+functional.h  
</span></span></span><span class="line"><span class="cl"><span class="k">@interface</span> <span class="nc">NSArray</span> <span class="nl">(functional)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="nf">each:</span><span class="p">(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)</span> <span class="p">(</span><span class="kt">id</span><span class="p">))</span><span class="nv">block</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">@end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E a implementação seria:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="c1">// NSArray+functional.m
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp"># import &#34;NSArray+functional.h&#34;
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">@implementation</span> <span class="nc">NSArray</span> <span class="nl">(functional)</span>  
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="nf">each:</span><span class="p">(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)</span> <span class="p">(</span><span class="kt">id</span><span class="p">))</span><span class="nv">block</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">i</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="p">[</span><span class="nb">self</span> <span class="n">count</span><span class="p">];</span> <span class="n">i</span> <span class="o">++</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="n">block</span><span class="p">([</span><span class="nb">self</span> <span class="nl">objectAtIndex</span><span class="p">:</span><span class="n">i</span><span class="p">]);</span>  
</span></span><span class="line"><span class="cl"> <span class="p">}</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>  
</span></span><span class="line"><span class="cl"><span class="k">@end</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>A sintaxe é exatamente a mesma se estivéssemos definindo uma nova classe, mas neste caso declaramos o mesmo nome da classe que já existe <tt>NSArray</tt> e entre parênteses colocamos o nome da nossa categoria que, neste caso, chamei arbitrariamente de “functional” para ter diversos métodos funcionais.</p>
<p>Categorias não podem ter variáveis de instância entre chaves na declaração da interface, ela só pode comportar novos métodos, por isso falei que não era não flexível, mas isso já seria o bastante.</p>
<p>Essa funcionalidade pode ser usada principalmente para duas coisas: substituir a necessidade de criar sub-classes e, com isso, evitar usar herança sempre que possível e que fizer sentido; e a outra é quebrar classes com implementações muito grande em múltiplos arquivos de forma a melhor organizar os arquivos do projeto.</p>
<h2>Blocos<span class="hx:absolute hx:-mt-20" id="blocos"></span>
    <a href="#blocos" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Como vocês devem ter suspeitado, implementar o método <tt>each</tt> semelhante ao Ruby significa que deveríamos poder usar blocos. E o Obj-C também permite blocos, na forma de métodos anônimos (sem nome).</p>
<p>O parâmetro que implementamos é <tt>(void (^) (id))block</tt>. “block” é o nome da variável que vai receber o bloco. Seu tipo é de retorno “void” e parâmetro “id”. O “^” é o “nome” do bloco, no caso, sem nome algum, ou anônimo. Tendo em mãos o bloco podemos executá-la assim: <tt>block([self objectAtIndex:i])</tt>. O tipo <tt>id</tt> em Obj-C é um tipo genérico que denota um objeto arbitrário. Ele é usado por todo o framework Cocoa e seria, mais ou menos, o equivalente a dizer que o método recebe qualquer tipo de objeto.</p>
<p>E como podemos usar essa nova categoria com o novo método? Vejamos:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="cp"># import &#34;NSArray+functional.h&#34;
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">-</span> <span class="p">(</span><span class="kt">IBAction</span><span class="p">)</span> <span class="nf">foo:</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="nv">sender</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">NSMutableArray</span> <span class="o">*</span><span class="n">list</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSMutableArray</span> <span class="nl">arrayWithObjects</span><span class="p">:</span><span class="s">&#34;;  </span>
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="n">list</span> <span class="nl">each</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="kt">id</span> <span class="n">obj</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="n">NSLog</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">obj</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">}];</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>No caso, faça de conta que estamos numa aplicação de iPhone ou Mac, por isso criei um método que retorna <tt>IBAction</tt>. Para quem não sabe, <tt>IBAction</tt> é a mesma coisa que <tt>void</tt>, ou seja, que o método não retorna nada. A diferença é que o Interface Builder reconhece métodos que retornam <tt>IBAction</tt> como métodos que podem ser ligados diretamente a ações de um elemento visual na tela, por exemplo.</p>
<p>No corpo do método começamos criando um <tt>NSMutableArray</tt>. Fiz isso de propósito porque essa classe herda de <tt>NSArray</tt> e, portanto, também herdará o novo método <tt>each</tt> que implementamos.</p>
<p>Agora a parte importante é como chamamos o método nesse objeto: <tt>[list each:^(id obj) { … }]</tt>. Ou seja, estamos enviando a mensagem <tt>each</tt> ao objeto <tt>list</tt> passando como parâmetro um bloco anônimo “^” que tem parâmetro <tt>id obj</tt>. Se você não conhece blocos de Ruby ou de outra linguagem como Lisp, pode ser difícil entender o que está acontecendo, por isso recomendo novamente ler meu artigo sobre <a href="http://rubylearning.com/blog/2007/11/30/akitaonrails-on-anatomy-of-ruby-blocksclosures/"target="_blank" rel="noopener">blocos</a> antes.</p>
<p>Note que dentro do bloco o <tt>NSLog</tt> está usando a string <tt>msg</tt> que foi criada fora do bloco, exatamente como eu poderia fazer em Ruby, o bloco tem conhecimento do ambiente ao seu redor e eu posso usar variáveis criadas fora do bloco. Isso é uma das coisas que torna essa funcionalidade de blocos diferente de um simples “delegate” ou simplesmente passar um ponteiro de uma função.</p>
<p>Em Ruby, eu posso capturar um bloco em uma variável, assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">bloco</span> <span class="o">=</span> <span class="nb">lambda</span> <span class="p">{</span> <span class="o">|</span><span class="n">a</span><span class="o">|</span> <span class="nb">puts</span> <span class="n">a</span> <span class="p">}</span>  
</span></span><span class="line"><span class="cl"><span class="n">bloco</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="s2">&#34;bla&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="mi">1</span><span class="o">.</span> <span class="o">=&gt;</span> <span class="s2">&#34;bla&#34;</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>No exemplo acima, criamos um bloco e em seguida executamos esse bloco usando o método <tt>call</tt>. Em Obj-C podemos fazer algo similar assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="n">bloco</span><span class="p">)(</span><span class="n">NSString</span><span class="o">*</span><span class="p">)</span> <span class="o">=</span> <span class="o">^</span><span class="p">(</span><span class="n">NSString</span><span class="o">*</span> <span class="n">msg</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="n">NSLog</span><span class="p">(</span><span class="n">msg</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"><span class="p">};</span>  
</span></span><span class="line"><span class="cl"><span class="n">bloco</span><span class="p">(</span><span class="s">@&#34;bla&#34;</span><span class="p">);</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Veja que é muito parecido só que precisamos declarar os tipos. Na primeira linha definimos uma variável do tipo bloco, com o nome de “bloco” (o nome vem logo depois do “^”). Antes do nome temos o tipo de retorno, <tt>void</tt>, e depois o tipo do parâmetro que ele aceita, ponteiro de <tt>NSString</tt>. Daí criamos o bloco propriamente dito.</p>
<p>Em seguida basta chamar o bloco como se fosse uma função normal de C, usando a notação de passar parâmetros entre parênteses.</p>
<h2>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Categorias e Blocos podem ajudar muito a tornar a programação em Obj-C mais flexível e mais próxima dos conceitos de linguagens mais dinâmicas como Ruby. Como exercício que tal completar a minha Categoria <tt>NSArray+functional.h</tt> e acrescentar métodos como <tt>select</tt>, <tt>map</tt>, <tt>sort</tt>, etc? Coloquem links para <a href="http://gist.github.com"target="_blank" rel="noopener">Gist</a> nos comentários com sugestões de implementação.</p>
<p>Para aprender mais sobre blocos, recomendo ler:</p>
<ul>
<li><a href="http://pragmaticstudio.com/blog/2010/7/28/ios4-blocks-1"target="_blank" rel="noopener">Using Blocks in iOS 4: The Basics</a></li>
<li><a href="http://pragmaticstudio.com/blog/2010/9/15/ios4-blocks-2"target="_blank" rel="noopener">Using Blocks in iOS 4: Designing with Blocks</a></li>
</ul>
]]></content:encoded><category>apple</category><category>programacao</category><category>tutoriais</category></item><item><title>[Objective-C] Entendendo NSAutoreleasePool</title><link>https://akitaonrails.github.io/2010/11/25/objective-c-entendendo-nsautoreleasepool/</link><guid isPermaLink="true">https://akitaonrails.github.io/2010/11/25/objective-c-entendendo-nsautoreleasepool/</guid><pubDate>Thu, 25 Nov 2010 01:13:00 -0200</pubDate><description>&lt;p&gt;Ultimamente ando brincando de desenvolvimento iPhone e pra isso caí no Objective-C. Gosto muito da linguagem. Já conhecia um pouco do básico dele mas foi a primeira vez que comecei a codificar de verdade. Alguns podem não gostar da sintaxe ou de algumas das ferramentas (realmente o XCode não é completo nem robusto o suficiente, mas dá pro gasto). Mas no geral acho o fluxo de desenvolvimento bastante agradável.&lt;/p&gt;
&lt;p&gt;Logo de cara uma coisa que confunde os que sempre trabalharam com plataformas com Garbage Collector é o gerenciamento manual de memória. Vou me abster da discussão sobre se é melhor ou pior e os trade-offs. Na prática, é simples manter isso manualmente.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Ultimamente ando brincando de desenvolvimento iPhone e pra isso caí no Objective-C. Gosto muito da linguagem. Já conhecia um pouco do básico dele mas foi a primeira vez que comecei a codificar de verdade. Alguns podem não gostar da sintaxe ou de algumas das ferramentas (realmente o XCode não é completo nem robusto o suficiente, mas dá pro gasto). Mas no geral acho o fluxo de desenvolvimento bastante agradável.</p>
<p>Logo de cara uma coisa que confunde os que sempre trabalharam com plataformas com Garbage Collector é o gerenciamento manual de memória. Vou me abster da discussão sobre se é melhor ou pior e os trade-offs. Na prática, é simples manter isso manualmente.</p>
<p>Uma coisa que confunde no início é o <tt>NSAutoreleasePool</tt>. Todo projeto Cocoa começa com algo parecido com isto, no <tt>main.m</tt>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span> <span class="p">{</span>   
</span></span><span class="line"><span class="cl"> <span class="n">NSAutoreleasePool</span> <span class="o">*</span> <span class="n">pool</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSAutoreleasePool</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">retVal</span> <span class="o">=</span> <span class="n">UIApplicationMain</span><span class="p">(</span><span class="n">argc</span><span class="p">,</span> <span class="n">argv</span><span class="p">,</span> <span class="nb">nil</span><span class="p">,</span> <span class="nb">nil</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="n">pool</span> <span class="k">release</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">retVal</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O Obj-C trabalha com contagem de referência para limpar memória. Toda vez que se chama o método <tt>alloc</tt> ou <tt>new</tt> memória é alocada, um novo objeto é instanciado e seu contador sobe para 1. Toda vez se envia a mensagem <tt>retain</tt> a esse objeto o contador é incrementado, toda vez que se envia a mensagem <tt>release</tt> o contador é decrementado. Quando o contador chega a zero, o sistema pode destruir o objeto (chamando também seu método <tt>dealloc</tt>) e a memória é devolvida ao sistema.</p>
<p>O sistema devolve memória liberado ao sistema ao final de uma execução, mas existe um caso em específico que pode dar picos de consumo de memória antes do sistema ter chance de limpá-la. Veja este trecho:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="p">-</span> <span class="p">(</span><span class="kt">IBAction</span><span class="p">)</span> <span class="nf">onClick:</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="nv">sender</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">i</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="err">\</span><span class="o">&lt;</span> <span class="mi">50000</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="n">NSString</span> <span class="o">*</span> <span class="n">teste</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSString</span> <span class="nl">stringWithFormat</span><span class="p">:</span><span class="err">`</span><span class="s">&#34;Teste %i&#34;</span><span class="p">,</span> <span class="n">i</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">      <span class="n">NSLog</span><span class="p">(</span><span class="err">`</span><span class="s">&#34;X: %@&#34;</span><span class="p">,</span> <span class="n">teste</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"> <span class="p">}</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Imagine situações onde você está consumindo um stream de dados como de um arquivo, um web service, um parser, um tweet stream ou coisas assim, com cada ítem sendo processado em loop. Não é difícil sair criando milhares de Strings sem liberá-los.</p>
<p>No caso, estamos criando Strings usando o método <tt>stringWithFormat</tt> que, por convenção, devolve o String criado depois de ter já chamado o método <tt>autorelease</tt>. Explicando, você é responsável por criar e destruir objetos. Porém, quando você repassa um objeto que você criou para outro objeto, quem é o responsável por mandar <tt>release</tt> ao objeto?</p>
<p>Esse é o caso do <tt>stringWithFormat</tt>. Nesse caso não é nem a classe <tt>NSString</tt> nem nosso código que o chamou que vai liberar a memória ocupada por esse String. Quando você tem essa situação, em vez de mandar um <tt>release</tt>, deve enviar <tt>autorelease</tt>. Isso colocará o objeto no último <tt>NSAutoreleasePool</tt> criado. Os pools são empilháveis: os objetos sempre são colocados sob a responsabilidade do último pool criado.</p>
<p>Assim, como no <tt>main.m</tt> criamos um pool, os Strings serão todos colocados lá. Porém, eles serão apenas liberados depois do loop de 50 mil voltas. Por isso teremos um pico de consumo de memória até o término do loop. Dependendo do que está processando, você pode consumir toda a memória do sistema sem saber. Veja quando rodamos esse código num aplicativo via Instruments:</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2010/11/25/Screen%20shot%202010-11-25%20at%201.03.24%20AM_original.png?1290654557" alt=""  loading="lazy" /></p>
<p>Note quanto de memória está sendo usada somente por <tt>CFString</tt>, mais de 1MB (!) Precisamos melhorar isso. E essa memória vai crescer quanto mais Strings forem criados dentro desse loop.</p>
<p>Esse padrão é fácil de identificar, basta procurar por loops que podem ser muito longos (centenas ou milhares de interações). Para “consertar” isso, podemos fazer o seguinte:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="p">-</span> <span class="p">(</span><span class="kt">IBAction</span><span class="p">)</span> <span class="nf">onClick:</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="nv">sender</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">i</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"> <span class="c1">// cria novo pool  
</span></span></span><span class="line"><span class="cl"> <span class="n">NSAutoreleasePool</span><span class="o">*</span> <span class="n">pool</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSAutoreleasePool</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="err">\</span><span class="o">&lt;</span> <span class="mi">50000</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="n">NSString</span> <span class="o">*</span> <span class="n">teste</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSString</span> <span class="nl">stringWithFormat</span><span class="p">:</span><span class="err">`</span><span class="s">&#34;Teste %i&#34;</span><span class="p">,</span> <span class="n">i</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="n">NSLog</span><span class="p">(</span><span class="err">`</span><span class="s">&#34;X: %@&#34;</span><span class="p">,</span> <span class="n">teste</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">i</span> <span class="o">%</span> <span class="mi">1000</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="c1">// limpa o pool a cada mil interações  
</span></span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="n">pool</span> <span class="k">release</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"> <span class="c1">// cria um novo pool vazio  
</span></span></span><span class="line"><span class="cl"> <span class="n">pool</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSAutoreleasePool</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"> <span class="p">}</span>  
</span></span><span class="line"><span class="cl"> <span class="p">}</span>  
</span></span><span class="line"><span class="cl"> <span class="c1">// limpa o último pool criado  
</span></span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="n">pool</span> <span class="k">release</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>É o mesmo código, porém criamos um novo <tt>NSAutoreleasePool</tt> especialmente para os objetos criados pelo loop. Dentro do loop limpamos o pool depois de alguma certa quantidade de interações que faça sentido, no exemplo, a cada 1000 interações. Uma vez que o pool é liberado, criamos outro vazio para poder continuar o loop. E no final garantimos que estamos liberando o último pool criado.</p>
<p>Com isso o consumo de memória nunca passará de um certo teto bem mais baixo que o pico causado pelo exemplo anterior. Vejamos rodando esse novo código via Instruments:</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2010/11/25/Screen%20shot%202010-11-25%20at%201.05.04%20AM_original.png?1290654550" alt=""  loading="lazy" /></p>
<p>Muito melhor! Não muito mais do que 100Kb. E esse consumo é constante e não crescente como antes, o que é mais importante. Mais do que consumir pouca memória é importante conseguir comportamentos onde o consumo não passe de um certo teto.</p>
<p>Esse é apenas um dos aspectos do gerenciamento de memória do Objective-C que é importante que os programadores se atentem. Vou fazer mais artigos sobre esse assunto, aguardem.</p>
]]></content:encoded><category>performance</category><category>apple</category><category>programacao</category></item></channel></rss>