Ir para conteúdo
  • Cadastre-se

SearchBar e banco de dados


Posts Recomendados

Boa tarde pessoal,

nesta minha tela tenho uma TableView com uma barra de pesquisa e esta pesquisa é feita no banco de dados, pois utilizo várias outras condições, inner joins, likes e etc. Acontecia inicialmente que havia um delay enorme no teclado, eu tocava alguma letra e ela demorava aparecer no campo de pesquisa. Ok, isto consegui resolver pesquisando e utilizando o NSOperation para realizar em outra thread.

Porém, agora o problema é outro: se eu digitar rápido, por exemplo "planalto", há um delay nos resultados, porque eles continuam aparecendo letra por letra, mesmo eu tendo terminado de digitar, ai eu tenho que esperar esse tempo para que realmente exiba a busca pela palavra completa.

Existe alguma alternativa para isso?

Link para o comentário
Compartilhar em outros sites

  • Respostas 14
  • Criado
  • Última resposta

Top Postadores Neste Tópico

Dias Populares

Top Postadores Neste Tópico

Talvez o algorítmo que você escreveu para realizar a busca esteja um pouco pesada (diria MUITO pesado até). Veja se você não consegue realizar algumas etapas do processo de busca no Main Thread, para dividir melhor as funcões entre os Threads.


[self performSelectorOnMainThread: WithObject: WaitUntilDone:];
[/CODE]

Link para o comentário
Compartilhar em outros sites

Bom, vou colocar aqui alguns trechos de como estou fazendo baseado em algo que encontrei no stackoverflow, pois assim você poderá me exemplificar o que exatamente seria dividir estas funções.

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
self.queue = [[NSOperationQueue new] autorelease];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(buscaLike:) object:searchText];
[self.queue addOperation:operation]
[operation release];
}[/CODE]

E aqui o método que realiza a busca e preenche a variável [b]displayItems[/b], que utilizo para exibir os itens da tabela:

[CODE]- (void)buscaLike:(NSString *)_string {
[self.displayItems removeAllObjects];

Usuarios *usr = [[[Usuarios alloc] init] autorelease];
self.displayItems = [[[NSMutableArray alloc] initWithArray:[usr getUsuariosLike:_string]] autorelease];

[self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];
}[/CODE]

Obrigado pela ajuda desde já.

Link para o comentário
Compartilhar em outros sites

Eu não vou olhar seu código pois não sei praticamente nada de Objective-C, nem de programação no iOS.

Mas imagino que tarefas pesadas não devem ser feitas na thread principal(pois ela provavelmente deve ser encarregada de manter a interface do usuário fluida).... daí o motivo de tudo ficar travado.

E que por ser uma tarefa pesada, que tu vai chamar "a cada letra digitada"... imagino que tu queira colocar um delay(atraso) na chamada dessa tarefa...

Ou seja, penso em um algoritmo mais ou menos assim:


//toda vez que o campo de busca é alterado
salva timestamp da ultima alteração no campo
se houver alguma busca em andamento(ocorrendo em outra thread)
--cancelar busca
se houver alguma busca em esperando para rodar
--retornar sem fazer nada
caso contrário
--agendar uma busca para rodar daqui a: 500ms


//thread que faz a busca
se a última digitação no campo foi antes de 500ms atrás(faz mais tempo que 500ms)
--iniciar busca
--atualizar campos
--retornar
caso contrário (significa que o usuário digitou alguma coisa agora a pouco, e quero esperar para ver se ele digita mais)
--agendar novamente a busca daqui em: 500ms -timestampAtual +timestampUltimaAlteracaoNoCampo (resulta no delay apropriado, em ms, para rodar novamente)

//não use sleep-loop para "rodar novamente depois", o sistema deve ter alguma API que permite agendar uma thread para rodar mais tarde.
[/CODE]

Estou assumindo que 500ms é um tempo legal de espera após parar de digitar, para iniciar uma busca pesada.

Link para o comentário
Compartilhar em outros sites

Então, cada vez que o texto muda na search bar, você cria um processo (thread) diferente. É por isso que acontece esse delay nos resultados, porque outros processos independentes estão sendo realizados. Você tem muitos itens a serem mostrados na TableView? Porque esse código não me parece nada pesado.

Tem outra dica também: atualize seu projeto para usar o ARC. Com isso seu programa gerenciará a própria memória e você não precisará (nem poderá) usar release e autorelease.

Link para o comentário
Compartilhar em outros sites

Eu não vou olhar seu código pois não sei praticamente nada de Objective-C, nem de programação no iOS.

Mas imagino que tarefas pesadas não devem ser feitas na thread principal(pois ela provavelmente deve ser encarregada de manter a interface do usuário fluida).... daí o motivo de tudo ficar travado.

E que por ser uma tarefa pesada, que tu vai chamar "a cada letra digitada"... imagino que tu queira colocar um delay(atraso) na chamada dessa tarefa...

Ou seja, penso em um algoritmo mais ou menos assim:


//toda vez que o campo de busca é alterado
salva timestamp da ultima alteração no campo
se houver alguma busca em andamento(ocorrendo em outra thread)
--cancelar busca
se houver alguma busca em esperando para rodar
--retornar sem fazer nada
caso contrário
--coloca uma busca nova em espera


//thread que faz a busca
se a última digitação no campo faz mais de 500ms
--iniciar busca
--atualizar campos
--retornar
rodar novamente depois (calcular milisegundos que faltam para fechar 500ms da ultima digitação)

//não use sleep-loop para "rodar novamente depois", o sistema deve ter alguma API que permite agendar uma thread.
[/CODE]

Ou nem precisa de timestamp, cria um BOOL chamado [i]searching. [/i] Enquanto uma busca estiver sendo realizada, [i]searching = YES.[/i] Quando terminar essa busca, [i]searching = NO.[/i]

Link para o comentário
Compartilhar em outros sites

Ou nem precisa de timestamp, cria um BOOL chamado searching. Enquanto uma busca estiver sendo realizada, searching = YES. Quando terminar essa busca, searching = NO.

A idéia do timestamp é atrasar o início da busca. Afinal, se é um processo pesado, e há uma grande chance do usuário mudar os parâmetros em curto espaço de tempo(ou seja, antes que a busca acabe) é muito cômodo esperar algum tempo para ter certeza do que vai fazer.

Além de ser algo rápido, pois não passa de um long onde tu faz comparações matemáticas... ajuda muito na tomada de decisão do programa.

Não sei como é no iOS, mas normalmente tu pode perguntar diretamente para thread se ela está funcionando, e pedir para ela parar "amigavelmente"(eu programo, principalmente, em Java). Não sendo necessário o bool.

Link para o comentário
Compartilhar em outros sites

Gabriel Couto, vou ver se consigo desenvolver algum algoritimo neste sentido, pois também faz pouco mais de duas semanas que iniciei com Objective-C e iOS, ainda tenho muito que aprender.

Gabriel Vicent, esta minha tabela possui 320 registros, então este seria o máximo de itens a serem exibidos. Sobre usar ARC, vou tentar novamente, pois estou usando o FMDB, que na minha primeira tentativa utilizando esta biblioteca com ARC, parece que não eram compatíveis ou algo parecido por causa da biblioteca estar no formato antigo, não sei, foi logo nos primeiros dias, agora com um pouco mais de experiência tentarei novamente.

Obrigado!

Editado por Paulo André
Link para o comentário
Compartilhar em outros sites

Gabriel Couto, vou ver se consigo desenvolver algum algoritimo neste sentido, pois também faz pouco mais de duas semanas que iniciei com Objective-C e iOS, ainda tenho muito que aprender.

Gabriel Vicent, esta minha tabela possui 320 registros, então este seria o máximo de itens a serem exibidos. Sobre usar ARC, vou tentar novamente, pois estou usando o FMDB, que na minha primeira tentativa utilizando esta biblioteca com ARC, parece que não eram compatíveis ou algo parecido por causa da biblioteca estar no formato antigo, não sei, foi logo nos primeiros dias, agora com um pouco mais de experiência tentarei novamente.

Obrigado!

320 registros é pouco, provavelmente tu não precisa do atraso.

Tu pode pegar o algoritmo que forneci e utilizar ele para uma busca normal, removendo as verificações de timestamp(e transformar o agendamento, em algo instantâneo)

Link para o comentário
Compartilhar em outros sites

Gabriel Couto, vou ver se consigo desenvolver algum algoritimo neste sentido, pois também faz pouco mais de duas semanas que iniciei com Objective-C e iOS, ainda tenho muito que aprender.

Gabriel Vicent, esta minha tabela possui 320 registros, então este seria o máximo de itens a serem exibidos. Sobre usar ARC, vou tentar novamente, pois estou usando o FMDB, que na minha primeira tentativa utilizando esta biblioteca com ARC, parece que não eram compatíveis ou algo parecido por causa da biblioteca estar no formato antigo, não sei, foi logo nos primeiros dias, agora com um pouco mais de experiência tentarei novamente.

Obrigado!

320 itens não são suficientes para fazer o programa pesar... Faço buscas em tabelas com bem mais itens e não vejo nem sinal de delay em nada. Mas eu faço de forma diferente. Eu faço um for que pesquisa item a item dentro de uma array e salva em uma segunda array tudo que bater com a busca.

Editado por Gabriel Vincent
Link para o comentário
Compartilhar em outros sites

Pois então, deixa eu contextualizar tudo: nesta minha barra de pesquisa eu tenho também uma scope bar com dois itens, o primeiro item para realizar a busca desta forma que você citou mesmo, pois os itens que pesquiso estão neste array que é exibido na TableView, por exemplo, o número no title e o nome no detail da célula. Mas, no outro item de escopo desta busca, eu preciso buscar por outros campos além destes do array, em outra tabela relacionada, que me fez criar uma query com inner joins.

Acha que é viável então eu criar este array já com todos os outros campos, os que exibo na TableView e os que vou precisar para a busca no segundo escopo? Desta forma fazendo a busca com o for que você disse?

Link para o comentário
Compartilhar em outros sites

Pois então, deixa eu contextualizar tudo: nesta minha barra de pesquisa eu tenho também uma scope bar com dois itens, o primeiro item para realizar a busca desta forma que você citou mesmo, pois os itens que pesquiso estão neste array que é exibido na TableView, por exemplo, o número no title e o nome no detail da célula. Mas, no outro item de escopo desta busca, eu preciso buscar por outros campos além destes do array, em outra tabela relacionada, que me fez criar uma query com inner joins.

Acha que é viável então eu criar este array já com todos os outros campos, os que exibo na TableView e os que vou precisar para a busca no segundo escopo? Desta forma fazendo a busca com o for que você disse?

Acho que vale a pena testar sim. Se não está funcionando muito bem do jeito que está, é bom tentar outra coisa.

Link para o comentário
Compartilhar em outros sites

Gabriel Couto, acredito que seja rápida sim, pois ao tocar em uma célula desta tabela, eu tenho praticamente a mesma query, com as tabelas relacionadas e é instantâneo o resultado.

Gabriel Vicent, a relação destas tabelas é 1:n, então a minha própria ideia de colocar inicialmente tudo em um array acho que seria um pouco mais complexa, acho que teria que ser um array multidimencional, certo? O próprio NSArray faz isso? Como ficaria o for?

Para que vocês entendam, acho que um bom exemplo é como se fosse uma relação estados -> cidades, onde na TableView eu tenho os estados e é possível também fazer uma busca por nomes de cidades e o resultado da TableView são os estados que contém aquele nome de cidade pesquisada.

Link para o comentário
Compartilhar em outros sites

Gabriel Couto, acredito que seja rápida sim, pois ao tocar em uma célula desta tabela, eu tenho praticamente a mesma query, com as tabelas relacionadas e é instantâneo o resultado.

Gabriel Vicent, a relação destas tabelas é 1:n, então a minha própria ideia de colocar inicialmente tudo em um array acho que seria um pouco mais complexa, acho que teria que ser um array multidimencional, certo? O próprio NSArray faz isso? Como ficaria o for?

Para que vocês entendam, acho que um bom exemplo é como se fosse uma relação estados -> cidades, onde na TableView eu tenho os estados e é possível também fazer uma busca por nomes de cidades e o resultado da TableView são os estados que contém aquele nome de cidade pesquisada.

Uma array multidimensional seria como uma matriz, certo? Não tenho idéia de como se faz isso em Objective-C.

Link para o comentário
Compartilhar em outros sites

Participe do debate

Você pode postar agora e se registrar depois. Se você tem uma conta, entre agora para postar com ela.

Visitante
Responder este tópico…

×   Você colou conteúdo com formatação.   Remover formatação

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Limpar editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Quem Está Navegando   0 membros estão online

    • Nenhum usuário registrado visualizando esta página.



  • Estatísticas do Fórum

    • Total de Tópicos
      56.5k
    • Total de Posts
      466.2k
×
×
  • Criar Novo...