Performance com UITableView

26thJul 10

A saga no desenvolvimento da minha próxima App continua, e como já tem sido hábito tenho perdido muito tempo com coisas que não pensei serem tão complexas.

Na passada sexta-feira consegui implementar com sucesso algumas UITableViews com os dados recebidos por XML. Contente com o resultado, passei a testar o desenvolvimento tanto no Simulador com no iPhone real, e a performance estava excelente. Scroll rápido, tanto para cima como para baixo.

No entanto a alegria não durou muito… a performance era rápida, porque ainda não tinha tentado incluir uma imagem em cada célula. Só com texto o iPhone digeria grandes quantidades sem problemas, mas com a imagem as coisas modificavam-se e a performance no scroll passava de excelente a miserável.

Como já parece costume, acabei por passar um fim-de-semana inteiro a perder tempo com esta situação tendo implementado várias abordagens ao problema:

1ª Abordagem – Imagem na UITableViewCell

Aproveitando o método que o Xcode cria por defeito para as UITableView, criei a minha célula personalizada com recurso a Views e SubViews. Rapidamente percebi o problema desta implementação.

Como tudo o que estiver neste método corre na Thread principal da aplicação, corre-se o risco de “bloquear” a UI e tornar toda a experiência de utilização da App um autêntico desastre.

No primeiro teste usei só texto, e tudo corria bem para uma quantidade de dados aceitáveis… com uma dose “massiva” de dados já se notava alguma perca de performance, mas nada de muito perceptível. Mas, assim que decidi implementar a imagem, com:

UIImage *myImg = [UIImage imageWithData: [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.foo.com/myIMG.jpg]

Notei imediatamente que assim não ia lá, porque desta forma cada vez que a célula tinha de ser criada ou “reutilizada” durante o scroll a imagem estava sempre a ser criada… e para piorar a situação, faz isto na Thread principal bloqueando por completo a UI.

Ok, era tempo de pensar noutra solução.

2ª Abordagem – Recolher as imagens de forma Assíncrona

Mantendo toda a estrutura que tinha, pensei que a solução ideal era fazer o download e criação da imagem em threads separadas de forma assíncrona. Em muito me ajudou este tutorial do Markj, que aborda o problema exactamente como eu tinha pensado: http://www.markj.net/iphone-asynchronous-table-image/

Após implementação, altura dos testes…. e funciona.  Mas não como eu pretendo.

Com esta abordagem todas as imagens são “recolhidas” em 2º plano, o que faz com que a tabela e a interface não bloqueie e não fica lenta, mas tem um problema. Quando a célula sobe/desce e sai da view, e volta a aparecer volta a ser pedido de forma assíncrona a criação da dita imagem. O que não é bem aquilo que pretendo.

Voltar a puxar pelos neurónios e Googlar por ajuda.

3ª Abordagem – Solução à lá Tweetie

Há uns tempos atrás quando começaram a aparecer os clientes para Twitter no iPhone, a grande maioria deles tinha problemas com a performance no scroll. Até que apareceu um que tinha como grande vantagem a rapidez de navegação… o Tweetie. O Loren Brichter criou uma solução engenhosa para tornar a UI muito mais rápida. Em vez de encher cada célula com Views e SubViews, ele utiliza toda a informação que cada célula deve conter e cria uma “imagem” para cada célula. A questão das imagens, aparentemente resolveu de outra forma… reutiliza cada imagem que já tenha sido utilizada.

Esta solução rapidamente deu nas vistas, e praticamente todos os clientes de Twitter existentes bem como outras App’s passaram a utilizar a mesma solução ou variantes desta solução.

O Loren tem uma entrada no seu blog onde partilha a ideia base de como fazer isto: http://blog.atebits.com/2008/12/fast-scrolling-in-tweetie-with-uitableview/

O meu grande azar é que o exemplo apenas indica como fazer com texto, e tenho tido grandes problemas em adaptar e incluir a imagem pretendida. Ou seja funciona, mas não funciona bem…

Resumo e Conclusão

Passou o fim-de-semana e não consegui chegar a uma solução ideal. Hoje irei voltar à carga, e irei tentar optar por mais 2 soluções: criar um sistema de cache de imagens ou começar a implementar o projecto com recurso à biblioteca Three20.

Update: numa primeira leitura parece que a biblioteca Three20 não trabalha com o Interface Builder directamente, e a personalização não é tão simples. A utilização desta biblioteca neste projecto fica para último recurso.

Se alguém tiver alguma solução de como resolver este problema de forma simples e eficaz, gostava mesmo de alguma ajuda…

Esta entrada foi publicada em iOS Dev e com as tags , , , , . Guardar nos favoritos o link permanente. Publicar comentário ou deixar um trackback: URL de Trackback.

Publicar Comentário

O seu endereço de e-mail nunca será publicado ou partilhado. Campos obrigatórios marcados com *

*
*

Pode usar as seguintes tags e atributos de HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">