Anda di halaman 1dari 27

Curso

de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares

Desenvolvendo aplicaes para iOS usando Objective-C

DESENVOLVIMENTO DE APLICAES PARA IOS USANDO OBJECTIVE-C

INTRODUO 2 CAPTULO 1 - CONHECENDO OBJECTIVE-C 3 IMAGEM 1 SELEO DE PROJETOS NO XCODE 3 IMAGEM 2 CRIANDO O PROJETO NO XCODE 4 IMAGEM 3 VISUALIZAO INICIAL DO PROJETO 5 MAGEM RIANDO O T ARGET Q UE V AI R ODAR O S N OSSOS T ESTES I 4C 6 IMAGEM 5 ADICIONANDO O EXECUTVEL DA APLICAO COMO DEPENDNCIA AO TARGET TEST 7 IMAGEM 6 CRIANDO A NOSSA PRIMEIRA CLASSE EM OBJECTIVE-C 8 IMAGEM 7 CRIANDO A NOSSA PRIMEIRA CLASSE EM OBJECTIVE-C 9 IMAGEM 8 VISUALIZAO DO NAVEGADOR DE ARQUIVOS COM A CLASSE CONTA CRIADA. 9 LISTAGEM 1 CONTA.H 9 LISTAGEM 2 CONTA.M 11 LISTAGEM 3 CONTA.H 11 LISTAGEM 4 CONTA.M 12 CRIANDO O NOSSO PRIMEIRO TESTE UNITRIO 12 IMAGEM 9 CRIANDO O GRUPO TEST 13 IMAGEM 10 CRIANDO A CLASSE DE TESTES 13 IMAGEM 11 SELECIONANDO OS TARGETS DA CLASSE DE TESTES 14 IMPLEMENTANDO O NOSSO PRIMEIRO TESTE 14 LISTAGEM 5 CONTATEST.M 14 IMAGEM 12 ALTERANDO O TARGET PADRO PARA TEST 16 IMAGEM 13 DRAG E DROP DO ARQUIVO CONTA.M EM TEST 16 IMAGEM 14 INDICAO DE ERROS DE BUILD DO XCODE 17 IMAGEM 15 TELA DE ERROS NO BUILD DO XCODE 18 LISTAGEM 6 CONTA.H 18 LISTAGEM 7 CONTA.M 19 LISTAGEM 8 CONTATEST.H 20 LISTAGEM 9 CONTATEST.M 20 CRIANDO UM CONSTRUTOR PARA O NOSSO OBJETO CONTA 22 LISTAGEM 10 CONTA.H DECLARANDO O MTODO INITWITHSALDO 22 LISTAGEM 11 CONTA.M 23 DEFININDO PROPRIEDADES AUTOMATICAMENTE NOS OBJETOS 23 LISTAGEM 12 CONTA.H COM AS NOVAS PROPRIEDADES DEFINIDAS 24 LISTAGEM 13 CONTA.M COM A DEFINIO DAS PROPRIEDADES E GERENCIAMENTO DE MEMRIA 25 LISTAGEM 14 CONTATEST.M COM O CDIGO DE GERENCIAMENTO DE MEMRIA 26

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares

Introduo
Este material tem como objetivo servir de referncia para o curso de desenvolvimento de aplicaes usando Objective-C e XCode para iOS, o sistema operacional para dispositivos mveis da Apple, como iPhones, iPods e iPads. Ele faz parte do material complementar para as aulas expositivas do curso de desenvolvimento para iOS. Para seguir esse material voc precisa de um computador com MacOS e XCode instalados, alm do SDK para desenvolvimento de aplicaes para iOS. O material tambm assume que voc j tem experincia com o desenvolvimento de software em ao menos uma linguagem orientada a objetos. Conceitos bsicos de programao orientada a objetos como variveis de instncia, mtodos, construtores, herana, encapsulamento no vo ser explicados, assume-se que quem est lendo o material j tem conhecimento de todos esses conceitos que so lugar comum em qualquer linguagem de programao orientada a objetos. Em vrias partes do material voc vai encontrar a fala Abra o menu contextual do item X ou clique com o boto direito em X, isso quer dizer usar o boto direito do mouse (em um mouse comom) fazer Control + Click no item selecionado ou, se voc estiver usando um trackpad multi-touch, clicar com os dois dedos ao mesmo tempo.

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares

Captulo 1 - Conhecendo Objective-C


O cdigo fonte deste primeiro captulo est disponvel em - https://github.com/mauricio/capitulo-1-curso-ios Objective-C uma linguagem de programao orientada a objetos de uso geral e a lngua padro para o desenvolvimento de aplicaes para o Mac OS e hoje tambm para o iOS, ambos sistemas operacionais desenvolvidos pela Apple. A linguagem derivada diretamente do C, com algumas caractersticas de Smalltalk, como o uso de parmetros dentro do nome do mtodo em vez de em uma seo de parmetros no mesmo. Vamos fazer agora dar os nossos primeiros passos com o XCode, criando um projeto. Abra o XCode, essa deve ser a primeira janela que voc vai ver: Imagem 1 Seleo de projetos no XCode

Nessa pgina, selecione Create a new Xcode project, aqui est a prxima janela que voc vai ver:

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares Imagem 2 Criando o projeto no Xcode

Nesse primeiro momento, vamos iniciar com uma aplicao para MacOS, pra entender o funcionamento da linguagem e nos acostumarmos com o Xcode como ferramenta. Aps selecionar Mac OS X -> Application -> Command Line Tool, alm de selecionar Foundation no campo de seleo. D o nome AprendendoObjectivec ao projeto. Com o projeto criado, voc deve ver uma janela como essa agora:

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares Imagem 3 Visualizao inicial do projeto

Um fator interessante ao se iniciar o desenvolvimento usando Xcode que mesmo se parecendo com pastas, Source, Documentation, External frameworks and libraries e Products no so pastas, mas agrupamentos de contedo. Se voc for at a pasta que est o projeto, vai perceber que no existem diretrios equivalentes a eles, isso acontece porque o Xcode organiza os arquivos apenas logicamente e no fisicamente dentro do projeto. Com o nosso projeto criado, vamos criar um target para os testes unitrios que vamos escrever durante o exemplo. Pra fazer isso, clique com o boto direito ou Control + Click no marcador Targets, siga para Add, depois New Target. Voc deve ver a tela abaixo:

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares Imagem 4 Criando o target que vai rodar os nossos testes

Ao partir pra prxima tela voc vai definir o nome do target, coloque o nome Test. Assim que o target for criado, ele vai abrir a janela de opes do mesmo, nela, selecione a aba General, clique no boto +, voc deve ver ento uma janela como a imagem logo abaixo, selecione AprendendoObjectivec e clique em Add Target.

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares Imagem 5 Adicionando o executvel da aplicao como dependncia ao target Test

Estamos agora finalmente prontos pra comear a escrever o cdigo do projeto. Para entender as construes bsicas da linguagem, vamos criar uma classe Conta que guarde os dados de agncia, nmero de conta, banco e saldo. Alm disso a classe tambm vai conter os mtodos para sacar, depositar e transferir dinheiro entre contas. Selecione o grupo Source e abra o menu contextual. V em Add -> New File. Selecione Cocoa Class e depois Objective-C class, como na imagem abaixo:

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares Imagem 6 Criando a nossa primeira classe em Objective-C

Na prxima janela, coloque o nome da classe como sendo Conta.m e marque o checkbox Also create Conta.h:

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares Imagem 7 Criando a nossa primeira classe em Objective-C

Com a classe criada, voc deve ver os arquivos no Xcode como na imagem abaixo: Imagem 8 visualizao do navegador de arquivos com a classe Conta criada.

Olhando pra essa imagem podemos ver que existe um arquivo Conta.m e um arquivo Conta.h, vejamos o que h de cdigo em cada um desses arquivos: Listagem 1 Conta.h
#import <Cocoa/Cocoa.h> @interface Conta : NSObject { } @end

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares Se voc nunca programou em C na vida, deve estar se perguntando porque temos dois arquivos para uma nica classe, um .h e outro .m. O arquivo .h, funciona como cabealho (da o .h, de header), nele voc define a interface pblica da classe, como os atributos que ela tem e os mtodos que ela implementa (e que devem ficar visveis para terceiros). Em Objective-C, diferentemente de Java e outras linguagens, no existem modificadores de nvel de visibilidade para as classes ou os seus membros (como mtodos e atributos), tudo visvel, mas apenas o que estiver definido no arquivo .h fica realmente disponvel para outros objetos que queiram usar a sua classe. Olhando agora diretamente para o cdigo fonte, vemos o #import <Cocoa/Cocoa.h>, isso quer dizer que a nossa classe est declarando que vai utilizar funcionalidades do framework Cocoa (na verdade ns s precisamos do framework Foundation, mas vamos deixar assim por enquanto). Logo aps isso vemos o seguinte cdigo: @interface Conta : NSObject Sempre que voc vir um caractere @ (arroba) em cdigo escrito em Objective- C, quer dizer que o que vem logo aps ele uma extenso da linguagem ao C. Opa, pera, como assim uma extenso a linguagem C? Objective-C, assim como C++, existe como uma extenso a linguagem C. Voc pode escrever cdigo C dentro de programas escritos em Objective-C e o seu cdigo (teoricamente) vai compilar e funcionar normalmente. Os designers da linguagem resolveram ento definir uma forma de deixar claro o que no C puro na linguagem usando o caracter @. Ento sempre que voc vir o @ j sabe que isso uma extenso do Objective-C para adicionar novos comportamentos ao nosso querido e amado C. A extenso @interface diz que estamos definindo uma nova classe na linguagem e o que segue essa declarao o nome da classe, no nosso caso Conta. Logo aps a declarao do nome da classe o : NSObject diz que a nossa classe Conta herda de NSObject. Diferentemente de outras linguagens onde existe uma nica classe raiz e me de todos os objetos (pense no Object de Java, Ruby, C# e tantas outras), em Objective-C voc mesmo pode definir uma classe raiz, mas normalmente voc vai herdar de NSObject que a classe raiz do framework base de Objective-C utilizado no desenvolvimento de aplicaes para o Mac OS e iOS. Obviamente, se voc no disser de qual classe voc herda, a sua classe se torna automaticamente uma classe raiz, ento lembre-se sempre de definir a superclasse da sua classe ou simplesmente coloque que ela herda de NSObject. O par de chaves {} que vem logo aps a declarao da classe o lugar onde voc define as variveis de instncia da sua classe e somente elas (no, no aqui que voc coloca os mtodos). Todas as variveis de instncia precisam estar definidas aqui no arquivo .h, mesmo aquelas que voc queira deixar como privadas. Aps o par de chaves vem o corpo da classe, que o lugar onde voc define os mtodos que essa classe implementa (mas voc no os implementa aqui, voc

10

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares apenas define quais so eles). No definir um mtodo aqui normalmente faz com que no seja possvel pra que algum o invoque, uma das formas de se criar mtodos privados em Objective-C, j que no existe esse conceito dentro da linguagem em si. Listagem 2 Conta.m
#import "Conta.h" @implementation Conta @end

No arquivo .m voc encontra agora o cdigo real da classe (mesmo que no tenhamos colocado nada ainda nele. Enquanto que no arquivo .h ns havamos definido a @interface do cdigo, agora estamos definindo a @implementation. Veja que aqui no mais necessrio definir de qual classe a nossa classe herda, a definio fica apenas na interface. Veja que o cdigo tambm faz um #import para o arquivo .h, isso para que o arquivo de implementao possa ver as informaes definidas na interface, como variveis de instncia e tambm receber automaticamente as dependncias que j foram importadas no mesmo. Em C voc faria o mesmo com #include, mas o #import vai um pouco mais longe e evita que o mesmo arquivo seja includo duas vezes, um problema bem comum pra quem trabalha com C. Vamos agora comear a realmente escrever cdigo: Listagem 3 Conta.h
#import <Cocoa/Cocoa.h> @interface Conta : NSObject { float saldo; } - (BOOL) depositar:(float)valor; - (float) saldo; @end

Agora a nossa classe conta tem uma varivel de instncia definida (do tipo float), declaramos a existncia do mtodo depositar que recebe um parmetro do tipo float e retorna um BOOL, o boolean da linguagem. Tambm declaramos o mtodo saldo que vai ser a forma de acessar a varivel de instncia saldo. possvel acessar uma varivel de instncia de uma classe em Objective-C diretamente de fora da classe, mas o melhor fazer o acesso sempre via mtodos (ou as propriedades que veremos mais a frente). O sinal de - (subtrao) antes da definio do mtodo avisa que esse um mtodo de instncia (mtodos de classe so definidos com um sinal de adio, o +). O tipo de retorno e o tipo dos parmetros recebidos ficam sempre entre parnteses. Um detalhe importante na declarao de mtodos em Objective-C que o parmetro fica dentro do nome do mtodo e no aps a definio do nome,

11

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares como em Java ou Ruby. Como o mtodo depositar recebe um parmetro necessrio colocar os : para separar o nome do parmetro que est sendo passado, depois vamos entender um pouco mais como se nomeiam mtodos em Objective-C. Vejamos ento como vai ficar o nosso arquivo .m: Listagem 4 Conta.m
#import "Conta.h" @implementation Conta - (BOOL) depositar: (float) valor { if ( valor > 0 ) { saldo += valor; return YES; } else { return NO; } } - (float) saldo { return saldo; } @end

Olhando pro cdigo fonte voc j deve ter entendido exatamente o que ele faz, se o valor passado como parmetro for maior do que zero, ele vai somar com o valor atual da varivel de instncia saldo e retornar YES, que um atalho para o valor BOOL que representa verdadeiro, se o valor passado como parmetro for menor ou igual a zero ele simplesmente retorna NO. Assim como em C, blocos de cdigo em Objective-C ficam sempre dentro de pares de chaves ({}) e todas as estruturas de controle que voc conhece do C (ou Java e C#) existem exatamente da mesma forma em Objective-C. A implementao do mtodo saldo ainda mais trivial, ela simplesmente retorna o valor da varivel de instncia diretamente.

Criando o nosso primeiro teste unitrio


Com a nossa classe implementada, agora a hora de escrever um teste para esse primeiro mtodo implementado. A primeira coisa a se fazer criar um novo grupo dentro do projeto pra manter as classes de teste, assim podemos facilmente separar as classes dos seus testes na hora de gerar a aplicao final, j que ela no precisa levar os testes consigo. Clique com o boto direito em AprendendoObjectivec, como na imagem abaixo:

12

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares Imagem 9 Criando o grupo Test

Com o grupo criado, clique com o boto direito em Test, selecione Add e New File. Voc vai criar uma classe de teste padro do Cocoa, como na imagem abaixo: Imagem 10 Criando a classe de testes

D o nome ContaTest a classe e selecione o Target Test apenas, desmarcando o primeiro Target que aparece, como na imagem abaixo:

13

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares Imagem 11 Selecionando os targets da classe de testes

No caso dos testes, voc normalmente no precisa definir nada no arquivo .h, j que os mtodos so chamados automaticamente, ento vamos nos focar apenas no arquivo .m, que onde ns vamos realmente estar trabalhando.

Implementando o nosso primeiro teste


Listagem 5 ContaTest.m
#import "ContaTest.h" #import "Conta.h" @implementation ContaTest - (void) testDepositarComSucesso { Conta * conta = [[Conta alloc] init]; [conta depositar:200]; STAssertTrue( [conta saldo] == 300, @"O saldo deve ser de 300 para que o teste falhe" ); } @end

Assim como em outros frameworks de teste, o mtodo que define a implementao do teste precisa ter o seu nome iniciando com test e no retornar nada (por isso o void). Na primeira linha do teste j temos vrios detalhes da linguagem pra entender. A primeira coisa a ser percebida que a declarao da varivel contm um *, se voc vem do C, sabe que isso quer dizer que essa varivel na verdade uma referencia (ou ponteiro) pra um objeto que est em memria. Sempre que voc define uma referencia pra uma varivel em Objective-C necessrio colocar o

14

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares *, se voc no o fizer vai receber warnings do compilador e o seu programa no vai funcionar corretamente. Ainda nessa linha temos o idioma de inicializao de objetos. O que em outras linguagens de programao OO seria feito atravs de um construtor, em Objective-C se faz atravs das chamadas a alloc, um mtodo de classe que organiza uma nova instncia do objeto em memria e retorna o objeto pronto pra uso, e init, que executa finalmente a inicializao do objeto. possvel usar tambm o mtodo de classe new em vez do par alloc/init para se criar um objeto, mas prefervel usar alloc/init, especialmente se voc pretende ter vrias formas de inicializar o seu objeto. timo, voc diz, mas o que diabos so aqueles pares de colchetes ([])? Seguindo a tradio de Smalltalk, em Objective-C a ideia no que voc est chamando um mtodo em um objeto, mas sim enviando uma mensagem a ele. Inicialmente, a sintaxe pode realmente parecer um pouco estranha, mas no fim das contas ela bem simples: [ objetoDestino mensagem ] Do lado esquerdo, voc sempre tem o objeto para o qual voc quer enviar a mensagem, do lado direito voc tem a mensagem que est sendo enviada (o mtodo que est sendo chamado), tudo isso dentro de colchetes. No nosso caso, onde fazemos [[Conta alloc] init], estamos enviando a mensagem alloc para o objeto que representa a classe Conta e no valor que retornado por esse mtodo (um objeto Conta) fazemos a chamada do mtodo init. O idioma alloc/init comum e pervasivo em toda a linguagem e exemplos de cdigo que voc vai encontrar, mas evite fazer chamadas de mtodo dentro de chamadas de mtodo no seu cdigo, a no ser que seja um caso muito simples como esse que ns estamos vendo aqui. Na segunda linha do teste vemos o seguinte:
[conta depositar:200];

Ns enviamos a mensagem depositar para o objeto representado pela varivel conta com o parmetro 200. Os : que ns usamos na definio do mtodo depositar fazem realmente parte do nome do mtodo, sendo obrigatrio a sua adio a chamada (os mtodos que no adicionam : so os que no recebem parmetros). No fim temos o cdigo que faz a assero do teste:
STAssertTrue( [conta saldo] == 300, @"O saldo deve ser de 300 para que o teste falhe" );

Comparamos ento o valor do saldo com 300 exatamente porque queremos, nesse primeiro momento, ver o teste falhar. STAssertTrue no um mtodo, mas uma funo comum que voc definiria como uma funo em C, ela faz parte do framework de testes unitrios que vem por padro dentro do Cocoa. Agora um detalhe importante que pode passar desapercebido a definio do texto usado como mensagem para esse teste, em vez de ser somente um conjunto de caracteres entre aspas, h um @ antes das aspas. Isso quer dizer que voc

15

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares no est usando uma string comum do C, que um array de caracteres, e sim um objeto do tipo NSString que adiciona vrias funcionalidades as strings comuns do C. A maior parte do cdigo em Objective-C que lida com Strings vai esperar que voc envie objetos do tipo NSString, ento bom se acostumar a escrever primeiro a @ antes de declarar um string no seu cdigo. Voltemos agora para o Xcode, onde voc vai mudar o Target padro para Test, veja como fazer isso na imagem abaixo: Imagem 12 Alterando o Target padro para Test

Agora estamos entrando no modo de testes do Xcode vamos poder comear a executar os testes, mas antes de fazer isso precisamos dizer para o Target Test onde ele vai achar a classe Conta, pois ela no foi adicionada a ele. Pra fazer isso, voc deve selecionar o arquivo Conta.m e arrast-lo para dentro da pasta Compile Sources do Target Test, como na imagem abaixo: Imagem 13 Drag e drop do arquivo Conta.m em Test

16

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares Com isso feito, podemos finalmente executar o build do projeto, pra fazer isso digite Command + B. Aps alguns instantes o Xcode deve terminar de fazer o build e voc deve ver um aviso no canto inferior direito da ferramenta indicando que existem dois erros: Imagem 14 Indicao de erros de build do Xcode

Ao clicar nos erros voc deve ver a seguinte tela:

17

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares Imagem 15 tela de erros no build do Xcode

Como voc pode perceber, o erro na verdade no exatamente no build, mas sim no nosso teste unitrio que falhou, j que o valor da varivel no 300 e sim 200. Para ver essa tela sem ter que usar o mouse pra clicar no erro basta fazer Shift + Command + B. Agora que voc j viu a tela, troque o 300 por 200 e execute o build mais uma vez com Command + B, o seu build deve executar sem erros, agora que o teste j est implementado corretamente. Vamos agora definir os mtodos sacar e transferir na classe conta: Listagem 6 Conta.h
#import <Cocoa/Cocoa.h> @interface Conta : NSObject { float saldo; } (BOOL) depositar: (float) valor; (BOOL) sacar: (float) valor; (BOOL) transferir: (float) valor para: (Conta *) destino; (float) saldo;

@end

Estamos quase chegando l, o mtodo sacar tem a definio igual a depositar, mas o mtodo transferir:para: (veja s como ele se chama) deve estar dando um n no seu crebro nesse momento. Vejamos:
- (BOOL) transferir: (float) valor para: (Conta *) destino;

Em Objective-C, quando voc tem um mtodo que recebe vrios parmetros, voc precisa dividir o nome do mtodo em pedaos para receber os

18

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares parmetros. Ento em vez de simplesmente fazer um transferir( double valor, Conta destino ), como voc faria em Java ou C#, voc quebra o nome do mtodo e transformar ele em transferir: valor para: destino. Inicialmente a sintaxe parece estranha, mas a prpria leitura da chamada do mtodo fica mais simples e se voc tiver um mtodo que recebe vrios parmetros ele com certeza vai ficar bem mais legvel, j que cada parmetro vai ter o seu identificador antes. Vejamos agora como fica a implementao desses dois mtodos: Listagem 7 Conta.m
#import "Conta.h" @implementation Conta - (BOOL) depositar: (float) valor { if ( valor > 0 ) { saldo += valor; return YES; } else { return NO; } } - (BOOL) sacar:(float)valor { if ( valor > 0 && valor <= saldo) { saldo -= valor; return YES; } else { return NO: } } - (BOOL) transferir:(float) valor para:(Conta *) destino { if ( [self sacar: valor] && [ destino depositar: valor ] ){ return YES; } else { return NO; } } - (float) saldo { return saldo; } @end

A essa altura do campeonato, voc j sabe exatamente o que esse cdigo todo est fazendo, ento vamos passar diretamente pros testes, pra ver esses novos 19

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares mtodos sendo exercitados. Em todos os nossos testes vamos, utilizar um objeto conta, ento em vez de recriar esse objeto a cada teste, vamos ser inteligentes definir uma varivel de instncia Conta no nosso teste e implementar o mtodo setUp que cria a conta para no repetirmos essa operao: Listagem 8 ContaTest.h
#import <SenTestingKit/SenTestingKit.h> @class Conta; @interface ContaTest : SenTestCase { Conta * conta; } @end

Adicionamos a definio da varivel de instncia na classe, como esperado, mas o que esse @class que tambm est a? O @class em Objective-C uma forward reference e normalmente utilizado em arquivos .h para que voc diga que o seu arquivo depende de uma classe em especfico, mas no vai fazer o #import dessa classe aqui, vai deixar pra importar o arquivo da classe somente no seu .m. Se voc no colocar o @class nem o #import pra o arquivo da classe no vai ser possvel compilar o cdigo. Um detalhe importante do #import que quando o texto que vem aps ele est entre <> (como em #import <SenTestingKit/SenTestingKit.h>), isso indica ao compilador que ele deve procurar esse arquivo no load path do sistema operacional, os lugares onde ficam os arquivos .h do mesmo. Quando o #import aparece usando aspas no contedo a ser importado, quer dizer que ele deve procurar dentro dos arquivos locais do projeto (como em #import "Conta.h"). Vejamos agora a implementao atual dos testes: Listagem 9 ContaTest.m
#import "ContaTest.h" #import "Conta.h" @implementation ContaTest - (void) setUp { conta = [[Conta alloc] init]; [conta depositar: 200]; } - (void) testDepositarComSucesso { [conta depositar:150]; STAssertTrue( conta.saldo == 350, @"Saldo final deve ser 350" );

20

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares


} - (void) testDepositarComFalha { [conta depositar:-150]; STAssertTrue( conta.saldo == 200, @"Valor do saldo no deve ter se modificado" ); } - (void) testSacarComSucesso { [conta sacar:150]; STAssertTrue( conta.saldo == 50, @"O saldo atual deve ser 50" ); } - (void) testSacarComValorMaior { [conta sacar: 250]; STAssertTrue( conta.saldo == 200, @"O saldo atual no deve ter se modificado" ); } - (void) testSacarComValorNegativo { [conta sacar: -100]; STAssertTrue( conta.saldo == 200, @"O saldo atual no deve ter se modificado" ); } - (void) testTransferirComSucesso { Conta * destino = [[Conta alloc] init]; [conta transferir:150 para: destino]; STAssertTrue( conta.saldo == 50, @"O saldo da conta origem deve ser 50" ); STAssertTrue( destino.saldo == 150, @"O saldo da conta destino deve ser 250" ); } - (void) testTransferirComFalha { Conta * destino = [[Conta alloc] init]; [ conta transferir:250 para: destino ]; STAssertTrue( conta.saldo == 200, @"O saldo da conta origem deve ser 50" ); STAssertTrue( destino.saldo == 0, @"O saldo da conta destino deve ser 250" );

21

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares


} @end

Temos ento vrios testes para a implementao das funcionalidades da nossa classe conta, eles so bem simples, mas tem duas coisas importantes que no discutimos ainda, a primeira essa:
conta.saldo == 200

Antes, no nosso teste, fazamos a chamada assim:


[conta saldo] == 200

Em Objective-C, se voc tem um mtodo que no recebe parmetros e retorna um valor, esse mtodo pode ser chamado como se ele fosse uma propriedade do seu objeto, sem que voc tenha que fazer uma invocao explcita do mesmo, ento conta.saldo a mesma coisa que escrever [conta saldo], o compilador vai fazer a mgica de transformar o primeiro no segundo pra voc. J o segundo caso:
[ conta transferir:250 para: destino ]

Aqui ns vemos um exemplo da chamada do mtodo transferir:para:, junto com o transferir ns temos o valor que vai ser transferido e logo depois de para temos o objeto que vai receber a transferncia, veja que no existem vrgulas separando os parmetros, eles so separados normalmente pelos espaos entre os nomes que formam o mtodo e os parmetros passados.

Criando um construtor para o nosso objeto conta


Como j comentamos antes, o par [[Conta alloc] init] serve pra criar o objeto e inicializ-lo dentro do projeto, mas e se ns quisermos definir uma forma personalizada? Simples, criamos um mtodo de inicializao. No nosso caso queremos poder criar contas com um saldo que seja diferente de zero. Comeamos por definir o mtodo initWithSaldo em Conta.h: Listagem 10 Conta.h declarando o mtodo initWithSaldo
#import <Cocoa/Cocoa.h> @interface Conta : NSObject { float saldo; } (Conta *) initWithSaldo: (float) valor; (BOOL) depositar: (float) valor; (BOOL) sacar: (float) valor; (BOOL) transferir: (float) valor para: (Conta *) destino; (float) saldo;

@end

22

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares Como no existem construtores realmente dentro da linguagem, o que ns fazemos definir mtodos que inicializem o objeto com o valor que nos interessa, vejamos a implementao agora pra entender um pouco mais o que est acontecendo e porque necessrio criar esses mtodos: Listagem 11 Conta.m
#import "Conta.h" @implementation Conta - (Conta *) initWithSaldo:(float)valor { if ( self = [ self init]) { saldo = valor; } return self; } // todo aquele cdigo que voc j viu @end

Mais um caso de idioma da linguagem surge ento pra ns nesse momento:


if ( self = [ self init]) {

Por mais estranho que parea, esse cdigo est realmente atribuindo um valor a varivel self (self equivalente ao this em Java e C#, uma referncia para o objeto onde o mtodo em execuo atual foi chamado) dentro do seu objeto. Mas porque algum iria querer fazer isso? Na implementao da Apple do Objective-C existe um conceito chamado de class-clusters. Quando voc cria um objeto do tipo NSString, o que voc recebe pode no ser exatamente um NSString, mas uma subclasse dele. As classes que ns vemos do lado de fora funcionam apenas como um meio pra se acessar as classes que fazem realmente o trabalho, mas esses detalhes de implementao ficam escondidos graas a essa pequena mgica do mtodo init (atribuir um novo valor a self e retornar esse valor). No caso da nossa classe no seria necessrio fazer essa mgica, j que estamos realmente retornando uma conta, mas o ideal que voc construa todos os seus inicializadores dessa forma para que quando for criar uma subclasse de uma classe padro da linguagem no se esquecer e terminar com bugs estranhos no seu cdigo. Outra coisa importante tambm lembrar-se de chamar o mtodo init da sua classe, se voc estiver implementando um novo inicializador (como ns fazemos nesse cdigo) ou chamar o mtodo init da sua superclasse (com [super init]) se voc estiver sobrescrevendo o mtodo init, assim voc no perde o cdigo de inicializao que j tenha sido implementado na classe atual e nas suas superclasses.

Definindo propriedades automaticamente nos objetos


Ns vimos que o compilador inteligente o suficiente pra aceitar que [conta saldo] seja chamado como conta.saldo, mas alm disso ns tambm podemos 23

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares instruir o compilador para que ele gere os mtodos de acesso para as propriedades dos nossos objetos automaticamente (pense no generate getters and setters do Eclipse ou attr_accessor em Ruby). Pra isso, vamos definir novas propriedades na nossa classe, agencia e conta. Vejamos como fica o nosso Conta.h agora:

Listagem 12 Conta.h com as novas propriedades definidas


#import <Cocoa/Cocoa.h> @interface Conta : NSObject { float saldo; NSString * conta; NSString * agencia; } @property (copy, nonatomic) NSString * conta; @property (copy, nonatomic) NSString * agencia; @property (readonly) float saldo; (Conta (BOOL) (BOOL) (BOOL) *) initWithSaldo: (float) valor; depositar: (float) valor; sacar: (float) valor; transferir: (float) valor para: (Conta *) destino;

@end

Ns definimos as duas variveis de instncia, agencia e conta, e logo depois temos as declaraes das propriedades, com @property:
@property (copy, nonatomic) NSString * conta;

Isso indica ao compilador que ns vamos ter os mtodos abaixo definidos: - - (NSString * ) conta; (void) setConta: ( NSString * );

As instrues copy e nonatomic so atributos que vo ser utilizados na gerao da implementao dos mtodos. - copy indica que quando um objeto for recebido como parmetro, deve ser criada uma cpia desse objeto e essa cpia quem vai ser atribuda a varivel de instncia, isso necessrio especialmente se voc est recebendo dados da interface, pois os strings que vem dela podem ser recolhidos da memria a qualquer momento nos ambientes onde no h coletor de lixo, como iPads e iPhones. nonatomic indica que os mtodos gerados no vo fazer nenhum controle sobre o acesso de forma concorrente. Esse normalmente o caso pra maior parte das aplicaes, mas se voc vai utilizar esse objeto em um ambiente com concorrncia, onde vrias threads vo acessar o mesmo objeto e chamar seus mtodos, deve remover isso. readonly indica que apenas o mtodo getter, que l o valor da varivel, vai ser gerado, o mtodo set, que altera o valor da varivel no vai ser gerado.

24

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares Com os mtodos definidos, agora voltamos pra Conta.m pra declarar o cdigo que vai fazer com que os mtodos sejam realmente gerados, vejamos como fica o cdigo agora: Listagem 13 Conta.m com a definio das propriedades e gerenciamento de memria
#import "Conta.h" @implementation Conta @synthesize agencia, conta, saldo; - (void) dealloc { [ self.agencia release ]; [ self.conta release ]; [ super dealloc ]; } // todo o resto do cdigo que voc j conhece aqui @end

A mgica de verdade vive no @synthesize, ele instrui o compilador a ler as informaes das propriedades definidas atravs de @property e gerar os mtodos. Junto com isso chegamos a um detalhe importante da programao com Objective-C, especialmente se voc estiver planejando programar para iOS, o gerenciamento de memria. Com a definio das propriedades ns definimos tambm o mtodo dealloc que chamado quando um objeto vai ser removido da memria, para que ele possa limpar da memria tambm os objetos para os quais ele aponta. Quando voc est programando em Objective-C para iOS, no existe um coletor de lixo automtico, liberar a memria responsabilidade do programador, ento necessrio que voc tome cuidado para no vazar memria no seu cdigo e estourar a memria do dispositivo. Em Objective-C o controle de memria, quando no feito atravs do coletor de lixo, acontece atravs da contagem de referencias. Sempre que voc cria um objeto usando alloc ou new esse objeto fica com o contador de referencias em 1 (um), cada vez que voc chama retain no objeto (como em [objeto retain]) esse contador aumenta em um e cada vs que voc chama release (como em [objeto release]) o contador diminui em 1. Quando o contador de referencias atingir 0, o objeto removido da memria. No nosso caso, as propriedades conta e agencia so definidas como copy, isso quer dizer que o objeto que vai ser colocado na varivel de instncia vai ser clonado e o clone o objeto que vai finalmente ficar disponvel para a nossa classe. Como o clone um objeto recm-criado com base em outro objeto a sua contagem de referencias 1 (um), o que quer dizer que quando chamarmos release neles, eles vo ser removidos da memria. Pra limpar a memria que estamos usando, precisamos ajustar o nosso teste para fazer o release dos objetos conta que esto sendo criados. Vamos fazer o

25

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares release da varivel de instncia conta no mtodo tearDown e da conta destino em cada um dos testes, vejamos o que muda na nossa classe teste: Listagem 14 ContaTest.m com o cdigo de gerenciamento de memria
@implementation ContaTest //mtodos no mostrados aqui no foram alterados - (void) tearDown { [ conta release ]; } - (void) testTransferirComSucesso { Conta * destino = [[Conta alloc] initWithSaldo: 100 ]; [conta transferir:150 para: destino]; STAssertTrue( conta.saldo == 50, @"O saldo da conta origem deve ser 50" ); STAssertTrue( destino.saldo == 250, @"O saldo da conta destino deve ser 250" ); [ destino release ]; } - (void) testTransferirComFalha { Conta * destino = [[Conta alloc] init]; [ conta transferir:250 para: destino ]; STAssertTrue( conta.saldo == 200, @"O saldo da conta origem deve ser 50" ); STAssertTrue( destino.saldo == 0, @"O saldo da conta destino deve ser 250" ); [ destino release ]; } - (void) testSetContaEAgencia { conta.agencia = @"1111-0"; conta.conta = @"10.000-9"; STAssertEqualObjects( conta.agencia, @"1111-0", @"O valor deve ser igual" ); STAssertEqualObjects( conta.conta, @"10.000-9", @"O valor deve ser igual" ); } @end

26

Curso de desenvolvimento de aplicaes para iOS usando Objective-C Maurcio Linhares Adicionamos a nossa implementao o mtodo tearDown que envia um release para o objeto conta e tambm fazemos o release dos objetos destino criados nos testes de transferncia. Voc nunca deve chamar o mtodo dealloc diretamente nos seus objetos, sempre chame release e deixe que o prprio runtime do Objective-C vai fazer a chamada a dealloc quando for a hora correta. possvel definir algumas regrinhas bsicas na hora de lidar com a gerncia de memria em aplicaes escritas em Objective-C: Se voc pegou um objeto atravs de alloc/new/copy, esse objeto tem um contador de 1 e voc deve se lembrar de liberar esse objeto quando ele no for mais necessrio; Se voc pegou um objeto de outro lugar, assuma que ele tem um contador de 1, se voc s vai us-lo e deixar ele pra l, no faa nada com ele, quem passou ele pra voc provavelmente vai limp-lo quando for necessrio. Se voc precisa manter um objeto recebido de outro lugar para us-lo em outro momento, chame retain nele para que o contador aumente para 2, assim quando quem lhe passou esse objeto chamar release nele o contador vai baixar pra 1 e o objeto ainda no vai ser liberado da memria. Sempre que voc d retain em um objeto, deve garantir que vai dar um release nele em algum momento, se voc no der o release, com certeza vai estar vazando memria na sua aplicao;

Gerenciamento de memria um tpico longo e vamos nos aprofundar mais nele conforme avanamos para a construo das nossas aplicaes para iOS, essa introduo apenas para que voc entenda o bsico de como esse conceito funciona dentro da linguagem.

27

Anda mungkin juga menyukai