[Objective-C] – Human readable date diff

Sometimes you have to express date differences in a human readable way: “2 hours ago”, “yesterday”, etc. How to do this in Objective-C?

Here’s a nice solution

    - (NSString *) dateToName:(NSDate*)dt withSec:(BOOL)sec {
 
        NSLocale *locale = [NSLocale currentLocale];
        NSTimeInterval tI = [[NSDate date] timeIntervalSinceDate:dt];
        if (tI < 60) {
          if (sec == NO) {
               return NSLocalizedString(@"just now", @"");
           }
           return [NSString stringWithFormat:
                     NSLocalizedString(@"%d seconds ago", @""),(int)tI];
         }
         if (tI < 3600) {
           return [NSString stringWithFormat:
                     NSLocalizedString(@"%d minutes ago", @""),(int)(tI/60)];
         }
         if (tI < 86400) {
          return [NSString stringWithFormat:
                     NSLocalizedString(@"%d hours ago", @""),(int)tI/3600];
         }
 
         NSDateFormatter *relativeDateFormatter = [[NSDateFormatter alloc] init];
         [relativeDateFormatter setTimeStyle:NSDateFormatterNoStyle];
         [relativeDateFormatter setDateStyle:NSDateFormatterMediumStyle];
         [relativeDateFormatter setDoesRelativeDateFormatting:YES];
         [relativeDateFormatter setLocale:locale];
 
         NSString * relativeFormattedString = 
                [relativeDateFormatter stringForObjectValue:dt];
         return relativeFormattedString;
    }

Atualizando a Interface Gráfica durante um processo demorado no iOS

Já faz algum tempo que não colocamos uma dica de Objective-C aqui no Zeletron. Deixo abaixo uma dica legal.

Indicar que um processo demorado está sendo executado e que o aplicativo não está travado é uma das indicações do HIG (Human Interface Guidelines) do iOS. Para isso existem indicadores de atividade e barras de progresso, que indicam ao usuário que o programa está em execução ou o quanto falta para terminar a tarefa (no caso do ProgressView).

Activity Indicator
Activity Indicator
Progress View
Progress View

O problema é que qualquer alteração na interface gráfica precisa ser feita na Thread principal do programa e, se o processo demorado está rodando na thread principal, você vai ter problemas para atualizar um ProgressView ou mostrar um ActivityIndicator.

A dica é simples, você separa o código demorado numa thread em background e, sempre que precisar atualizar a interface gráfica, manda o programa fazer isso na thread principal. Assim, ó:

//Evento de um botão de "salvar"
- (IBAction)eventoBotaoSalvar:(id)sender {
    //Manda salvar numa thread em background
    [NSThread detachNewThreadSelector:@selector(salvaUmMonteDeCoisas) 
                             toTarget:self 
                           withObject:nil];
}
 
//--------------------------------------------------
//Dois métodos simples que atualizam a interface gráfica
//--------------------------------------------------
//Mostra o Activity Indicator
- (void)mostraActivityIndicator{
    self.meuActivityIndicator.hidden = NO;
}
 
//Esconde o Activity Indicator
- (void)escondeActivityIndicator{
    self.meuActivityIndicator.hidden = YES;
}
//--------------------------------------------------
 
//Salva a tralha toda
- (void)salvaUmMonteDeCoisas{
    //Mostra o ActivityIndicator antes de começar
    [self performSelectorOnMainThread:@selector(mostraActivityIndicator) 
                           withObject:nil 
                        waitUntilDone:NO];
 
    //Salva tudo (pode demorar à vontade)
    for (NSDictionary *d in meuArrayDeDicionarios){
        [self salvaDicionario:d];
    }
 
    //Depois de terminar tira o ActivityIndicator
    [self performSelectorOnMainThread:@selector(escondeActivityIndicator) 
                           withObject:nil 
                        waitUntilDone:NO];
}

Dessa forma, o programa não fica travado enquanto você está salvando aquele monte de dados. Você pode, inclusive, criar o ActivityIndicator na status bar do aparelho e deixar o usuário fazer outras coisas enquanto o App está salvando.

O código acima é só um exemplo de como podemos usar o detachNewThreadSelector e o performSelectorOnMainThread. Você pode encontrar, eventualmente, erros de sintaxe nele, mas a ideia é essa: Manda executar uma tarefa demorada em background e, sempre que precisar, atualiza a interface na thread principal.

IPhone BrainView – Neuroanatomia para Dummies

Apesar de escrever sobre tecnologia, há quase dois anos me tornei doutor em medicina e a área com que trabalho (quer dizer, com que trabalho nas horas vagas) é neurociências.

Bom, toda esta introdução para falar do programa que fiz para o iPhone que considero meu melhor programa até agora. Trata-se de um atlas de neuroanatomia que tira todo potencial do pequeno smartphone da Apple. Como queria que fosse uma ferramenta de uso acadêmico ele é totalmente grátis e sem anúncios.

A idéia foi incluir junto um pequeno tutorial de um programa de medição de áreas do cérebro para que a pessoa interessada já tenha um V0.

Algumas imagens da app: http://itunes.apple.com/br/app/isurf-brainview/id381072423?mt=8

Genius revisitado e uma meditação sobre Objective-C

Mais um aplicativo que publicamos na AppStore chamado SigaCor que é uma versão moderna do Genius. É o primeiro Genius completo e grátis da AppStore (AFAIK). Vale a pena baixar: http://itunes.apple.com/br/app/sigacor/id377891433?mt=8

Este aplicativo foi desenvolvido totalmente na linguagem Objective-C o que me leva a fazer uma pequena meditação sobre o assunto.

O que você espera de uma linguagem que se chama Objective-C: que seja parecida com C. É a resposta mais obvia. Acontece que, como diria o capitão Nascimento, não é assim que a banda toca em Cupertino, sede da Apple. Portanto o nome Objective-C acho que é um dos maiores desastres de marketing para programador.

Você abre o exemplo pensando encontrar isto:

1
2
3
void MudaCor (char * colorname) {
        cordefundo = GetColor(colorname);
}

e se depara com:

1
2
3
- MudaCor (NSString * colorname) {
   [myColor changeColorToName:colorname];
}

Isto e outras mudanças sintáticas importantes causam uma frustação no programador que foge e tenta outro caminho para desenvolver para o IPhone.

O problema é que se a linguagem se chamasse Objective-Apple e você não esperasse uma sintaxe como C provavelmente você não fugiria dela e rapidamente estaria usando um framework muito amigável.

Fizemos 13 aplicações com o Phonegap e esta é a primeira com Objective-C. Posso dizer que uma vez vencida a barreira do medo ao Objective-C você acaba gostando dele.