Introdução
Muitas pessoas gostariam de estar programando para Apple hoje em dia, mas algumas tem preguiça de aprender uma nova linguagem como Objective-C, outras simplesmente não conseguem, e por ai vai. Sei que pode ser difícil no começo, mas eis um conselho: Nunca desista! Desistir é o caminho mais fácil para o fracasso, e não é isso que você quer.
Porém, para você que ainda está aprendendo Objective-C, mas tem aquele vasto conhecimento na linguagem C#, e já quer sair criando as mais variadas aplicações, eis que vos apresento o MonoMac.
O que é isso?
O MonoMac permite que você crie aplicações no Mac utilizando C# e utilizando a interface nativa do OS X. Ele é parente do MonoTouch, que roda em iPhones, iPods e iPads, com a diferença que ele é Open Source. Ou seja, você não precisa de uma licença para utiliza-lo, e nem publicar seu aplicativo na Mac App Store.
Como usar?
Primeiro de tudo, você precisa de algumas coisas instaladas na sua máquina:
O XCode presumo que você já tenha instalado, então basta instalar o MonoDevelop e o Mono SDK. É necessário ter o XCode instalado pois o MonoMac utiliza o Interface Builder para montar a interface gráfica do programa. Ou seja, o que muda é somente a linguagem, o resto, é praticamente a mesma coisa.
O MonoDevelop é a IDE que iremos utilizar para fazermos nosso primeiro HelloWorld e mostrar alguns conceitos básicos de Cocoa e C#.
O Mono SDK é, como o próprio nome já diz, o SDK do Mono, que contei todas as bibliotecas e runtimes que precisaremos para executar, debugar, e empacotar nosso programa.
Baixe o Mono SDK em http://www.go-mono.com/mono-downloads/download.html e o MonoDevelop em http://monodevelop.com/Download
Instale primeiro o Mono SDK, e logo em seguida o MonoDevelop – Este último basta arrastar para o seu diretório de Aplicativos.
Feito isso, basta executar o MonoDevelop, e a primeira tela que você verá é a seguinte:
Feito isso, basta agora clicar em Start New Solution.., na janela que irá aparecer, escolha C# -> MonoMac -> MonoMac Project. Nomeie seu projeto HelloWorld, e clique no botão Forward.
Ignore o GTK# Support, pois estaremos fazendo verdadeiros aplicativos utilizando a interface gráfica Cocoa, e não de terceiros.
Clique em Ok, e o MonoDevelop irá criar o esqueleto do nosso projeto. Note que ele criou o MainMenu.xib e o MainWindow.xib que já são velhos conhecidos nossos.
Os arquivos .designer.cs são arquivos internos que o próprio MonoMac/MonoDevelop irão se encarregar de atualizar, à medida que adicionarmos Outlets/Actions na nossa interface gráfica.
Terminado toda essa parte, dê um clique duplo no MainWindow.xib, este irá abrir o XCode 4. Infelizmente este é um passo necessário para que possamos criar nossa interface gráfica. A não ser que você crie tudo manualmente, porém este não é o intuito deste post, e inclusive não é muito recomendado pela Apple. O Interface Builder está ai para isso, e precisamos utiliza-lo.
Ao abrir o XCode 4, ele automaticamente irá adicionar alguns arquivos .h e .c no solution. Isso é normal, e não precisa se preocupar com ele. Na verdade, iremos até utilizar esses arquivos, para manter a sincronização entre a nossa interface gráfica, e o MonoDevelop.
Adicione um NSLabel e um NSButton na nossa janela, e acerte para que ela fique como mostrado na tela abaixo:
Vocês devem estar se perguntando: E como vou agora codificar no C# se não tem nada ligando uma coisa a outra. E mesmo se ele ler o arquivo .xib, como ele vai fazer todas as alterações sem bagunçar o código? Simples: Toda vez que você adiciona um IBOutlet no arquivo .c que o XCode 4 criou, o MonoDevelop atualiza o código C#. Aparentemente parece ser algo sujo de se fazer, mas não irá interferir em nada no resultado final. Esse é um passo necessário uma vez que o novo XCode vem com tudo embutido, então façamos o seguinte:
Clique no botão Show the Assistance Editor
para que possamos dividir a tela em duas. Note que quando você selecionar o MainWindow.xib, na tela da direita irá aparecer o MainWindow.h, e é ai que a mágica funciona.
Primeiro aperte a tecla control no seu Mac, clique no NSButton e arraste ele para o MainWindow.h como mostrado na figura abaixo.
Um popup irá aparecer. Na opção Connection, selecione Action. Em Type, selecione Button, e em Name, selecione Clicked. Faça o mesmo para o nosso NSLabel, porém em Connection selecione Outlet ao invés de Action.
Feito isso, salve tudo, feche o XCode e voltemos para o MonoDevelop. Neste momento, o MonoDevelop já deve ter sincronizado tudo. Abra o arquivo MainWindowController.cs e adicione o código abaixo:
partial void Clicked (MonoMac.AppKit.NSButton sender) { label.StringValue = "Hello World!"; }
O partial aqui é necessário, pois ele já está implementado de maneira partial em outra parte do código, a qual não precisamos nos preocupar. o label aqui, é o nome que demos ao nosso NSLabel quando adicionamos o Outlet no XCode.
E pronto, agora basta executar em Run -> Run, clicar no botão, e voilá, nosso primeiro Hello World em MonoMac!
E não para por ai. Uma das vantagens de se utilizar o MonoMac, é que você tem todas as facilidades do .Net:
- Banco de dados: SQLite, PostgreSQL, MySQL mais fácil e rápido de programar.
- WebServices mais fáceis de programar.
- XML nativo.
- Todas as suas bibliotecas em .Net estarão disponíveis no seu aplicativo sem precisar reescrever praticamente nada (talvez uma alteração aqui e ali para rodar no mac).
E muito mais. Espero que tenham gostado, e não se esqueçam de nos seguir no twitter @dev_br e até a próxima!
Introdução
Dando continuação ao desenvolvimento do nosso aplicativo TodoList, hoje mostraremos como mostrar informações na Dock do mac.
Não seria interessante que quando executássemos nosso TodoList, ele mostrasse o número de Tasks que ainda não completamos?
O código para mostar uma mensagem no Dock do mac é bastante simples, o nosso problema é como atualizá-lo quando alterarmos uma task. E como sabemos quantas Tasks estão completas e quantas estão incompletas? Por isso que precisávamos ter uma base sobre NSNotificationCenter, NSPredicate e NSFetchRequest primeiro, antes de chegarmos até aqui.
Com o NSNotificationCenter, nosso aplicativo é notificado quando alterarmos alguma task, e com o NSPredicate/NSFetchRequest fazemos nosso “SELECT * FROM Tasks WHERE status = incompleto” e retornamos a quantidade.
Sem mais delongas…
O código
Inicialmente, quando inicalizarmos o nosso aplicativo, precisamos iniciar o NSNotificationCenter e dizer para ficar de olho em qualquer notificação que nos interesse, e por acaso, queremos saber quando o nosso NSManagedObjectContext dispara a notificação NSManagedObjectContextObjectsDidChangeNotification o que signfica que foi adicionado, removido ou alterado alguma informação no nosso Core Data.
Existem outros tipos de notificação, mas para o nosso caso, utilizaremos apenas essa. E como precisamos usar quando o nosso aplicativo for inicializado, que lugar melhor do que o nosso applicationDidFinishLaunching no arquivo?
TodoListAppDelegate.m:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notification:) name:NSManagedObjectContextObjectsDidChangeNotification object:[self managedObjectContext]]; }
Aqui pegamos o NSNotificationCenter padrão (defaultCenter) e adicionamos um observer (nosso TodoListAppDelegate) e quando o NSManagedObjectContext for alterado, ele enviará um NSManagedOBjectContextObjectsDidChangeNotification, que fará com que o NSNotificationCenter chame o método notification: na nossa classe.
Até aqui tudo bem, agora o que poderia ter neste método notification: ?
É aqui que a mágica toda acontece. Primeiramente fazemos nosso “SELECT” criando um NSPredicate e um NSFetchRequest, retornamos um array, pegamos o count deste array, instanciamos um NSDocTile e setamos o label dele:
- (void) notification:(NSNotification *)notification { NSPredicate *predicate = [NSPredicate predicateWithFormat:@"isCompleted != YES"]; NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"TodoList"]; [request setPredicate:predicate]; NSArray *newArray = [[self managedObjectContext] executeFetchRequest:request error:nil]; NSDockTile *docTitle = [NSApp dockTile]; [docTitle setBadgeLabel:[NSString stringWithFormat:@"%u", newArray.count]]; }
E pronto! Rode seu aplicativo, veja que quando adicionamos, removemos, ou alteramos alguma task, o balãozinho no nosso dock vai alterando:
E Por hoje é só! Sei que já falei isso antes, mas voltaremos com mais posts com maior frequência, e não se esqueçam de nos seguir no twitter @dev_br.
Introdução
Já parou para se imaginar, como fazemos a busca na nossa TodoList? Inicialmente só usamos o NSSearchField, e setamos no seu Bindings, a propriedade Predicate Format para text contains $value, e toda vez que digitamos alguma coisa no nosso NSSearchField, automaticamente ele retorna todas as Tasks que contém o texto.
Tudo isso é muto bom, e muito fácil, e o Cocoa ajuda bastante nisso. Mas como fazer isso programaticamente? Nem sempre poderemos contar com as facilidades do KVO/KVC, e é isso que vamos aprender hoje.
NSFetchRequest
O NSFetchRequest é um objeto que irá dizer o que queremos retornar da nossa “busca”. Por exemplo, imagine que na nossa TodoList exista dentro do NSManagedObjectContext diversas Entities, não apenas nossa Entity TodoList. Para fazermos uma busca precisamos dizer o que queremos retornar. No nosso caso, queremos retornar objetos do tipo TodoList.
NSPredicate
O NSPredicate é o nosso “WHERE” do SQL. É o NSPredicate que diz: Retorne todos os TodoList do NSManagedObjectContext ONDE (WHERE) o status é completo.
O NSPredicate também é uma propriedade do NSFetchRequest, ou seja, eles trabalham juntos para retornar o que estamos interessados. Pense no NSFetchRequest como o “SELECT * FROM TodoList” e o NSPredicate como o “WHERE isCompleted = YES”.
Quais “WHERE’s” posso fazer?
Você pode fazer muitas coisas, praticamente tudo que você faria com SQL. Alguns exemplos do que pode ter em um NSPredicate são os seguintes:
- “atributo = valor” – “isCompleted = YES”;
- “atributo contains valor” – “texto contains dev-br”;
- “atributo > %@” – “date > %@”, [NSDate date]; (usando predicateWithFormat).
E o que é retornado?
Normalmente, quando usamos um NSPredicate, o retorno vem em um NSArray com todos os objetos em questão.
Mãos à obra!
Imaginemos que queremos retornar a quantidade de tarefas que estão incompletas, e quem sabe mostrar isso no Dock (não perca o próximo post), como o aplicativo mail que diz quantos emails existem sem ler. Para isso usamos o seguinte código:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"isCompleted = NO"]; NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"TodoList"]; [request setPredicate:predicate]; NSArray *newArray = [[self managedObjectContext] executeFetchRequest:request error:nil];
Dentro de newArray, tem todos os Entities TodoList que estão com o status isCompleted igual a NO. E dai basta usarmos o [newArray count] para sabermos quantos estão incompletos.
E não é somente isso!
Claro que não precisamos parar por ai. O NSPredicate não é utilizado apenas quando usamos Core Data. Podemos ter um NSArray com vários objetos, e fazermos um NSPredicate para filtrar estes dados:
NSArray *arrays = [NSArray arrayWithObjects:@"Dev-br", @"O", @"Melhor", @"blog", @"de", @"programação", nil]; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"self contains 'Dev-br'"]; NSArray *arrayFiltrado = [arrays filteredArrayUsingPredicate:predicate]; NSLog(@"Valores: %@", arrayFiltrado);
O mesmo pode ser feito com dicionários:
NSMutableArray *arrays = [NSMutableArray array]; [arrays addObject:[NSDictionary dictionaryWithObject:@"Objective-C" forKey:@"Linguagem"]]; [arrays addObject:[NSDictionary dictionaryWithObject:@"Java" forKey:@"Linguagem"]]; [arrays addObject:[NSDictionary dictionaryWithObject:@"CSharp" forKey:@"Linguagem"]]; NSPredicate *predicatex = [NSPredicate predicateWithFormat:@"Linguagem = 'Objective-C'"]; NSArray *novoArray = [arrays filteredArrayUsingPredicate:predicatex]; NSLog(@"Valores: %@", novoArray);
E por ai vai…
Conclusão:
Se você tem um projeto pequeno como o nosso TodoList, você não precisa implementar sua camada de persistência no SQLite. Você pode usar o Core Data, e não se preocupar com SELECTS, pois você sempre terá à sua disposição o NSFetchRequest (para ser usado com o Core Data e retornar o tipo de Entity) e o NSPredicate (o nosso WHERE).
Por hoje é só. Fique de olho nas novidades através do twitter @dev_br.
Para completar a famíla, eis o primo distante do KVO e KVC: O NSNotificationCenter.
Imagine a situação:
Você tem uma janela que mostra informações dos clientes. Então, você clica em editar, uma janela popup aparece, e dentro dela você faz algumas alterações, e dentro deste popup tem outro botão para adicionar algum comportamento que irá ser mostrado na janela de informações de clientes, e ao clicar neste botão, outro popup aparece para você fazer a alteração.
Não é o mais belo dos cenários, mas se um dia você precisar de algo parecido, o que você teria que fazer, é passar a janela principal como argumento para o popup, e este passaria a janela principal novamente para o segundo popup, para quando alterasse a informação necessária, a segunda janela popup avisar à janela principal para atualizar os dados.
Com o tempo, você pode acabar fazendo as janelas mais complexas, e terá sempre que se preocupar com os dois popups. Talvez você por algum motivo tenha que alterar a assinatura do método que atualiza os dados, e ai vai ter que fazer o mesmo nas outras janelas, que usam este método. É um trabalho gigantesco de refatoramento, só para atualizar os dados na janela principal.
Neste ponto você tem três opções: retrabalho, retrabalho e retrabalho, ou então desistir de atualizar e deixar seu aplicativo “capenga”, ou usar a terceira opção, que é o NSNotificationCenter.
O que é?
O NSNotificationCenter é nada mais do que uma camada que trabalha entre os eventos do seu aplicativo. Ou seja, com o KVO você tem que saber o objeto que você quer escutar, e avisar a ele que você quer receber informações, então o próprio objeto, envia esta informação para todos os objetos que se registraram. Com o NSNotificationCenter, você avisa ao NSNotificationCenter que você quer receber notificações sobre determinada alteração, para determinado objeto, ou para qualquer objeto. E o NSNotificationCenter faz isso para todo o seu aplicativo, e também para diferentes aplicativos. Imagine que você adiciona um compromisso no iCal, e quer que seu TodoList saiba isso e avise se você tiver alguma tarefa para aquele dia por exemplo. Estamos falando de dois aplicativos que não tem nada a ver um com o outro, e graças ao NSNotificationCenter, podemos fazer isso acontecer.
Tipos
O NSNotificationCenter trabalha de maneira assíncrona, ou seja, recebeu uma notificação, já sai enviando para todo mundo que se registrou, mas ele tem um irmão mais novo que é o NSNotificationQueue, que permite que você escolha quando uma notificação será entregue, se assim que for enviado, se quando terminar um ciclo do loop da aplicação, ou quando a aplicação estiver idle. Mas hoje falaremos apenas do NSNotificationCenter.
Como instanciar?
Para instanciar um NSNotificationCenter, executamos o seguinte código:
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
Isso fará com que retorne um objeto NSNotificationCenter para a sua aplicação, para a thread default (para programas que não precisam de multithreading, é o suficiente).
O que posso fazer?
Basicamente, podemos fazer duas coisas com um NSNotificationCenter:
- Receber notificações.
- Enviar notificações.
[center addObserver:objetoQueQuerSerNotificado selector:@selector(metodoRecebeMensagem:) name:@"TipoDaMensagem" object:objetoQueEnviaMensagem];
Onde objetoQueQuerSerNotificado normalmente é self, metodoRecebeMensagem: é o método que o NSNotificationCenter irá invocar quando receber a mensagem, e esta recebe um objeto do tipo NSNotification como argumento. Name é o identificador da mensagem, normalmente um NSString e objetoQueEnviaMensagem, é o objeto que você quer receber mensagem. Aqui você pode colocar nil e receberá mensagem de todos os objetos que enviem uma notificação com o id contido em name.
Mas o que queremos ver é o NSNotificationCenter em ação correto? Então vamos à obra!
Crie um projeto Command Line Tool no XCode chamado Notificacoes. Se não sabe como fazer isso, veja aqui como faz.
Crie duas classes, uma se chama Recebe, e outra Envia, eis o conteúdo de ambas:
Recebe.h:
#import <Foundation/Foundation.h> @interface Recebe : NSObject - (void) recebeNotificacao:(NSNotification *)notification; @end
Recebe.m:
#import "Recebe.h" @implementation Recebe - (id)init { self = [super init]; if (self) { NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center addObserver:self selector:@selector(recebeNotificacao:) name:@"MinhaNotificacao" object:nil]; } return self; } - (void) recebeNotificacao:(NSNotification *)notification { NSLog(@"Notificação recebida\n"); NSLog(@"Notificação: %@", notification.name); NSLog(@"A mensagem foi: %@", [notification.userInfo objectForKey:@"Mensagem"]); } - (void) dealloc { NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center removeObserver:self]; [super dealloc]; } @end
Repare que no dealloc, removemos o nosso objeto do NSNotificationCenter, e não precisamos dealocar o NSNotificationCenter.
Note também que o userInfo é um NSDictionary, que podemos passar no método que enviará a notificação.
Agora a nossa classe Envia:
Envia.h:
#import <Foundation/Foundation.h> @interface Envia : NSObject - (void) mensagemParaOMundo:(NSString *)mensagem; @end
Envia.m:
#import "Envia.h" @implementation Envia - (void) mensagemParaOMundo:(NSString *)mensagem { NSNotificationCenter *center =[NSNotificationCenter defaultCenter]; NSDictionary *message = [NSDictionary dictionaryWithObject:mensagem forKey:@"Mensagem"]; [center postNotificationName:@"MinhaNotificacao" object:self userInfo:message]; } - (id)init { self = [super init]; if (self) { // Initialization code here. } return self; } @end E finalmente o nosso método main. Aqui iremos instanciar os dois objetos, e enviar uma mensagem com o objeto Envia: <strong>main.m:</strong>
#import <Foundation/Foundation.h> #import "Recebe.h" #import "Envia.h" int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; Recebe *recebe = [[Recebe alloc] init]; Envia *envia = [[Envia alloc] init]; // Enviando a mensagem: [envia mensagemParaOMundo:@"Hello World"]; [pool drain]; return 0; }
E eis o resultado:
Notificacoes[10790:707] Notificação recebida Notificacoes[10790:707] Notificação: MinhaNotificacao Notificacoes[10790:707] A mensagem foi: Hello World
Como pode ser visto, a classe Recebe não sabe nada sobre a classe Envia, e vice-versa. isso faz com que não caiamos no problema inicial de várias janelas que precisam ser atualizadas, e precisar ter uma referência em cada classe para a janela que será atualizada.
Por hoje é só, fiquem ligados que vem muita coisa boa. Sei que estou devagar nos posts, mas tentarei postar com mais frequência. E sigam o @dev_br no twitter.
Completando o KVC, temos o KVO ou Key Value Observer, que serve para nos avisarmos, quando determinado valor de determinado atributo é modificado. Pense nele como o Padrão Observer de design patterns.
Importância
O motivo do KVO ser tão importante, é devido ao fato de ele ser o responsável por avisar à nossa interface gráfica, o que alterou, e com isso, a nossa interface gráfica sabe quando e o que atualizar, como por exemplo quando alteramos o texto de uma task na nossa TodoList. Quando alteramos o texto, alteramos o atributo, e este avisa a todos os que se registraram para receber notificações.
E o mais legal do KVO, é que ele é implementado no próprio NSObject, então, é necessário muito pouco trabalho para implementá-lo.
Como implementa?
O KVO é implementado pelo conjunto de alguns métodos, dentre eles, os mais importantes, são:
- addObserver:forKeyPath:options:context
- removeObserver:forKeyPath
Adicionando Observer
Implementação
#import <Foundation/Foundation.h> @interface Observado : NSObject { @private } @property (retain) NSString *atributoObservado; @end
#import "Observado.h" @implementation Observado @synthesize atributoObservado; - (id)init { self = [super init]; if (self) { // Initialization code here. } return self; } - (void)dealloc { self.atributoObservado = nil; [super dealloc]; } @end
#import @interface Observador : NSObject { @private } @end
#import "Observador.h" @implementation Observador - (id)init { self = [super init]; if (self) { // Initialization code here. } return self; } - (void)dealloc { [super dealloc]; } - (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (context != @"ExemploKVO") { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; return; } NSLog(@"Atributo %@ mudou de %@ para %@ o que faremos agora?", keyPath, [change valueForKey:NSKeyValueChangeOldKey], [change valueForKey:NSKeyValueChangeNewKey]); } @end
#import <Foundation/Foundation.h> #import "Observado.h" #import "Observador.h" int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; Observado *objObservado = [[Observado alloc] init]; Observador *objObservador = [[Observador alloc] init]; [objObservado addObserver:objObservador forKeyPath:@"atributoObservado" options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) context:@"ExemploKVO"]; // Alterando o atributo atributoObservado: objObservado.atributoObservado = @"Novo valor"; // Alterando novamente: objObservado.atributoObservado = @"Outro valor"; [pool drain]; return 0; }
ExemploKVO[23505:903] Atributo atributoObservado mudou de para Novo valor o que faremos agora? ExemploKVO[23505:903] Atributo atributoObservado mudou de Novo valor para Outro valor o que faremos agora?
Existem outras opções que podemos utilizar porém este é o básico para usarmos KVO e KVC, e por hoje é só, e não deixem de seguir o @dev_br no twitter, assim estarão sempre ligados nas novidades.
Introdução
Hoje falaremos sobre KVC, ou Key Value Coding, que é o protocolo que faz a verdadeira “mágica”, que usamos para criar nosso TodoList sem uma linha de código.
KVC é um protocolo que existe em Objective-C, e que está implementado dentro do NSObject, logo, todas as classes possuem, que faz com que possamos acessar gets e sets, sem a necessidade de chamar [classe setAtributo:@"Um atributo"]; ou [classe atributo];
Utilizando o KVC
E como fazemos isso? Por meio dos métodos setValue:forKey e valueForKey:
Lembra da nossa classe Usuario?
Usuario.h:
#import <Foundation/Foundation.h> @interface Usuario : NSObject { NSString *nome; NSString *sobreNome; NSString *email; NSString *endereco; NSString *senha; NSNumber *rendaMensal; } @property (retain) NSString *nome; @property (retain) NSString *sobreNome; @property (retain) NSString *email; @property (retain) NSString *endereco; @property (retain) NSString *senha; @property (retain) NSNumber *rendaMensal; - (id) initWithNome:(NSString *) newNome endereco:(NSString *)newEndereco senha:(NSString *)newSenha; - (void) logarComCredencial:(NSString *)credencial souAdministrador:(BOOL)souAdmin; @end
Usuario.m:
#import "Usuario.h" @implementation Usuario @synthesize nome; @synthesize endereco; @synthesize senha; @synthesize sobreNome; @synthesize email; @synthesize rendaMensal; - (NSString *) nome { NSLog(@"Entrando no get nome"); return nome; } - (void) setNome:(NSString *)newNome { NSLog(@"Entrando no set nome"); [newNome retain]; [nome release]; nome = newNome; } - (id) init { return [self initWithNome:nil endereco:nil senha:nil]; } - (id) initWithNome:(NSString *) newNome endereco:(NSString *)newEndereco senha:(NSString *)newSenha { self = [super init]; if (self) { self.nome = newNome; self.endereco = newEndereco; [self setSenha:newSenha]; } return self; } - (void) logarComCredencial:(NSString *)credencial souAdministrador:(BOOL)souAdmin { if(souAdmin) NSLog(@"Estou logado e sou administrador.\n"); else NSLog(@"Estou logado mas não sou administrador.\n"); } - (void) dealloc { self.nome = nil; self.endereco = nil; self.senha = nil; self.sobreNome = nil; self.email = nil; self.rendaMensal = nil; [super dealloc]; } @end
Fizemos umas modificações nele. No caso, implementamos os métodos get e set do atributo nome, mas foi só para demonstrar o KVC.
Abra o aplicativo AppUsuario que criamos anteriormente, e altere o Usuario.m adicionando o get e o set mostrado acima para nome.
Agora altere o método main.m para que fique igual ao mostrado abaixo:
main.m:
#import <Foundation/Foundation.h> #import "Usuario.h" int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; Usuario *usuario = [[Usuario alloc] initWithNome:@"Nome" endereco:@"Endereco" senha:@"12345"]; usuario.sobreNome = @"Sobrenome"; usuario.email = @"um@email.com"; usuario.rendaMensal = [NSNumber numberWithFloat:1.0]; [usuario setValue:@"Arx Cruz" forKey:@"nome"]; NSString *nome = [usuario valueForKey:@"nome"]; NSLog(@"Nome: %@", nome); [nome release]; [pool drain]; return 0; }
Veja que setamos o nome do usuário, e pegamos o seu valor, utilizando a dupla setValue:forKey e valueForKey:
E esses dois métodos, nada mais fazem do que perguntar ao nosso objeto usuário: Ei, usuario, você tem um atributo nome ai? Se tiver, chama ele.
E para mostrar que o método chamado é realmente o nome e setNome:, abaixo é o resultado que é mostrado do NSLog quando executamos nosso aplicativo:
AppUsuarios[829:903] Entrando no set nome AppUsuarios[829:903] Entrando no set nome AppUsuarios[829:903] Entrando no get nome AppUsuarios[829:903] Nome: Arx Cruz AppUsuarios[829:903] Arx Cruz Sobrenome - Salário de R$ 1
O primeiro set nome é quando instanciamos nosso objeto, dentro do initWithNome, fazemos uma chamada self.nome = newNome, o segundo set, é quando utilizamos o setValue:forKey: e a terceira mensagem com get nome, é quando atribuímos o valor à NSString *nome.
E não para por ai:
Pensou que era tudo? Ledo engano! O KVC também funciona em Collections (falaremos em breve de Collections, não se preocupe!).
Imagine que temos um array de usuários, e queremos mostrar o nome de todos os usuários neste array, como fazemos?
Altere o main.m para que fique como abaixo:
main.m:
#import <Foundation/Foundation.h> #import "Usuario.h" int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; Usuario *usuario = [[Usuario alloc] initWithNome:@"Nome" endereco:@"Endereco" senha:@"12345"]; Usuario *usuario1 = [[Usuario alloc] initWithNome:@"Arx Cruz" endereco:@"Endereco" senha:@"12345"]; Usuario *usuario2 = [[Usuario alloc] initWithNome:@"Joao" endereco:@"Endereco" senha:@"12345"]; NSMutableArray *array = [NSMutableArray array]; [array addObject:usuario]; [array addObject:usuario1]; [array addObject:usuario2]; NSLog(@"Nomes: %@", [array valueForKey:@"nome"]); [array release]; [pool drain]; return 0; }
E o resultado:
AppUsuarios[954:903] Entrando no set nome
AppUsuarios[954:903] Entrando no set nome
AppUsuarios[954:903] Entrando no set nome
AppUsuarios[954:903] Entrando no get nome
AppUsuarios[954:903] Entrando no get nome
AppUsuarios[954:903] Entrando no get nome
AppUsuarios[954:903] Nomes: (
Nome,
"Arx Cruz",
Joao
)
Como podemos notar, as três primeiras mensagens, são do nosso alloc/initWithNome, e as três últimas são da nossa chamada [array valueForKey:@"nome"]
Como pudemos notar, o array faz um loop em todos os seus objetos, e em cada um faz uma chamada [objeto valueForKey:@"nome"], que chama o get para o nosso atributo nome.
E é isso o que o KVC faz por debaixo dos panos, é uma maneira de chamar um get ou set, sem chamar diretamente o método. Você pode até pensar que não existe razão para isso, pra que criar dois métodos para retornar valores, se posso chamar o objeto.atributo e pronto, correto? Mas se não fosse o KVC, você teria que programar bastante na nossa TodoList para criar os Entities, setar os valores, criar um método para quando for adicionar uma nova task, instanciar o objeto da task, setar seus valores, mostrar na NSTableView… enfim, você já viu onde quero chegar. O KVC ajuda e muito na hora de programar, e temos que ter sempre isso em mente.
Acha que acabou? Ledo engano novamente, o KVC tem um irmão, o KVO que também ajuda na hora de escrever menos código, e vamos falar dele no próximo post, antes de voltarmos ao nosso TodoList. Até a próxima, e não se esqueçam de nos seguir no twitter @dev_br e mandar sugestões e críticas. Até a próxima!
No post anterior, mostramos como adicionar uma busca no nosso aplicativo TodoList, mas ele ainda não está perfeito. Ao adicionarmos uma nova task, a data sempre está errada. Ela deveria ser no mínimo a data atual, e a task deveria iniciar com um nome, tipo Nova Tarefa.
Mas como nem tudo são flores, vamos ter que programar um pouco. O que não implica dizer que deixe de ser fácil programar com o framework Core Data. Na verdade, vamos continuar usando o Core Data, e vamos nos aprofundar mais nele agora.
Quando criamos um Entity no core data (arquivo TodoList.xcdatamodeld), automaticamente ele diz que esse Entity é do tipo NSManagedObject, que é a classe padrão para todos os Entities. Isso não quer dizer que não podemos alterar essa classe. Podemos ter um Entity do tipo que quisermos, contanto que a classe herde de NSManagedObject, e então podemos adicionar funcionalidades que não conseguiríamos adicionar sem código.
Então vamos lá, mãos à obra!
Valores defaults
Valores defaults são os valores que o Core Data seta para cada Entity, na hora em que são criados. No caso da nossa task, o atributo text podemos adicionar direto no arquivo TodoList.xcdatamodeld, para isso, abra este arquivo, selecione a Entity TodoList, depois o atributo text, e no Data Model Inspector, em Default Value, coloque “Nova tarefa” como mostrado abaixo:
E pronto! Fácil certo? Porém, como fazer com o atributo date? Como colocar sempre a data atual? Infelizmente não dá para fazer isso graficamente no Core Data. Não podemos usar um [NSDate date] no Default Value, e é ai que entra a nossa classe Task.
Implementando a classe Task
Implementar esta classe não tem muito mistério, para isso vamos criar uma classe como normalmente criamos: File -> New -> New File. Selecione Objective-C class:
Clique em Next, mantenha Subclass of como NSObject, pois iremos alterá-la logo.
Clique em next, nomeie a nossa classe como Task, e salve:
Pronto, agora vamos fazer as alterações necessárias na nossa classe Task.
Primeiramente precisamos alterar a parent class para NSManagedObject, e adicionar o método awakeFromInsert, depois remover o método init. Logo, nossa classe Task vai ser assim:
Task.h:
#import @interface Task : NSManagedObject { @private } @end
Task.m:
#import "Task.h" @implementation Task - (void) awakeFromInsert { [self setValue:[NSDate date] forKey:@"date"]; } @end
Você deve ter notado que eu usei o método setValue para alterar o valor da propriedade date, do nosso Entity. Isso é o KVC, o setValue perguntando para a classe Task, se ele tem um atributo date, e setando o valor dele para a data atual. Basicamente é assim que o Core Data seta os valores, inclusive os que estão binding na interface gráfica, como quando setamos o conteúdo da nossa NSTableView para mostrar o text.
Salve o arquivo, volte ao TodoList.xcdatamodeld, selecione nossa Entity TodoList, e na aba Data Model Inspector, mude a classe de NSManagedObject para Task:
E pronto! Terminamos, agora rode o seu programa, e adicione uma nova task, e veja que ela vai ser adicionada com o texto Nova Tarefa, e com a data atual:
E por hoje é só, mas ainda falta muita coisa para termos um TodoList legal. Precisamos fazer umas alterações na forma que as listas são mostradas, remover o NSDatePicker lá embaixo e adicionar na própria NSTableView. Seria interessante também mostrar as tasks coloridas, como vermelho se já passou da data, verde para completo, poderíamos até criar uma janela de properties para setar todos esses atributos! Como pode ver, vamos trabalhar bastante, e cada vez que adicionarmos novas funcionalidades, estaremos aprendendo mais e mais!
E não se esqueçam de segur o @dev_br no twitter para ficar sabendo dos novos posts.
No post anterior, mostramos como criar um aplicativo Todo List, de maneira rápida, sem escrever nenhum código, e a seguir, vamos incrementá-lo, adicionando uma busca, e não iremos utilizar nenhum código também para isso. No entanto, é necessário entender como conseguimos fazer isso tudo, implementar até uma busca, sem usar nenhum código.
O Core Data framework utiliza para fazer toda a sua mágica, o conceito de KCV, ou Key Code Value. Esta é uma propriedade vastamente utilizada em Objective-C, e iremos demonstrar seu funcionamento em breve, logo, pense que o Objective-C manda uma mensagem para o objeto perguntando: Alô, você tem um atributo chamado X? E o objeto responde: Ah, tenho sim, então o Objective-C fala: Então mude esse atributo X ai para @”Teste”, e o objeto diz: Ok, mudando! E ai chama o [objeto setX:@"Teste"]; ou objeto.X = @”Teste” como vocês preferirem.
Mais uma vez, não se preocupem se não entenderem o conceito de KVC, iremos falar em detalhes sobre ele em breve. Então, vamos lá, mãos à obra!
Adicionando uma busca no TodoList
Abra o nosso projeto TodoList, e abra o MainMenu.xib, na interface, altere o tamanho do NSTableView e adicione no topo um NSSearchField, como mostrado na figura abaixo:

Agora, precisamos linkar esse NSSearchField, ao nosso NSArrayController, para que ele saiba onde, e o que ele deve filtrar, para isso selecione o NSSearchField recém criado, clique no botão Bindings Inspector, e na opção Search, marque a opção Bind to: e selecione TodoList Controller (que é o nosso NSArrayController), no campo Predicate Format, use o seguinte código:
text contains[c] $value
Onde text é o nome do atributo da nossa TodoList, que iremos filtrar.
O contains[c] significa que é para fazer uma busca, independente se a letra é maiúscula ou minúscula. Internamente, o Cocoa utiliza a classe NSPredicate, que serve para fazer consultas muito parecidas com SQL, você pode usar também text like $value por exemplo para procurar por textos que iniciem com $value.
E falando em $value, é uma variável interna do Interface Builder, sempre será $value, não se preocupe com isso.
Importante:
Não coloque um atributo que não exista na sua classe. Se colocarmos texto contais[c] $value, o Objective-C vai perguntar ao nosso objeto TodoList: Oi, você tem um atributo texto? E o nosso objeto vai responder: Não! e ai o programa vai travar. Então preste bastante atenção todas as vezes que for setar esses valores.
Até agora está tudo bem correto? Salve o projeto, e rode o programa, adicione novas tasks na nossa Todo List, e faça uma busca:
Mas ainda não terminamos, não seria legal que a data de criação fosse a data atual? E quando criássemos uma task, já tivesse uma descrição do tipo: “Clique aqui duas vezes para inserir uma descrição?” Veremos isso no próximo post, não percam, e lembrem-se de seguir o @dev_br no twitter, comentar e enviar suas sugestões.
Hoje iremos mostrar como criar uma aplicação que além de utilizar a interface gráfica do Objective-C: Cocoa, usa também uma persistência de dados criada pela própria Apple chamada Core Data.
Não entraremos em detalhes sobre o conceito de Core Data, o intuito é apenas mostrar do que esse framework é capaz de fazer.
Lembrando que existem outras formas de se trabalhar com dados em Cocoa, como o SQLite, e breve iremos abordar este assunto.
Mas chega de delongas, hoje iremos criar um Todo List, sem utilizar uma única linha de código. E o melhor de tudo, pode ser um aplicativo que irá te ajudar a manter a sua vida organizada.
Primeiro abra o XCode, e crie um novo projeto:
Logo em seguida selecione na aba Mac OS X -> Application e em seguida Cocoa Application:
Escolha o nome da sua aplicação (TodoList) e Não se esqueça de deixar a opção Use Core Data selecionada, pois é esta opção que irá fazer toda a diferença (não escrever nenhum código por exemplo). Logo depois clique em Next, e escolha onde você irá salvar seu aplicativo:
Na tela inicial, escolha agora o arquivo TodoList.xcdatamodeld, e você será apresentado à janela abaixo:
O arquivo TodoList.xcdatamodeld é onde você irá graficamente criar todas as suas entidades para de acesso. No nosso caso, iremos criar apenas uma chamada TodoList, e esta conterá os seguintes campos e respectivos tipos:
- text – String
- date – Date
- isCompleted – Boolean
Existem duas formas de se adicionar um Entity. Nesta tela, em formato de listas como pode ser visto acima, ou clicando no botão Editor Style – Graph, na parte inferior direita, onde o XCode irá nos presentear com esta tela:
Clique no botão Add Entity, e na lista Entities dê um double click e altere o nome para TodoList. Logo em seguida, adicione 3 atributos clicando no botão Add Attribute, e nomeie eles text, date, isCompleted:
Voltemos para o tipo de visualização anterior clicando em Editor Style – Table, e configuremos o tipo para cada um destes atributos:
Salve tudo com Command + S, e agora vamos iniciar a construção da nossa interface gráfica. Clique em MainMenu.xib, selecione Window na aba de objetos, e deixe ela de tamanho aproximadamente igual ao mostrado:
Adicione dois Gradient buttons, clique em Show Size Inspector (botão circulado na figura abaixo) e sete os valores para Width 42 e Height para 43:
Sete o label dos dois botões para + e - respectivamente, e posicione-os como na imagem abaixo:
Agora adicione uma NSTableView, e posicione como na imagem abaixo:
Importante perceber aqui, que quando você arrasta um NSTableView para sua janela, ela já vai com scroll, células, colunas, tudo que você precisa, então cuidado, na imagem acima por exemplo, não é o NSTableView que está selecionado, é o NSScrolledView, clique novamente e selecionará o NSTableView, mais uma vez, e selecionará uma das columas.
Dê um double click na coluna, e altere o texto para Descrição, e a outra coluna para Completo:
Agora vamos alterar o tipo de célula da coluna Completo, pois isComplete é do tipo Boolean, e merece um check box dizendo se está completo ou não correto?
Procure por Check Box Cell em Object Library:
E arraste para a segunda coluna:
Agora vá em Attributes Inspector, remova o texto e deixe a checkbox centralizada como mostrado na imagem abaixo:
Neste momento, procure em Object Library por um NSArrayController, e arraste para a a janela de objetos:
Selecione o nosso NSArrayController e no Attributes Inspector, vá até o Object Controller, em Mode, selecione Entity (Isso irá fazer com que o NSArrayController ache nosso Entity TodoList). Em Entity Name coloque TodoList, marque todas as 3 opções: Prepares Content, Uses Lazy Fetching e Editable:
Depois, vá até Bindings Inspector, e Selecione Parameters -> Managed Object Context, e configure da forma que aparece na figura abaixo:
Antes que eu me esqueça, adicione um NSDatePicker também:
E alteremos o nome do nosso NSArrayControler, expandindo nossa tabela de Objetos clicando no botão circulado, como mostrado abaixo:
Pronto, coloque o nome TodoList Controller:
Agora selecione a primeira coluna do nosso aplicativo, vá até o Bindings Inspector, vá até Value, clique em Bind to, selecione TodoList Controller, mantenha em Controller Key o arrangedObjects e em Model Key Path coloque text, que é o atributo do Entity TodoList que criamos no TodoList.xcdatamodeld e que setamos no NSArrayController.
Faça o mesmo para a segunda coluna, colocando em Model Key Path isComplete:
E a mesma coisa para o NSDatePicker:
Clique com o botão direito sobre o NSArrayController, e clique no + no método add e arraste até o botão +, e faça o mesmo com o remove e arraste até o botão - como mostrado abaixo:
Salve tudo, e clique no botão de Run. Você verá sua aplicação rodando! Tente adicionar algumas tarefas, e remove-las. Feche o programa, abra-o novamente, e veja a mágica! Está tudo salvo!
E por hoje é só! Viu como é fácil criar aplicativos em Cocoa? Espero que este post sirva para incentivar todos a começar a programar para Mac, e veja que não é nenhum bicho de 7 cabeças, é apenas diferente.
Breve vamos melhorar mais este Todo List que fizemos, mas não adiantarei o que faremos. Você vai ter que esperar o próximo post!
E não se esqueça de seguir o @dev_br no twitter para ficar atento nas novidades do blog.
Introdução
Hoje teremos nosso primeiro aplicativo em Cocoa. Não será um super aplicativo, mas abordará as principais características de um aplicativo criado em Cocoa: Gerenciamento de eventos e como fazer a ligação entre o seu código e a interface gráfica.
Obviamente, é possível criar um aplicativo Cocoa sem utilizar o XCode, porém, a quantidade de código necessária para tal, é muito maior, pois você terá que criar cada componente manualmente (botões, tabelas, janelas etc), sem contar que terá que dizer exatamente qual a posição de cada um desses componentes, dentro da janela, o que não será o nosso foco neste post.
Para iniciarmos, vamos fazer um aplicativo simples, com uma janela, e um NSSlider e à medida que movermos o NSSlider, ele irá atualizar um NSTextField com o valor.
Abra o XCode, e clique na opção Create a new XCode Project:
Na próxima janela, selecione no menu à esquerda Mac OS X -> Application e à direita selecione Cocoa Application:
Clique em Next, e preencha o Product Name. Utilizaremos o nome PrimeiroAplicativo:
Aqui você pode setar também informações como Categoria em que seu aplicativo será adicionado na Appp Store, caso deseje adicioná-lo na App Store depois de concluido. Também se irá usar Core Data, Testes etc. Deixe tudo como default por enquanto.
Logo em seguida, selecione onde o seu aplicativo irá ser salvo e você verá a tela do XCode com informações sobre seu aplicativo
Nesta tela inicial, o XCode mostra algumas informações sobre seu aplicativo, e veja que foi criado uma série de arquivos para o seu aplicativo:
O primeiro deles, PrimeiroAplicativoAppDelegate.h e PrimeiroAplicativoAppDelegate.m é a classe principal do nosso aplicativo, é a classe que dá o start no nosso aplicativo, e que conterá todo o nosso código. Nela iremos declarar os componentes que iremos utilizar (NSSLider e NSTextField) e o método que o NSSlider irá chamar quando atualizarmos ele.
O MainMenu.xib é o arquivo que conterá a interface gráfica do nosso aplicativo. Na verdade, esse MainMenu.xib é nada mais do que um arquivo XML, contendo informações sobre os componentes que utilizamos, a posição de cada um na tela, a hierarquia de criação dos componentes, etc.
Quando o nosso aplicativo está carregando, ele lê esse MainMenu.xib e em tempo de execução vai executando o código necessário para criar a interface gráfica do nosso aplicativo. É como se ele lesse esse MainMenu.xib, e visse que tem uma janela do tipo NSWindow, de nome window, que está na posição x, y, de altura e largura w, h, então ele Cria uma nova Janela chamando [[NSWindow alloc] init] seta posição x, y e altura. Depois ele vê que dentro desta janela existe um NSSlider na posição x, y relativa à janela, de altura e largura w, h e cria um NSSlider com alloc/init (ou qualquer outro método de inicialização do NSSlider) e seta a posição, altura, largura e adiciona à janela e por ai vai.
O arquivo PrimeiroAplicativo.xcdatamodeld é onde criaremos a persistência dos nossos dados, porém não iremos utilizá-lo neste exemplo.
Montando a interface gráfica
Selecionando o arquivo MainMenu.xib, aparecerá a tela a seguir:
Note que o que está selecionado na parte superior é o menu do nosso aplicativo, que o XCode já teve o trabalho de criar coisas do tipo File, Edit, etc, que já são padrão em aplicativos Cocoa, e você pode adicionar ou remover esses menus facilmente (deixo este trabalho como exercício para ir treinando). Na barra ao lado, veja que temos alguns botões, estes são os componentes do seu MainMenu.xib, clique no quinto botão de cima para baixo, e você verá a janela do nosso aplicativo
Na parte superior direita do XCode, tem um conjunto de 3 botões escrito View. Clique no terceiro botão Hide or Show Utilities:
Isso irá mostrar o Object Library, onde você encontrará os componentes que você poderá arrastar para a sua janela.
Adicione um NSSlider procurando na lista de componentes, e dois NSTextField do tipo Label à sua janela, e tente deixar como a imagem abaixo:
Dê um double clique no primeiro Label, e digite “Valor:”, selecione o segundo label e digite “50″ (ambos sem aspas).
Depois selecione o NSSlider (que por sinal é Horizontal NSSlider) e no Utilities, selecione Show the attributes Inspector:
O Attributes Inspector, mostra algumas das propriedades que podemos alterar para o nosso NSSlider (e para todos os outros componentes do Cocoa), e aqui marcaremos em State, a opção Continuous.
Pronto, estamos quase terminando com a interface gráfica.
Escrevendo o código
Agora, precisamos linkar o NSSlider e o segundo NSTextField ao nosso código, para que possamos, à medida que movemos o NSSlider de um lado para o outro, alterar o valor do NSTextField, então voltemos ao nosso PrimeiroAplicativoAppDelegate.h, e adicionemos os dois componentes como atributos com o seguinte código:
@property (assign) IBOutlet NSSlider *slider; @property (assign) IBOutlet NSTextField *valor;
E no PrimeiroAplicativoAppDelegate.m adicionamos o synthesize:
@synthesize slider; @synthesize valor;
Você verá que tem um monte de código que o próprio XCode criou, mas não nos preocupemos com isso agora.
Note que usamos um tal de IBOutlet para criar os atributos para o nosso NSSlider e o NSTextField. Este IBOutlet é o que faz a mágica de linkar este atributo, aos componentes que criamos no MainMenu.xib, basicamente ele diz que esses dois atributos são componentes da interface gráfica do nosso aplicativo.
Também precisamos criar o código necessário para quando movermos o NSSlider. Este método é um evento, e quase todos os eventos em Objective-C/Cocoa, seguem o seguinte padrão:
- (IBAction) nomeDoMétodo:(id) sender;
Onde (id) pode ser (id) mesmo, ou o tipo do objeto que está recebendo o evento (no nosso caso poderia ser (NSSlider *), mas como já comentamos antes, (id) é um tipo genérico, e pode ser usado sempre.
O IBAction é o mesmo que void, ele também serve para dizer ao MainMenu.xib que este método, é um evento (ou action), que pode ser um clique de botão, um NSSlider movendo o cursor de um lado para o outro (o nosso caso) ou qualquer outro tipo de evento (aplicativo sendo fechado ou inicializado por exemplo).
Criemos nosso método com o nome didSliderChange. Adicionamos a declaração en nosso arquivo PrimeiroAplicativoAppDelegate.h:
- (IBAction)didSliderChange:(id)sender;
E no arquivo PrimeiroAplicativoAppDelegate.m implementamos:
- (IBAction) didSliderChange:(id)sender { [[self valor] setStringValue:[[self slider] stringValue]]; }
Note que tanto o setStringValue como o stringValue são gets e sets, então poderia ter sido utilizando também a versão com pontos:
- (IBAction) didSliderChange:(id)sender { self.valor.stringValue = self.slider.stringValue; }
Utilize a versão que for mais simples e intuitiva para você.
Ligando os atributos e eventos
Agora que já temos nossos atributos e eventos devidamente codificados, precisamos ligá-los ao nosso MainMenu.xib, então voltemos a ele, selecionemos o Primeiro Aplicativo App Delegate como mostrado na figura abaixo:
Agora, com o botão direito do mouse, clique nele. Aparecerá uma janela como a mostrada abaixo:
Clique no círculo que está sobre o Outlets -> slider, (mantendo o botão pressionado) e arraste até o NSSlider do seu aplicativo:
Faça o mesmo para valor, linkando com o NSTextField que está com o texto 50.
Observação:
Veja que interessante; em momento algum, quando estávamos criando a nossa interface gráfica no MainMenu.xib, dissemos qual seria o nome do nosso NSSlider. Isso foi definido na hora que linkamos o IBOutlet slider que declaramos no nosso PrimeiroAplicativoAppDelegate com o NSSlider do MainMenu.xib. Isso a princípio pode soar estranho para quem está acostumado a desenvolver em Java ou C# (Windows.Forms ou Asp.Net). Aqui, se abrirmos em modo texto o MainMenu.xib, veremos que foi adicionado um número de id único para a aplicação ao NSSlider e quando fazemos esse link, atribuimos ao nosso atributo slider este id único.
Agora iremos linkar o evento didSliderChange ao nosso NSSlider, e o processo é o mesmo, em Received Actions, clicamos em didSliderChange e arrastamos para o NSSlider do MainMenu.xib:
E a janela do nosso Primeiro Aplicativo App Delegate fica como a mostrada abaixo:
Salve tudo, e basta rodar nosso aplicativo clicando no botão Run na parte superior esquerda do XCode, ou com o atalho command + r:
Observação:
Note que o valor vai mudando enquanto arrastamos o NSSlider de um lado para outro. Isso porque marcamos a opção Continuous em Attributes Inspector -> State -> Continuous. Se não tivéssemos marcado esta opção, o valor só mudaria quando parássemos de arrastar. Tente desmarcar esta opção e rodar novamente seu programa e veja o que acontece.
E por hoje é só, fizemos um aplicativo simples, utilizando pouco código, e mostrando os principais aspectos do XCode, Cocoa e Objective-C para desenvolvimento de aplicativos. Até a próxima, e não deixem de nos seguir no twitter @dev_br, comentar e enviar suas dúvidas, críticas ou sugestões.



























































Comentários