Artigos da contendo a tag ‘iphone’

I.ndigo Blog.

The Royal Wedding Rebound


Apps
Edmar Miyake
18abril

Na semana passada completamos 15 dias do lançamento dos aplicativos iPhone e iPad que fizemos para a NBC – o The Royal Wedding by NBC News.

O fato do aplicativo ter sido lançado durante os programas de maior audiência da televisão norte-americana, nos rendeu uma repercursão que não acreditávamos ser possível em tão pouco tempo, em pouquíssimas horas nosso app já figurava entre os vinte mais baixados da App Store Americana, chegando ao segundo lugar entre os aplicativos da categoria lifestyle.

Os dias que sucederam o lançamento foram de mais surpresas ainda, figuramos entre os aplicativos recomendados pela Apple nas seções “What’s Hot” e “New and Noteworthy” ao lado do Justin Bieber e da Oprah (rs). Outro fato curioso foi a criação de uma área inteira de destaque na App Store para aplicativos voltados à cobertura do casamento real.

Nosso app em destaque entro o Justin Bieber e a Oprah

Nosso app em destaque no New and Noteworthy

Área de destaque criada pela Apple para Apps do Royal Wedding

Área de destaque criada pela Apple para Apps do Royal Wedding

A notícia do aplicativo também repercurtiu em alguns sites que gostamos muito como o appolicious e o mobilepedia, no youtube a NBC publicou um vídeo com o Vice-Presidente deles contando detalhes do desafio de lançar um aplicativo tão completo, em tão pouco tempo.

O aprendizado com o projeto foi grande também para o nosso time, por exemplo em mobile-advertising, tivemos a oportunidade de lidar de perto com o iAd aproveitando todo o buzz criado pela NBC e compará-lo com a busca de patrocínios independentes. Tem sido interessante também analisar o padrão de comportamento e o país de origem dos usuários que baixaram o aplicativo.

Estamos agora ansiosos para acompanhar a evolução de usuários com a proximidade do casamento, e fiquem de olho para acompanhar as próximas novidades que vamos lançar até lá.

permalink
, , , , , , , ,

Permitindo Untrusted Certificates com UIWebView


Go Tech
Edmar Miyake
11abril

Recentemente caímos em uma situação em que necessitávamos testar uma aplicação iPhone (SDK 4.0) tentando acessar uma aplicação web via UIWebView. Porém, havia um problema: todas as páginas do servidor eram fornecidas por conexão HTTPS, mas o certificado não era válido.

Uma forma de resolver este problema foi usando o método estático setAllowsAnyHTTPSCertificate:forHost: da classe NSURLRequest, que faz parte da API privada da Apple. Este método permite que você especifique quais host podem ter seu certificado HTTPS aceito pela aplicação.

Usando o método acima há grandes chances de ter seu app rejeitado, mas em uma situação de teste a alternativa funciona muito bem.

Você deve usar este método antes de fazer o request do UIWebView, como o seguinte:

NSURL *url = [[NSURL alloc] initWithString:@”https://www.something.com”];
[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[url host]];
[webView loadRequest:url];

Isto seria suficiente, mas você verá que seu código mostrará uma mensagem de warning dizendo “‘NSURLRequest’ may not respond to ‘+setAllowsAnyHTTPSCertificate:forHost:’”. Se você quer resolver isso, adicione o seguinte ao final do arquivo .h que corresponde ao .m que você está trabalhando:

@interface NSURLRequest (Certificates)
+ (void)setAllowsAnyHTTPSCertificate:(BOOL)allow forHost:(NSString*)host;
@end

Este código sobrecarrega a interface do método da classe NSURLRequest, mas não iremos reimplementá-lo, então a implementação existente na API privada pode ser usada.

Como pode ser visto, embora o uso da API privada da Apple não seja permitido, ele pode ser bastante útil em algumas situações.

Espero que este post tenha ajudado. Obrigado!

permalink
, , , ,

Airbnb vencedor da categoria mobile do South by Southwest, reforça o time de cases de sucesso em consumo colaborativo


Keep Watching
Edmar Miyake
11abril

A Airbnb é uma empresa relativamente nova, que foi fundada a partir de um simples conceito – conectar pessoas que procuram um lugar para ficar e pessoas que têm um espaço livre para emprestar/alugar – e que recentemente atingiu a incrível marce de um milhão de noites reservadas. É uma marca impressionante para uma empresa que tem menos de cinco anos de vida, e um salto gigante para o movimento de consumo colaborativo que segundo Rachel Botsman co-autora do livro “What’s Mine Is Yours: The Rise of Collaborative Consumption” está em sua “fase incipiente” e tem o potencial de ser um catalisador cultural e económico para as mudanças nas formas que vivemos e fazemos negócios.

O sucesso da Airbnb e de seu aplicativo – que já atingiu em poucos meses mais de 160.000 de downloads no itunes – é um bom sinal por uma série de razões. Em primeiro lugar, é simplesmente gratificante ver página após página de opiniões positivas sobre as experiências de seus usuários. Por mais absurdo que possa parecer, em sua maioria, estranhos na Internet tendem a se comportar bem. “Eu vou passar a noite na casa desse cara que eu acabei de conhecer” não soa mais tão assustador quanto soaria alguns anos atrás. Na verdade soa mais para “Eu vou passar a noite na casa de uma cara que tem uma grande sala com vista para o mar e 180 reviews com cinco estrelas”.

O sucesso do Airbnb continua a evidenciar que o consumo colaborativo não é apenas algo que as pessoas procuram quando estão querendo economizar, ou quando estão sem opções (de hospedagem no caso) – claro, muita gente usa o Airbnb, para encontrar um bom quarto com preços comparativamente mais baixo – mas há muitos que usam o aplicativo para encontrar lugares que custam milhares de dólares por noite.

Se a empresa era apenas dirigida por uma resposta a um mau momento da economia, agora que os mercados estão em alta, seria de esperar que os negócios do Airbnb fossem pelo menos diminuir a velocidade de crescimento, mas ao invés disso, eles estão crescendo – e rápido. A companhia reportou em janeiro passado um de 65%.

No que diz respeito ao modelo de negócio o Airbnb leva uma porcentagem de 10% do preço de reserva, o que significa que 90% do dinheiro das mais de um milhão de noites reservadas foi diretamente para as mãos dos usuários do aplicativo.

Os Estados Unidos sempre foram amplamente criticados pelos excessos do capitalismo e pela cultura gananciosa de suas grandes corporações, mas parece que os emprendedores de crowd-sourcing e os beta-empreendedores como a Airbnb encontraram um meio-termo onde todos saem ganhando.

Então parabéns, Airbnb. Compartilhar é cuidar de fato.

fontes: JustMeans, South by South West, RCR Wireless

permalink
, , , , , , , ,

Core Data over SQLite Performance Tests – Part 3


English
Raphael Petegrosso
12agosto

Following the last post, Core Data over SQLite Performance Tests – Part 2, when we began performance tests with Core Data, now we continue with the results of this analysis.

As we defined before, this test will show the performance of 4 situations (see details on the previous post):

  1. Insert without join tables;
  2. Inserts with tables;
  3. Select without join tables;
  4. Select with join tables.

The previous post showed the first 2 situations. This time we will cover the last 2 (selects).

1. Select without join tables

This test tries to execute selects without joins in 2 ways:

  • Fetch by object’s attributes;
  • Fetch by identifier.

In each case, we see how the time to execute the select varies with the number of registries of the table (from 1 to 10000):

a) Fetch by object’s attributes

min 0.007469 s
max 0.259504 s
average 0.049227 s
total 492.3 s

As we can see on the chart, when fetching by an attribute that is not indexed the time needed to execute the select varies almost linearly with the number of registries of the table. So, it is easy to think on how the performance of your table is getting worst with the time.

b) Fetch by identifier

min 0.000070 s
max 0.004420 s
average 0.000086 s
total 0.8597 s

This case shown us that fetching by the identifier (indexed), the time to fetch almost do not change with the number of registries, once the average time to fetch was almost equal the min time.

Conclusion

This tests resulted on the following table:

Test Average Time per Select Total Time
Fetch by object’s attributes t1 or 0.049227 s t2 or 492.3 s
Fetch by identifier 0.0017 x t1 or 0.000086 s 0.0017 x t2 or 0.8597 s

As we can see, for simple selects (without joins) when possible we should use identifiers to fetch, but, if we need to fetch by an attribute, it’s not hard to think about the performance, once it increases linearly with the size of the table.

2. Selects with join tables

This test shows how the time to execute a select increases as the number of join tables (in each select) and number of rows increases. The number of joins varies from 0 to 4.

a) Joins quantity: 0

min 0.010763 s
max 0.405039 s
average 0.071537 s
total 7.15 s

This test has no joins, so the results is the same from the previous test when fetching by an attribute.

b) Joins quantity: 1

min 0.012153 s
max 0.632435 s
average 0.299673 s
total 29.98 s

As might be expected, with 1 join the average time to a insert was much worst, about 4.27 times greater than with 0 joins.

c) Joins quantity: 2

min 0.021038 s
max 0.633293 s
average 0.29986 s
total 29.96 s

With 2 joins we needed almost the same time to process the select, as expected, once the fetching engine has already entered on the process’ join step, what is not needed with 0 joins.

d) Joins quantity: 3

min 0.025723 s
max 0.621014 s
average 0.303619 s
total 30.36 s

With 3 joins the average time was slightly worst again, as we might expect.

e) Joins quantity: 4

min 0.027883 s
max 0.64675 s
average 0.316077 s
total 31.61 s

Again, with 4 joins the average time was slightly worst, as we might expect.

Conclusion

The following table results from the tests:

Test Average Time Total Time
0 joins 0.071537 s 7.15 s
1 join 0.299673 s 29.98 s
2 joins 0.29986 s 29.96 s
3 joins 0.303619 s 30.36 s
4 joins 0.316077 s 31.61 s

As we can see, we have a great variance from 0 to 1 join, but a small variance as the number of joins increases, due the way the select engine works.

This post, and the previous one, showed performance tests for Core Data that bring us information to analyse when use it in a project and what impact we would have when using it.

The next posts will present our analysis over the Magical Panda Active Record framework. We expect you are anxious as we are. Stay tuned!

This post is also available in Portuguese: Testes de performance do Core Data sobre SQLite – Parte 3.

permalink
, ,

Testes de performance do Core Data sobre SQLite – Parte 3


Go Tech
Raphael Petegrosso
12agosto

Seguindo nosso último post, Testes de performance do Core Data sobre SQLite – Parte 2, quando iniciamos testes de desempenho com o Core Cata, agora continuaremos com os resultados desta análise.

Como definimos anteriormente este teste mostrará o desempenho em 4 situações (veja detalhes no post anterior):

  1. Inserções sem relacionamentos;
  2. Inserções com relacionamentos;
  3. Buscas sem relacionamentos;
  4. Buscas com relacionamentos.

O post anterior mostrou as 2 primeiras situações. Este post mostrará as últimas duas (selects).

1. Buscas sem relacionamentos

Este teste tenta executar buscas sem joins de 2 formas:

  • Busca por atributo;
  • Busca por identificador.

Em cada caso, vemos como o tempo para executar a busca varia com o número de registros da tabela (de 1 até 10000):

a) Busca por atributo

mín 0,007469 s
máx 0,259504 s
média 0,049227 s
total 492,3 s

Como podemos ver no gráfico, quando buscando por um atributo que não esteja indexado o tempo necessário para executar o select varia quase linearmente com o número de registros da tabela. Assim, é fácil pensar em como o desempenho de sua tabela está piorando com o tempo.

b) Busca por identificador

mín 0,000070 s
máx 0,004420 s
média 0,000086 s
total 0,8597 s

Este caso mostra que buscando pelo identificador (indexado), o tempo de busca praticamente não muda com o aumento do número de registros da tabela, uma vez que o tempo médio de busca foi quase igual ao tempo mínimo.

Conclusão

Estes testes resultaram na seguinte tabela:

Teste Tempo Médio por Select Tempo Total
Busca por atributo t1 or 0,049227 s t2 or 492,3 s
Busca por identificador 0,0017 x t1 or 0,000086 s 0,0017 x t2 or 0,8597 s

Como podemos ver, para selects simples (sem joins) sempre que possível devemos usar identificadores para a busca, mas, se precisarmos buscar pelo identificador, não é difícil pensar no desempenho, uma vez que ele aumenta linearmente com o tamanho da tabela.

2. Buscas com relacionamentos

Este teste mostra como o tempo para executar um select aumenta com o número de joins (em cada select) e o número de linhas. O número de joins varia de 0 a 4.

a) Relacionamentos: 0

mín 0,010763 s
máx 0,405039 s
média 0,071537 s
total 7,15 s

Este teste não tem relacionamentos, então o resultado é o mesmo do teste anterior quando buscando por um atributo.

b) Relacionamentos: 1

mín 0,012153 s
máx 0,632435 s
média 0,299673 s
total 29,98 s

Como esperado, com 1 join o tempo médio foi bem maior, 4,27 vezes maior que com 0 joins.

c) Relacionamentos: 2

mín 0,021038 s
máx 0,633293 s
média 0,29986 s
total 29,96 s

Com 2 joins precisamos de quase o mesmo tempo de processar o select, como esperado, uma vez que a engine de busca já entrou o passo de join do processo de busca, o que não ocorre com 0 joins.

d) Relacionamentos: 3

mín 0,025723 s
máx 0,621014 s
média 0,303619 s
total 30,36 s

Com 3 joins o tempo médio foi levemente pior novamente, como esperado.

e) Relacionamentos: 4

mín 0,027883 s
máx 0,64675 s
média 0,316077 s
total 31,61 s

Novamente, com 4 joins o tempo médio foi levemente pior, como esperado.

Conclusão

A seguinte tabela resulta dos testes:

Teste Tempo Médio Tempo Total
0 joins 0,071537 s 7,15 s
1 join 0,299673 s 29,98 s
2 joins 0,29986 s 29,96 s
3 joins 0,303619 s 30,36 s
4 joins 0,316077 s 31,61 s

Como podemos ver, temos uma grande variação de 0 para 1 join, mas uma pequena variação conforme o número de joins aumenta, devido a funcionamento da engine de busca.

Este post, e o anterior, mostraram os testes de desempenho para o Core Data, que nos trouxeram informações para analisar quando usá-lo em um project e qual impacto teríamos quando usando-o.

Os próximos posts apresentarão nossa análise sobre o framework Magical Panda Active Record. Esperamos que você esteja ansioso como nós estamos.

Este post também está disponível em Inglês: Core Data over SQLite Performance Tests – Part 3

permalink
, ,

Cocos2d for iPhone 0.99.4 – Camada Transparente com OpenGL ES


Go Tech
Raphael Petegrosso
27julho

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

permalink
, ,

Cocos2d for iPhone 0.99.4 – OpenGL ES Transparent Layer


English
Raphael Petegrosso
27julho

Overview

According to Cocos2d website, Cocos2d for iPhone is a framework for building 2D games, demos, and other graphical/interactive applications. It is based on the cocos2d design: it uses the same concepts, but instead of using Python it uses Objective-C.

Their website says that Cocos2d for iPhone is:

  • Easy to use: it uses a familiar API, and comes with lots of examples
  • Fast: it uses the OpenGL ES best practices and optimized data structures
  • Flexible: it is easy to extend, easy to integrate with 3rd party libraries
  • Free: is open source, compatible both with closed and open source games
  • Community supported: cocos2d has an active, big and friendly community (forum, IRC)
  • AppStore approved: More than 550 AppStore games already use it, including many best seller games.

Cocos2d comes with an API that makes it simple to create an OpenGL ES based project, even if you are not an expert with OpenGL programming, once it has a nice encapsulation of some functionalities that are mostly used.

One negative point of using this kind of tool is that sometimes you get lost when it automates something that you didn’t want to be done for you. When trying to create a transparent OpenGL ES Layer with Cocos2d we saw that lot of people had this problem so we resolved to post about it.

Creating a Transparent OpenGL ES Layer with Cocos2d

Creating a transparent OpenGL ES Layer with Cocos2d v 0.99.4 was not an easy job, once its template code use a Macro to initialize a set of variables.

If you see the CC_DIRECTOR_INIT() macro, located on the ccMacros.h file, we have the following:

#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);                                                                      \

As we can see, this macro creates an EAGLView that has pixelFormat of type kEAGLColorFormatRGB565, which is 16 bits. In order to have transparency enabled in our EAGLView we need to create it using kEAGLColorFormatRGBA8 format, which is 32 bits.

We have lot of ways to solve it, such as changing that macro or initializing everything by ourselves. The important thing is to make sure to change the line:

EAGLView *__glView = [EAGLView viewWithFrame:[window bounds]                      \
                                 pixelFormat:kEAGLColorFormatRGB565               \
                                 depthFormat:0                                    \
                          preserveBackbuffer:NO];                                 \

to

EAGLView *__glView = [EAGLView viewWithFrame:[window bounds]                      \
                                 pixelFormat:kEAGLColorFormatRGBA8                \
                                 depthFormat:0                                    \
                          preserveBackbuffer:NO];                                 \

So, we will have a transparent layer when using:

glClearColor(0, 0, 0, 0);

In the above line, the last parameter indicates the opacity.
(http://www.khronos.org/opengles/sdk/1.1/docs/man/).

So that’s it! We hope you enjoy Cocos2d for iPhone and this tip helps you!

This post is also available in Portuguese: Cocos2d for iPhone 0.99.4 – Camada Transparente com OpenGL ES

permalink
, , ,

Testes de performance do Core Data sobre SQLite – Parte 2


Go Tech
Raphael Petegrosso
22julho

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):

  1. Inserções sem relacionamentos;
  2. Inserções com relacionamentos;
  3. Buscas sem relacionamentos;
  4. 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

permalink
, ,

Core Data over SQLite Performance Tests – Part 2


English
Raphael Petegrosso
22julho

Following the last post, Core Data over SQLite Performance Tests – Part 1, when we introduced Core Data and defined the environment in which tests will run on, now we are going to start presenting you the results of this analysis.

As we defined before, this test will show the performance of 4 situations (see details on the previous post):

  1. Insert without join tables;
  2. Inserts with tables;
  3. Select without join tables;
  4. Select with join tables.

This post will cover the first 2 situations (inserts).

1. Inserts without join tables

This test tries to execute 10000 inserts on 5 different ways:

  • Batch size: 1; Times: 10000;
  • Batch size: 10; Times: 1000;
  • Batch size: 100; Times: 100;
  • Batch size: 1000; Times: 10;
  • Batch size: 10000; Times: 1.

The results were the following:

a) Batch size: 1; Times: 10000

min 0.037017 s
max 0.571604 s
average 0.047213 s
total 417.3 s

As we can see on the chart, we have a slight variance between the inserts. Although the maximum chart value was 0.57 seconds, the average (0.047s) was much more close to the minimum value (0.037s). Also, we can see that the time needed to a insert does not changes significantly while the table increases.

b) Batch size: 10; Times: 1000

min 0.051545 s
max 1.592167 s
average 0.077328 s
total 77.3 s

This case shown us that, increasing the batch size to 10 we need, on average, about 1.64x more time to execute this batch. So, we can imagine that is much better to execute a big batch than lot of small batches. The test shown that to insert 10000 registries with batch size of 10 we needed 77.3 s, while with batch size of 1, to insert 10000 registries we needed 417.3 s.

c) Batch size: 100; Times: 100

min 0.221817 s
max 0.733436 s
average 0.276504 s
total 27.7 s

This case shown that increasing again the batch size, now to 100, we needed about 3.6x more time per batch than we needed with batch size of 10. So, we can deduce that the time per batch does not increases linearly as the batch size increases. But again, the total time to execute 10000 inserts was lower (27 s against 77 s).

d) Batch size: 1000; Times: 10

min 2.341496 s
max 2.895445 s
average 2.522845 s
total 25.2 s

Again, the same happened. As we increases the batch size to 1000 we needed 9.1x more time than we needed with batch size of 100. The total time was better than the previous, but is almost the same (25 s against 27 s).

e) Batch size: 10000; Times: 1 (10 repetitions with empty database)

min 19.171194 s
max 24.020913 s
average 22.2 s

This time, increasing the batch size to 10000 we needed 8x more time than we needed with batch size of 1000, while we could imagine we would need more than 9.1. So, we needed only 22 s to execute 10000 inserts.

Conclusion

This tests resulted on the following table:

Test Average Time per Batch Total Time
a t1 or 0.047213 s t2 or 417.3 s
b 1.83 x t1 or 0.077328 s t2/5.40 or 77.3 s
c 5.86 x t1 or 0.276504 s t2/0.066 or 27.7 s
d 53.68 x t1 or 2.523 s t2/0.060 or 25.2 s
e 470.34 x t1 or 22.2 s t2/0.053 or 22.2 s

As we can see, for simple inserts (without joins) as we increases the batch size, the time needed to to execute that batch is greater, but, the total time is lower. So, with Core Data, when possible we should save data to database using batches.

2. Inserts with join tables

This test shows how the time to execute a insert increases as the number of join tables (in each insert) and number of rows increases. The number of joins varies from 0 to 3.

a) Joins quantity: 0

min 0.053622 s
max 0.626013 s
average 0.068631 s
total 137.3 s

This test has no joins, so the results is the same from the previous test.

b) Joins quantity: 1

min 0.617910 s
max 0.353416 s
average 0.080156 s
total 160.3 s

As might be expected, with 1 join the average time to a insert was 1.17 times greater than with 0 joins.

c) Joins quantity: 2

min 0.078214 s
max 0.559592 s
average 0.109143 s
total 218.3 s

With 2 joins we needed even more time to process an insert: 1.37 times more than with 1 join. Also, we can see that it seems that, as the database increases, we need more time to do inserts that was join tables.

d) Joins quantity: 3

min 0.093524 s
max 0.650233 s
average 0.135843 s
total 271.7 s

With 3 joins the average time was worst again: 1.244 times more than with 2 joins.

Conclusion

The following table results from the tests:

Test Average Time Total Time
a t1 or 0.068631 s t2 or 137.3 s
b 1.17 x t1 or 0.080156 s 1.17 x t2 or 160.3 s
c 1.59 x t1 or 0.109143 s 1.59 x t2 or 218.3 s
d 1.99 x t1 or 0.135843 s 1.99 x t2 or 271.7 s

As we can see, as the number of joins increases in a insert the time required to process it also increases. This increasing number is not linear.

The next post will present our results and conclusions for selects on Core Data, stay tuned!

This post is also available in Portuguese: Testes de performance do Core Data sobre SQLite – Parte 2

permalink
, ,

Testes de performance do Core Data sobre SQLite – Parte 1


Go Tech
Edmar Miyake
13julho

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.

Core Data Architecture

  • 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

Data Model

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:

  1. 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.
  2. 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.
  3. 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.
  4. 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

permalink
, ,