Escolar Documentos
Profissional Documentos
Cultura Documentos
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
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.
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.
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.
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
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
21
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
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.
@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
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.
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:
@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