I.ndigo Blog.
Cocos2d for iPhone 0.99.4 – Camada Transparente com OpenGL ES
Visão Geral
Segundo site do Cocos2d, Cocos2d for iPhone é um framework para desenvolver jogos 2D, demos e outras aplicações gráficas/interativas. Ele é baseado no padrão cocos2d: ele usa os mesmos conceitos, mas em vez de Python ele usa Objective-C.
Para os desenvolvedores do Framework, o Cocos2d for iPhone é:
- Fácil de usar: ele usa uma API familiar e vem com uma série de exemplos
- Rápido: ele usa boas práticas do OpenGL ES e otimiza estruturas de dados
- Flexível: ele é fácil de ser integrado com outras bibliotecas
- Grátis: é open source, compatível tanto com jogos abertos quanto fechados
- Comunidade: o cocos2d tem uma comunidade ativa, grande e amigável (fórum, IRC)
- Aprovado pela AppStore: mais de 550 jogos na AppStore o utilizam, incluindo vários jogos bem vendidos
O Cocos2d vem com uma API que torna simples a criação de projetos baseados no OpenGL ES, mesmo se você não é um expert com programação em OpenGL, uma vez que tem um bom encapsulamento de algumas funcionalidades bastante usadas.
Um ponto negativo em usar este tipo de ferramenta é que algumas vezes você se perde quando ele automatiza algo que você não gostaria que fosse feito. Criar uma camada transparente de OpenGL ES usando o Cocos2d tem esse problema. Uma vez que muitas pessoas da comunidade tiveram esse problema, resolvemos postar sobre isso.
Criando uma camada transparente do OpenGL ES Layer com o Cocos2d
Criar uma camada transparente de OpenGL ES com o Cocos2d v 0.99.4 não foi uma tarefa simples, uma vez que seu código template contém uma Macro para inicializar uma série de variáveis internas.
Se você ver a macro CC_DIRECTOR_INIT(), localizada no arquivo ccMacros.h, temos o seguinte:
#define CC_DIRECTOR_INIT() \ do { \ \ window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; \ \ if( ! [CCDirector setDirectorType:kCCDirectorTypeDisplayLink] ) \ [CCDirector setDirectorType:kCCDirectorTypeNSTimer]; \ \ CCDirector *__director = [CCDirector sharedDirector]; \ [__director setDeviceOrientation:kCCDeviceOrientationPortrait]; \ [__director setDisplayFPS:NO]; \ [__director setAnimationInterval:1.0/60]; \ \ EAGLView *__glView = [EAGLView viewWithFrame:[window bounds] \ pixelFormat:kEAGLColorFormatRGB565 \ depthFormat:0 \ preserveBackbuffer:NO]; \ \ [__director setOpenGLView:__glView]; \ \ [window addSubview:__glView]; \ [window makeKeyAndVisible]; \ \ } while(0); \
Como podemos ver, esta macro cria um EAGLView que tem um pixelFormat do tipo kEAGLColorFormatRGB565, que é de 16 bits. Para termos transparencia habilitada no nosso EAGLView precisamos criá-la com o formato kEAGLColorFormatRGBA8, que é de 32 bits.
Temos diversas formas de resolver isso, como alterar a macro ou inicializar tudo por nossa conta. O importante é certificar-se de alterar a linha:
EAGLView *__glView = [EAGLView viewWithFrame:[window bounds] \ pixelFormat:kEAGLColorFormatRGB565 \ depthFormat:0 \ preserveBackbuffer:NO]; \
para
EAGLView *__glView = [EAGLView viewWithFrame:[window bounds] \ pixelFormat:kEAGLColorFormatRGBA8 \ depthFormat:0 \ preserveBackbuffer:NO]; \
Com isso, teremos nossa camada OpenGL ES transparente quando usando:
glClearColor(0, 0, 0, 0);
Na linha acima, o último parâmetro indica a opacidade
(http://www.khronos.org/opengles/sdk/1.1/docs/man/).
É isso! Esperamos que você goste do Cocos2d for iPhone e que esta dica lhe seja útil!
Este post também está disponível em inglês: Cocos2d for iPhone 0.99.4 – OpenGL ES Transparent Layer
Testes de performance do Core Data sobre SQLite – Parte 2
Dando seqüência ao último post, Testes de performance do Core Data sobre SQLite – Parte 1, no qual introduzimos o Core Data e definimos o ambiente de testes, agora iniciaremos a apresentação dos resultados desta análise.
Assim como definido anteriormente, este teste mostrará o desempenho em 4 situações (veja detalhes no post anterior):
- Inserções sem relacionamentos;
- Inserções com relacionamentos;
- Buscas sem relacionamentos;
- Buscas com relacionamentos.
Este post cobrirá as 2 primeiras situações (inserções).
1. Inserções sem relacionamentos
Este teste tenta executar 10000 comandos inserts de 5 formas diferentes:
- Tamanho do lote: 1; Repetições: 10000;
- Tamanho do lote: 10; Repetições: 1000;
- Tamanho do lote: 100; Repetições: 100;
- Tamanho do lote: 1000; Repetições: 10;
- Tamanho do lote: 10000; Repetições: 1;
Os resultados foram os seguintes:
a) Tamanho do lote: 1; Repetições: 10000

| mín | 0,037017 s |
| máx | 0,571604 s |
| média | 0,047213 s |
| total | 417,3 s |
Como podemos ver no gráfico, temos uma pequena variação entre o tempo das inserções. Embora o valor máximo do gráfico seja 0,57 segundos, a média (0,047 s) foi bem mais próxima do valor mínimo (0,037 s). Também, podemos ver que o tempo necessário para uma inserções não muda significantemente enquanto a tabela aumenta.
b) Tamanho do lote: 10; Repetições: 1000

| mín | 0,051545 s |
| máx | 1,592167 s |
| média | 0,077328 s |
| total | 77,3 s |
Este caso nos mostrou que, aumentando o tamanho do lote para 10 precisamos, em média, de cerca de 1,64 vezes mais tempo para executar este lote. Assim, podemos imaginar que é muito melhor executar um lote grande do que vários lotes pequenos. O teste também nos mostrou que para inserir 10000 registros com tamanho de lote de 10 precisamos de 77,3 segundos, enquanto com tamanho de lote de 1, para inserir 10000 registros precisamos de 417,3 segundos.
c) Tamanho de lote: 100; Repetições: 100

| mín | 0,221817 s |
| máx | 0,733436 s |
| média | 0,276504 s |
| total | 27,7 s |
Novamente, aumentando o tamanho de lote, agora para 100, precisamos de cerca de 3,6 mais tempo por lote do que precisamos com tamanho de lote de 10. Assim, podemos deduzir que o tempo por lote não aumenta linearmente com o tamanho de lote. Mas novamente, o tempo total para executar os 10000 inserts diminuiu (27 s contra 77 s).
d) Tamanho de lote: 1000; Repetições: 10

| mín | 2,341496 s |
| máx | 2,895445 s |
| média | 2,522845 s |
| total | 25,2 s |
Novamente, o mesmo aconteceu. Com o aumento do tamanho de lote para 1000 precisamos de 9,1 vezes mais tempo do que com tamanho de lote de 100. O tempo total foi melhor que o anterior, mas quase o mesmo (25 s contra 27).
e) Tamanho de lote: 10000; Repetições: 1 (10 repetições com banco vazio)

| mín | 19,171194 s |
| máx | 24,020913 s |
| média | 22,2 s |
Desta vez, aumentando o tamanho de lote para 10000 precisamos de 8 vezes mais tempo do que com tamanho de lote de 1000, enquanto poderíamos imaginar que precisaríamos de mais de 9,1 vezes. Assim, levamos somente 22 s para executar os 10000 inserts.
Conclusão
Estes testes resultaram na seguinte tabela:
| Teste | Tempo médio por lote | Tempo Total |
| a | t1 ou 0,047213 s | t2 ou 417,3 s |
| b | 1,83 x t1 ou 0,077328 s | t2/5,40 ou 77,3 s |
| c | 5,86 x t1 ou 0,276504 s | t2/0,066 ou 27,7 s |
| d | 53,68 x t1 ou 2,523 s | t2/0.060 ou 25,2 s |
| e | 470,34 x t1 ou 22,2 s | t2/0,053 ou 22,2 s |
Como podemos ver, para inserções simples (sem relacionamentos) quando aumentamos o tamanho do lote o tempo para executá-lo é maior, mas, o tempo total é menor. Assim, quando usando o Core Data, sempre que possível devemos salvar dados em lotes grandes.
2. Inserções com relacionamentos
Este teste mostra como o tempo para executar uma inserção aumenta com o aumento do número de relacionamentos (em cada inserção) e de linhas da tabela. O número de relacionamentos varia de 0 até 3.
a) Quantidade de relacionamentos: 0

| mín | 0,053622 s |
| máx | 0,626013 s |
| média | 0,068631 s |
| total | 137,3 s |
Como este teste não contém relacionamentos, o resultado é o mesmo do teste anterior.
b) Quantidade de relacionamentos: 1

| mín | 0,617910 s |
| máx | 0,353416 s |
| média | 0,080156 s |
| total | 160,3 s |
Como seria esperado, com um relacionamento o tempo médio de inserção foi 1,17 vezes maior do que sem inserções.
c) Quantidade de relacionamentos: 2

| mín | 0,078214 s |
| máx | 0,559592 s |
| média | 0,109143 s |
| total | 218,3 s |
Com 2 relacionamentos precisamos de ainda mais tempo para processar cada inserção: 1,37 vezes mais do que com 1 relacionamento. Também, podemos ver que parece que, enquanto a o banco de dados aumenta, leva mais tempo para executar cada insert.
d) Quantidade de relacionamentos: 3

| mín | 0,093524 s |
| máx | 0,650233 s |
| média | 0,135843 s |
| total | 271,7 s |
Com 3 relacionamentos o tempo médio foi ainda pior: 1,244 vezes mais que com 2 relacionamentos.
Conclusão
A seguinte tabela resulta dos testes realizados:
| Teste | Tempo médio | Tempo total |
| a | t1 ou 0,068631 s | t2 ou 137,3 s |
| b | 1,17 x t1 ou 0,080156 s | 1,17 x t2 ou 160,3 s |
| c | 1,59 x t1 ou 0,109143 s | 1,59 x t2 ou 218,3 s |
| d | 1,99 x t1 ou 0,135843 s | 1,99 x t2 ou 271,7 s |
Como podemos ver, com o aumento do número de relacionamentos o tempo médio de inserção também aumenta. Este aumento não é linear.
O próximo post apresentará nossos resultados e conclusões para seleções no Core Data, acompanhe!
Este post também está disponível em inglês: Core Data over SQLite Performance Tests – Part 2
Testes de performance do Core Data sobre SQLite – Parte 1
Dando sequência ao post da semana passada, Visão Geral de iPhone Persistent Store, a I.ndigo inicia a série de testes de performance das as alternativas de persistência de dados no iPhone com o framework oficial da Apple, o Core Data.
Introdução
Core Data foi disponibilizado para iPhone na versão 3.0 do SDK, apesar de já existir para Mac OSX há mais tempo. Esse framework implementa um Object Graph Manager, que fornece funcionalidades de gerenciamento de dados, incluindo inserção de dados, alterações dos mesmos, funcionalidade de desfazer e refazer as mudanças, além da possibilidade de persistí-los.
O Core Data apresenta uma API de alto nível, que abstrai as regras de gerência de dados, como identificadores, consistência do modelo de dados, validação, além de inserção, alteração e deleção de dados e criação e gerenciamento do arquivo de persistência.
A abstração da modelagem de dados é obtida por meio da ferramenta de modelagem de dados integrada no Xcode, onde o desenvolvedor deve descrever os dados do sistema por meio de um diagrama entidade-relacionamento. O Xcode se encarrega de gerar as classes e arquivos necessários para a gerência e, opcionalmente, persistência dos dados.
A camada de persistência de dados abstrai do desenvolvedor os detalhes de implementação do banco de dados. Na verdade, o SDK disponibiliza alguns tipos de camada persistente, como banco de dados SQLite, formato binário de arquivo e XML, este último disponível somente para Mac OSX. Independentemente do tipo de persistência escolhida, o desenvolvedor interage somente com objetos e suas propriedades.
Arquitetura do Core Data
Para implementar todas as funcionalidades descritas, foi escolhida uma arquitetura sólida e flexível, como descrito no diagrama que segue.
- NSManagedObjectModel: Criado em tempo de execurtpxução, é baseado no modelo de dados do projeto, que é descrito pelo desenvolvedor na ferramenta integrada de modelagem de dados. Representa o modelo de dados do sistema;
- NSManagedObject: Representa cada entidade e suas propriedades, modeladas pelo desenvolvedor. As propriedades incluem atributos e relacionamentos;
- NSManagedObjectContext: Disponibiliza todas as funcionalidades de gerspztssusrência de dados mencionadas, como busca, inserção e deleção. Essa classe ssssé ciente e tem acesso ao Persistent Store Coordinator;
- NSPersistentStoreCoordinator: Disponibiliza uma interface para a camada de persistência de dados.
Como citado, o Core Data não limitado à persistência de dados. Todos as características de gerenciamento de dados são separadas da camanda de persistência e podem ser utilizadas sem ela.
Metodologia de testes
Ambiente de testes
| iPhone 3G 8GB | Xcode 3.2.3 | iPhone SDK 4.0 | iOS 4.0 | Release Configuration |
Modelo de dados
Cenário de teste
SQLite foi escolhido, ao invés de um formato binário, uma vez que somente esse tipo é capaz de carregar objetos parcialmente, por meio da funcionalidade de lazy loading, o que é muito importante, tendo em vista que o desempenho do hardware do iPhone é alto, porém limitado.
Além disso, foi consiserado suficiente para os fins do teste um banco de dados de 10000 linhas, ou 10000 objetos persistidos. O Core Data persiste dados salvando de uma vez todos os objetos (NSManagedObject) presentes no contexto (NSManagedObjectContext). Assim, a metodologia para os testes de inserção prevê operações em lotes, de acordo com a tabela que segue.
| Tamanho do lote | Repetições |
| 1 | 10000 |
| 10 | 1000 |
| 100 | 100 |
| 1000 | 10 |
| 10000 | 1 |
Os seguintes testes serão realizados:
- Inserção sem relacionamentos
O principal objetivo desse teste é avaliar a degradação de performance de acordo com o tamanho do banco de dados. Assim, seguindo a tabela acima, 10000 objetos serão persistidos. - Inserção com relacionamentos
Nesse teste será medida a influência da quantidade de relacionamentos de uma entidade na performance da inserção. Serão inseridos 2000 objetos, com a quantidade de relaciomentos variando de nenhuma até quatro. - Busca sem relacionamentos
Nesse teste serão abordados dois modos de busca: por propriedades e pelo identificador. Novamente serão inseridos e buscados 10000 objetos. - Busca com relacionamentos
O último teste tem como objetivo medir a degradação de performance de acordo com a quantidade de relacionamentos de um entidade. Como esse é o teste mais custoso, os dados serão buscados a cada 100 inserções, até que se alcance 10000 objetos.
Todos os testes se completam para avaliar a degradação de performance do Core Data, em relação ao tamanho da base de dados, bem como a quantidade de seus relacionamentos.
O próximo post trará nossos resultados e conclusões, acompanhe!
Este post também está disponível em ingês: Core Data over SQLite Performance Tests – Part 1
Visão Geral de iPhone Persistent Store
Armazenar informações em aplicações de iPhone é uma tarefa que deve ser cuidadosamente analisada. Sabemos que o iPhone tem limitações de recursos e que eles precisam ser usados e liberados de forma correta. O problema é: o que acontece quando você precisa de uma aplicação que armazena e carrega uma grande quantia de dados (como um Sistema de Automação de Força de Venda)?
Não sabemos se aplicação iPhone se comportará bem nesses acessos (conforme o tamanho do banco de dados aumenta). Além disso, há diversas opções de implementação de camada de persistência desenvolvida por terceiro, ou seja, camada responsável por gerenciar o acesso aos dados e seu mapeamento a objetos.
Estas opções de terceiros podem ter outros problemas que, por sua vez, podem resultar em perda de desempenho com o tempo. Assim, escolher o melhor para cada situação não é fácil.
Portanto, a I.ndigo decidiu realizar uma série de experimentos de desempenho nas opções mais conhecidas de persistência de dados e também, obviamente, no Core Data implementado puramente.
Ao buscar na web por opções tivemos a seguinte lista de tecnologias:
| Core Data | FMDB | Magical Panda | Mogenerator | OmniDataObjects | iphone-rsdb | SQLite | SQLitePersistentObjects | |
| Abstraction level | object graph manager | SQLite wrapper | ActiveRecord (over Core Data) | object graph manager | Core Data API implementation (over SQLite) | SQLite wrapper (based on fmdb) | - | ActiveRecord over SQLite |
| belongs_to implementation | yes | yes | yes | yes | yes | yes | yes | yes |
| has_many implementation | yes | yes | yes | yes | yes | yes | yes | yes |
| many_to_many implementation | yes | yes | yes | yes | N/A | no | yes | no |
| SQL | no | yes | no | no | no | yes | yes | yes |
| Lazy Loading | yes | no | yes | yes | yes | no | yes | no |
| License | iPhone Program | MIT | MIT | N/A | MIT | Apache 2.0 | Public Domain | New BSD License |
Esta tabela também mostra algumas informações sobre as tecnologias, que nos ajudaram a escolher opções diferentes para testar e comparar. A tabela também ajuda a escolher quando você tem limitações de licença ou precisa de uma funcionalidade específica, como implementação de SQL.
Os próximos posts cobrirão uma série de testes executados em algumas dessas tecnologias e comparações entre elas em diversos cenários.
Acompanhe!
Este post também está disponível em inglês: iPhone Persistent Store Overview
Pesquisa de Desenvolvimento de Aplicações Móveis
Appcelerator (http://www.appcelerator.com/) empresa responsável pelo desenvolvimento da plataforma Appcelerator Titanium (discutido neste post) realizou uma pesquisa com 2700 desenvolvedores de aplicações para dispositivos móveis. Esta pesquisa engloba detalhes e percepções de plataformas como iOS (Apple), Android (Google), webOS (Palm/HP), Windows Phone 7 (Microsoft), Symbian (Nokia) e Blackberry (RIM).
Informações interessantes como aumento da motivação em desenvolver aplicações na plataforma Apple tem aumentado desde o lançamento do iPad.
A pesquisa pode ser encontrada na íntegra no site da Appcelerator ou baixada aqui.
Appcelerator Titanium
Hoje em dia temos uma série de novas tecnologias sendo lançadas diariamente e é cada vez mais difícil selecionar o que usar e quando usar. Além disso, há um grande risco experimentando algo novo dentro da empresa, uma vez que os recursos podem não saber utilizar a nova tecnologia e, em um pior caso, essa pode conter diversos bugs.
Appcelerator Titanium (http://www.appcelerator.com/) é um desses, mas quando você começa a usá-lo percebe que não se trata de somente “mais uma tecnologia”.
Titanium nos trás uma nova forma de desenvolver “Aplicações Desktop” e, mais recentemente, “Aplicações Mobile“. Eu uso aspas aqui porque ele não é completamente desktop ou mobile, mas faz uso de um webkit que permite que você programe como se estivesse desenvolvendo um website.
O que eu quero dizer é que tudo que você precisa fazer é criar seu HTML/CSS/Javascript, compilar o código e a sua aplicação está pronta. Além disso, ele é multi-plataforma, significando que você pode construir aplicações para o Windows, OS X e Linux na versão desktop e para o iPhone and Android na versão mobile.
Uso de AJAX
Pense no Titanium como se você estivesse criando sua aplicação web. Você pode usar sua biblioteca de javascript favorita, como Prototype, JQuery ou Mootools. Assim, você pode facilmente fazer suas requisições AJAX ao servidor e tornar sua aplicação dinâmica e amigável.
Uma coisa a ser notada aqui é que se você já possuir uma aplicação web (suponha uma MVC-like, baseado em rails) você pode facilmente consumir seu server-side pela sua aplicação em Titanium e, então, o principal problema será somente desenvolver sua UI. Isso significa que você pode criar aplicações multi-plataforma de forma muito rápida.
Titanium Vs Adobe Air?
Eu acredito que eles estão competindo, mas vejo o Titanium como o mais fácil, uma vez que é bem mais fácil criar interfaces web em vez de interfaces flash (se você não for um expert). Em ambos os casos o usuário necessita instalar kits para ver a aplicação rodando e, no caso do Air, os recursos podem ter uma UI bem mais rica, mas quando você pensa em desenvolver algo bem rapidamente (e você não tem um grande artista como seu recurso), o Titanium é a melhor escolha.
Uma opção para desenvolvimento mobile
Titanium é mais que um website. Com ele você pode desenvolver situações offline, registrar conteúdo localmente e criar notificações facilmente. Para implementar aplicações offline, o Titanium faz uso do Google Gears, facilitando a sincronização de dados. O Titanium também suporta o uso de linguagens de programação como Ruby, Python e PHP, o que o torna ainda mais poderoso.
Além disso, embora seja baseado em web, você pode ter controles nativos da plataforma que está desenvolvendo, como os controles do iPhone, tudo isso utilizando javascript.
O único problema de usar estas funcionalidades é que a documentação do Titanium não está completamente pronta, então muitas vezes você terá dificuldades na implementação.
O preço?
O Titanium é completamente free. Porém, em março de 2010 foi lançada uma versão Professional ($199/desenvolvedor/mês) que terá, nas palavras deles, “premium support, analytics and rapid updates”.




