Ir para conteúdo
Visualizar no app

Uma forma melhor de navegar. Saiba mais.

MM Fórum

Um app em tela cheia na sua Tela de Início com notificações push, avisos e mais.

Para instalar este app no iOS/iPadOS
  1. Toque no ícone de Compartilhamento no Safari
  2. Role o menu e toque em Adicionar à Tela de Início.
  3. Toque em Adicionar no canto superior direito.
Para instalar este app no Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

SearchBar e banco de dados

Featured Replies

Postado

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?

  • Respostas 14
  • Visualizações 1.6k
  • Criado
  • Última resposta

Top Postadores Neste Tópico

Postado

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]

Postado
  • Autor

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á.

Postado

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.

Postado

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.

Postado

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]

Postado

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.

Postado
  • Autor

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é

Postado

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)

Postado

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

Postado
  • Autor

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?

Postado

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.

Postado

Quando tu vai trabalhar com banco de dados, tu tem que analisar se suas consultas são eficientes.

Já chegou a testar para ver quanto tempo estão levando suas consultas individualmente?

Postado
  • Autor

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.

Postado

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.

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…

Quem Está Navegando 0

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

Conta

Navegação

Buscar

Buscar

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.