O documento apresenta um curso sobre desenvolvimento de aplicações para iOS usando Objective-C. É dividido em capítulos que abordam tópicos como conhecendo Objective-C, criando classes e métodos, desenvolvendo testes unitários e definindo propriedades automaticamente nos objetos. O objetivo é servir de referência para o curso e ensinar a criar aplicativos para dispositivos móveis da Apple usando a linguagem Objective-C no Xcode.
Curso de desenvolvimento de aplicações para iOS com Objective-C
1. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
1
Desenvolvendo
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
mauricio.linhares@gmail.com
DESENVOLVIMENTO
DE
APLICAÇÕES
PARA
IOS
USANDO
OBJECTIVE-‐C
1
INTRODUÇÃO
2
CAPÍTULO
1
-‐
CONHECENDO
OBJECTIVE-‐C
3
IMAGEM
1
–
SELEÇÃO
DE
PROJETOS
NO
XCODE
3
IMAGEM
2
–
CRIANDO
O
PROJETO
NO
XCODE
4
IMAGEM
3
–
VISUALIZAÇÃO
INICIAL
DO
PROJETO
5
IMAGEM
4
–
CRIANDO
O
TARGET
QUE
VAI
RODAR
OS
NOSSOS
TESTES
6
IMAGEM
5
–
ADICIONANDO
O
EXECUTÁVEL
DA
APLICAÇÃO
COMO
DEPENDÊNCIA
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
–
VISUALIZAÇÃO
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
UNITÁRIO
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
PADRÃO
PARA
TEST
16
IMAGEM
13
–
DRAG
E
DROP
DO
ARQUIVO
“CONTA.M”
EM
TEST
16
IMAGEM
14
–
INDICAÇÃO
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
MÉTODO
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
DEFINIÇÃO
DAS
PROPRIEDADES
E
GERENCIAMENTO
DE
MEMÓRIA
25
LISTAGEM
14
–
CONTATEST.M
COM
O
CÓDIGO
DE
GERENCIAMENTO
DE
MEMÓRIA
26
2. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
2
Introdução
Este
material
tem
como
objetivo
servir
de
referência
para
o
curso
de
desenvolvimento
de
aplicações
usando
Objective-‐C
e
XCode
para
iOS,
o
sistema
operacional
para
dispositivos
móveis
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,
além
do
SDK
para
desenvolvimento
de
aplicações
para
iOS.
O
material
também
assume
que
você
já
tem
experiência
com
o
desenvolvimento
de
software
em
ao
menos
uma
linguagem
orientada
a
objetos.
Conceitos
básicos
de
programação
orientada
a
objetos
como
variáveis
de
instância,
métodos,
construtores,
herança,
encapsulamento
não
vão
ser
explicados,
assume-‐se
que
quem
está
lendo
o
material
já
tem
conhecimento
de
todos
esses
conceitos
que
são
lugar
comum
em
qualquer
linguagem
de
programação
orientada
a
objetos.
Em
várias
partes
do
material
você
vai
encontrar
a
fala
“Abra
o
menu
contextual
do
item
X”
ou
“clique
com
o
botão
direito
em
X”,
isso
quer
dizer
usar
o
botão
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.
3. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
3
Capítulo
1
-‐
Conhecendo
Objective-‐C
O
código
fonte
deste
primeiro
capítulo
está
disponível
em
-‐
https://github.com/mauricio/capitulo-‐1-‐curso-‐ios
Objective-‐C
é
uma
linguagem
de
programação
orientada
a
objetos
de
uso
geral
e
é
a
língua
padrão
para
o
desenvolvimento
de
aplicações
para
o
Mac
OS
e
hoje
também
para
o
iOS,
ambos
sistemas
operacionais
desenvolvidos
pela
Apple.
A
linguagem
é
derivada
diretamente
do
C,
com
algumas
características
de
Smalltalk,
como
o
uso
de
parâmetros
dentro
do
nome
do
método
em
vez
de
em
uma
seção
de
parâmetros
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
–
Seleção
de
projetos
no
XCode
Nessa
página,
selecione
“Create
a
new
Xcode
project”,
aqui
está
a
próxima
janela
que
você
vai
ver:
4. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
4
Imagem
2
–
Criando
o
projeto
no
Xcode
Nesse
primeiro
momento,
vamos
iniciar
com
uma
aplicação
para
MacOS,
pra
entender
o
funcionamento
da
linguagem
e
nos
acostumarmos
com
o
Xcode
como
ferramenta.
Após
selecionar
“Mac
OS
X”
-‐>
“Application”
-‐>
“Command
Line
Tool”,
além
de
selecionar
“Foundation”
no
campo
de
seleção.
Dê
o
nome
“AprendendoObjectivec”
ao
projeto.
Com
o
projeto
criado,
você
deve
ver
uma
janela
como
essa
agora:
5. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
5
Imagem
3
–
Visualização
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”
não
são
pastas,
mas
“agrupamentos”
de
conteúdo.
Se
você
for
até
a
pasta
que
está
o
projeto,
vai
perceber
que
não
existem
diretórios
equivalentes
a
eles,
isso
acontece
porque
o
Xcode
organiza
os
arquivos
apenas
logicamente
e
não
fisicamente
dentro
do
projeto.
Com
o
nosso
projeto
criado,
vamos
criar
um
target
para
os
testes
unitários
que
vamos
escrever
durante
o
exemplo.
Pra
fazer
isso,
clique
com
o
botão
direito
ou
“Control
+
Click”
no
marcador
“Targets”,
siga
para
“Add”,
depois
“New
Target”.
Você
deve
ver
a
tela
abaixo:
6. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
6
Imagem
4
–
Criando
o
target
que
vai
rodar
os
nossos
testes
Ao
partir
pra
próxima
tela
você
vai
definir
o
nome
do
target,
coloque
o
nome
Test.
Assim
que
o
target
for
criado,
ele
vai
abrir
a
janela
de
opções
do
mesmo,
nela,
selecione
a
aba
“General”,
clique
no
botão
“+”,
você
deve
ver
então
uma
janela
como
a
imagem
logo
abaixo,
selecione
“AprendendoObjectivec”
e
clique
em
“Add
Target”.
7. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
7
Imagem
5
–
Adicionando
o
executável
da
aplicação
como
dependência
ao
target
Test
Estamos
agora
finalmente
prontos
pra
começar
a
escrever
o
código
do
projeto.
Para
entender
as
construções
básicas
da
linguagem,
vamos
criar
uma
classe
Conta
que
guarde
os
dados
de
agência,
número
de
conta,
banco
e
saldo.
Além
disso
a
classe
também
vai
conter
os
métodos
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:
8. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
8
Imagem
6
–
Criando
a
nossa
primeira
classe
em
Objective-‐C
Na
próxima
janela,
coloque
o
nome
da
classe
como
sendo
“Conta.m”
e
marque
o
checkbox
“Also
create
‘Conta.h’”:
9. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
9
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
–
visualização
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
código
em
cada
um
desses
arquivos:
Listagem
1
–
Conta.h
#import <Cocoa/Cocoa.h>
@interface Conta : NSObject {
}
@end
10. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
10
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
“cabeçalho”
(daí
o
“.h”,
de
“header”),
nele
você
define
a
interface
pública
da
classe,
como
os
atributos
que
ela
tem
e
os
métodos
que
ela
implementa
(e
que
devem
ficar
visíveis
para
terceiros).
Em
Objective-‐C,
diferentemente
de
Java
e
outras
linguagens,
não
existem
modificadores
de
nível
de
visibilidade
para
as
classes
ou
os
seus
membros
(como
métodos
e
atributos),
tudo
é
“visível”,
mas
apenas
o
que
estiver
definido
no
arquivo
“.h”
fica
realmente
disponível
para
outros
objetos
que
queiram
usar
a
sua
classe.
Olhando
agora
diretamente
para
o
código
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
nós
só
precisamos
do
framework
“Foundation”,
mas
vamos
deixar
assim
por
enquanto).
Logo
após
isso
vemos
o
seguinte
código:
@interface
Conta
:
NSObject
Sempre
que
você
vir
um
caractere
“@”
(arroba)
em
código
escrito
em
Objective-‐
C,
quer
dizer
que
o
que
vem
logo
após
ele
é
uma
extensão
da
linguagem
ao
C.
Opa,
peraí,
como
assim
uma
“extensão
a
linguagem
C”?
Objective-‐C,
assim
como
C++,
existe
como
uma
extensão
a
linguagem
C.
Você
pode
escrever
código
C
dentro
de
programas
escritos
em
Objective-‐C
e
o
seu
código
(teoricamente)
vai
compilar
e
funcionar
normalmente.
Os
designers
da
linguagem
resolveram
então
definir
uma
forma
de
deixar
claro
o
que
não
é
“C
puro”
na
linguagem
usando
o
caracter
“@”.
Então
sempre
que
você
vir
o
“@”
já
sabe
que
isso
é
uma
extensão
do
Objective-‐C
para
adicionar
novos
comportamentos
ao
nosso
querido
e
amado
C.
A
extensão
@interface
diz
que
estamos
definindo
uma
nova
classe
na
linguagem
e
o
que
segue
essa
declaração
é
o
nome
da
classe,
no
nosso
caso
“Conta”.
Logo
após
a
declaração
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
mãe
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
aplicações
para
o
Mac
OS
e
iOS.
Obviamente,
se
você
não
disser
de
qual
classe
você
herda,
a
sua
classe
se
torna
automaticamente
uma
classe
raiz,
então
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
após
a
declaração
da
classe
é
o
lugar
onde
você
define
as
variáveis
de
instância
da
sua
classe
e
somente
elas
(não,
não
é
aqui
que
você
coloca
os
métodos).
Todas
as
variáveis
de
instância
precisam
estar
definidas
aqui
no
arquivo
“.h”,
mesmo
aquelas
que
você
queira
deixar
como
“privadas”.
Após
o
par
de
chaves
vem
o
corpo
da
classe,
que
é
o
lugar
onde
você
define
os
métodos
que
essa
classe
implementa
(mas
você
não
os
implementa
aqui,
você
11. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
11
apenas
define
quais
são
eles).
Não
definir
um
método
aqui
normalmente
faz
com
que
não
seja
possível
pra
que
alguém
o
invoque,
é
uma
das
formas
de
se
criar
métodos
“privados”
em
Objective-‐C,
já
que
não
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
código
real
da
classe
(mesmo
que
não
tenhamos
colocado
nada
ainda
nele.
Enquanto
que
no
arquivo
“.h”
nós
havíamos
definido
a
@interface
do
código,
agora
estamos
definindo
a
@implementation.
Veja
que
aqui
não
é
mais
necessário
definir
de
qual
classe
a
nossa
classe
herda,
a
definição
fica
apenas
na
interface.
Veja
que
o
código
também
faz
um
“#import”
para
o
arquivo
“.h”,
isso
é
para
que
o
arquivo
de
implementação
possa
ver
as
informações
definidas
na
interface,
como
variáveis
de
instância
e
também
receber
automaticamente
as
dependências
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
“incluído”
duas
vezes,
um
problema
bem
comum
pra
quem
trabalha
com
C.
Vamos
agora
começar
a
realmente
escrever
código:
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
variável
de
instância
definida
(do
tipo
“float”),
declaramos
a
existência
do
método
depositar
que
recebe
um
parâmetro
do
tipo
float
e
retorna
um
BOOL,
o
boolean
da
linguagem.
Também
declaramos
o
método
“saldo”
que
vai
ser
a
forma
de
acessar
a
variável
de
instância
“saldo”.
É
possível
acessar
uma
variável
de
instância
de
uma
classe
em
Objective-‐C
diretamente
de
“fora”
da
classe,
mas
o
melhor
é
fazer
o
acesso
sempre
via
métodos
(ou
as
propriedades
que
veremos
mais
a
frente).
O
sinal
de
“-‐“
(subtração)
antes
da
definição
do
método
avisa
que
esse
é
um
método
de
instância
(métodos
de
classe
são
definidos
com
um
sinal
de
adição,
o
“+”).
O
tipo
de
retorno
e
o
tipo
dos
parâmetros
recebidos
ficam
sempre
entre
parênteses.
Um
detalhe
importante
na
declaração
de
métodos
em
Objective-‐C
é
que
o
parâmetro
fica
“dentro”
do
nome
do
método
e
não
após
a
definição
do
nome,
12. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
12
como
em
Java
ou
Ruby.
Como
o
método
depositar
recebe
um
parâmetro
é
necessário
colocar
os
“:”
para
separar
o
nome
do
parâmetro
que
está
sendo
passado,
depois
vamos
entender
um
pouco
mais
como
se
nomeiam
métodos
em
Objective-‐C.
Vejamos
então
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
código
fonte
você
já
deve
ter
entendido
exatamente
o
que
ele
faz,
se
o
valor
passado
como
parâmetro
for
maior
do
que
zero,
ele
vai
somar
com
o
valor
atual
da
variável
de
instância
“saldo”
e
retornar
YES,
que
é
um
atalho
para
o
valor
BOOL
que
representa
verdadeiro,
se
o
valor
passado
como
parâmetro
for
menor
ou
igual
a
zero
ele
simplesmente
retorna
NO.
Assim
como
em
C,
blocos
de
código
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
implementação
do
método
“saldo”
é
ainda
mais
trivial,
ela
simplesmente
retorna
o
valor
da
variável
de
instância
diretamente.
Criando
o
nosso
primeiro
teste
unitário
Com
a
nossa
classe
implementada,
agora
é
a
hora
de
escrever
um
teste
para
esse
primeiro
método
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
aplicação
final,
já
que
ela
não
precisa
levar
os
testes
consigo.
Clique
com
o
botão
direito
em
“AprendendoObjectivec”,
como
na
imagem
abaixo:
13. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
13
Imagem
9
–
Criando
o
grupo
“Test”
Com
o
grupo
criado,
clique
com
o
botão
direito
em
“Test”,
selecione
“Add”
e
“New
File”.
Você
vai
criar
uma
classe
de
teste
padrão
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:
14. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
14
Imagem
11
–
Selecionando
os
targets
da
classe
de
testes
No
caso
dos
testes,
você
normalmente
não
precisa
definir
nada
no
arquivo
“.h”,
já
que
os
métodos
são
chamados
automaticamente,
então
vamos
nos
focar
apenas
no
arquivo
“.m”,
que
é
onde
nós
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
método
que
define
a
implementação
do
teste
precisa
ter
o
seu
nome
iniciando
com
“test”
e
não
retornar
nada
(por
isso
o
void).
Na
primeira
linha
do
teste
já
temos
vários
detalhes
da
linguagem
pra
entender.
A
primeira
coisa
a
ser
percebida
é
que
a
declaração
da
variável
contém
um
“*”,
se
você
vem
do
C,
sabe
que
isso
quer
dizer
que
essa
variável
é
na
verdade
uma
referencia
(ou
ponteiro)
pra
um
objeto
que
está
em
memória.
Sempre
que
você
define
uma
referencia
pra
uma
variável
em
Objective-‐C
é
necessário
colocar
o
15. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
15
“*”,
se
você
não
o
fizer
vai
receber
warnings
do
compilador
e
o
seu
programa
não
vai
funcionar
corretamente.
Ainda
nessa
linha
temos
o
idioma
de
inicialização
de
objetos.
O
que
em
outras
linguagens
de
programação
OO
seria
feito
através
de
um
construtor,
em
Objective-‐C
se
faz
através
das
chamadas
a
“alloc”,
um
método
de
classe
que
organiza
uma
nova
instância
do
objeto
em
memória
e
retorna
o
objeto
pronto
pra
uso,
e
“init”,
que
executa
finalmente
a
inicialização
do
objeto.
É
possível
usar
também
o
método
de
classe
“new”
em
vez
do
“par”
alloc/init
para
se
criar
um
objeto,
mas
é
preferível
usar
alloc/init,
especialmente
se
você
pretende
ter
várias
formas
de
inicializar
o
seu
objeto.
Ótimo,
você
diz,
mas
o
que
diabos
são
aqueles
pares
de
colchetes
(“[]”)?
Seguindo
a
tradição
de
Smalltalk,
em
Objective-‐C
a
ideia
não
é
que
você
está
chamando
um
método
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
método
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
método
(um
objeto
Conta)
fazemos
a
chamada
do
método
“init”.
O
idioma
alloc/init
é
comum
e
pervasivo
em
toda
a
linguagem
e
exemplos
de
código
que
você
vai
encontrar,
mas
evite
fazer
chamadas
de
método
dentro
de
chamadas
de
método
no
seu
código,
a
não
ser
que
seja
um
caso
muito
simples
como
esse
que
nós
estamos
vendo
aqui.
Na
segunda
linha
do
teste
vemos
o
seguinte:
[conta depositar:200];
Nós
enviamos
a
mensagem
“depositar”
para
o
objeto
representado
pela
variável
“conta”
com
o
parâmetro
200.
Os
“:”
que
nós
usamos
na
definição
do
método
“depositar”
fazem
realmente
parte
do
nome
do
método,
sendo
obrigatório
a
sua
adição
a
chamada
(os
métodos
que
não
adicionam
“:”
são
os
que
não
recebem
parâmetros).
No
fim
temos
o
código
que
faz
a
asserção
do
teste:
STAssertTrue( [conta saldo] == 300, @"O saldo deve ser de
300 para que o teste falhe" );
Comparamos
então
o
valor
do
saldo
com
300
exatamente
porque
queremos,
nesse
primeiro
momento,
ver
o
teste
falhar.
STAssertTrue
não
é
um
método,
mas
uma
função
comum
que
você
definiria
como
uma
função
em
C,
ela
faz
parte
do
framework
de
testes
unitários
que
vem
por
padrão
dentro
do
Cocoa.
Agora
um
detalhe
importante
que
pode
passar
desapercebido
é
a
definição
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ê
16. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
16
não
está
usando
uma
string
comum
do
C,
que
é
um
array
de
caracteres,
e
sim
um
objeto
do
tipo
NSString
que
adiciona
várias
funcionalidades
as
strings
comuns
do
C.
A
maior
parte
do
código
em
Objective-‐C
que
lida
com
Strings
vai
esperar
que
você
envie
objetos
do
tipo
NSString,
então
é
bom
se
acostumar
a
escrever
primeiro
a
“@”
antes
de
declarar
um
string
no
seu
código.
Voltemos
agora
para
o
Xcode,
onde
você
vai
mudar
o
Target
padrão
para
Test,
veja
como
fazer
isso
na
imagem
abaixo:
Imagem
12
–
Alterando
o
Target
padrão
para
Test
Agora
estamos
entrando
no
modo
de
testes
do
Xcode
vamos
poder
começar
a
executar
os
testes,
mas
antes
de
fazer
isso
precisamos
dizer
para
o
Target
“Test”
onde
ele
vai
achar
a
classe
Conta,
pois
ela
não
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
17. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
17
Com
isso
feito,
podemos
finalmente
executar
o
build
do
projeto,
pra
fazer
isso
digite
“Command
+
B”.
Após
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
–
Indicação
de
erros
de
build
do
Xcode
Ao
clicar
nos
erros
você
deve
ver
a
seguinte
tela:
18. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
18
Imagem
15
–
tela
de
erros
no
build
do
Xcode
Como
você
pode
perceber,
o
erro
na
verdade
não
é
exatamente
no
build,
mas
sim
no
nosso
teste
unitário
que
falhou,
já
que
o
valor
da
variável
não
é
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
métodos
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
método
sacar
tem
a
definição
igual
a
depositar,
mas
o
método
“transferir:para:”
(veja
só
como
ele
se
chama)
deve
estar
dando
um
nó
no
seu
cérebro
nesse
momento.
Vejamos:
- (BOOL) transferir: (float) valor para: (Conta *) destino;
Em
Objective-‐C,
quando
você
tem
um
método
que
recebe
vários
parâmetros,
você
precisa
“dividir”
o
nome
do
método
em
pedaços
para
receber
os
19. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
19
parâmetros.
Então
em
vez
de
simplesmente
fazer
um
“transferir(
double
valor,
Conta
destino
)”,
como
você
faria
em
Java
ou
C#,
você
quebra
o
nome
do
método
e
transformar
ele
em
“transferir:
valor
para:
destino”.
Inicialmente
a
sintaxe
parece
estranha,
mas
a
própria
leitura
da
chamada
do
método
fica
mais
simples
e
se
você
tiver
um
método
que
recebe
vários
parâmetros
ele
com
certeza
vai
ficar
bem
mais
legível,
já
que
cada
parâmetro
vai
ter
o
seu
identificador
antes.
Vejamos
agora
como
fica
a
implementação
desses
dois
métodos:
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
código
todo
está
fazendo,
então
vamos
passar
diretamente
pros
testes,
pra
ver
esses
novos
20. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
20
métodos
sendo
exercitados.
Em
todos
os
nossos
testes
vamos,
utilizar
um
objeto
conta,
então
em
vez
de
recriar
esse
objeto
a
cada
teste,
vamos
ser
inteligentes
definir
uma
variável
de
instância
Conta
no
nosso
teste
e
implementar
o
método
“setUp”
que
cria
a
conta
para
não
repetirmos
essa
operação:
Listagem
8
–
ContaTest.h
#import <SenTestingKit/SenTestingKit.h>
@class Conta;
@interface ContaTest : SenTestCase {
Conta * conta;
}
@end
Adicionamos
a
definição
da
variável
de
instância
na
classe,
como
esperado,
mas
o
que
é
esse
“@class”
que
também
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
específico,
mas
não
vai
fazer
o
“#import”
dessa
classe
aqui,
vai
deixar
pra
importar
o
arquivo
da
classe
somente
no
seu
“.m”.
Se
você
não
colocar
o
@class
nem
o
“#import”
pra
o
arquivo
da
classe
não
vai
ser
possível
compilar
o
código.
Um
detalhe
importante
do
“#import”
é
que
quando
o
texto
que
vem
após
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
conteúdo
a
ser
importado,
quer
dizer
que
ele
deve
procurar
dentro
dos
arquivos
locais
do
projeto
(como
em
#import
"Conta.h").
Vejamos
agora
a
implementação
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" );
21. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
21
}
- (void) testDepositarComFalha {
[conta depositar:-150];
STAssertTrue( conta.saldo == 200, @"Valor do saldo não
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 não deve
ter se modificado" );
}
- (void) testSacarComValorNegativo {
[conta sacar: -100];
STAssertTrue( conta.saldo == 200, @"O saldo atual não 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" );
22. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
22
}
@end
Temos
então
vários
testes
para
a
implementação
das
funcionalidades
da
nossa
classe
conta,
eles
são
bem
simples,
mas
tem
duas
coisas
importantes
que
não
discutimos
ainda,
a
primeira
é
essa:
conta.saldo == 200
Antes,
no
nosso
teste,
fazíamos
a
chamada
assim:
[conta saldo] == 200
Em
Objective-‐C,
se
você
tem
um
método
que
não
recebe
parâmetros
e
retorna
um
valor,
esse
método
pode
ser
chamado
como
se
ele
fosse
uma
propriedade
do
seu
objeto,
sem
que
você
tenha
que
fazer
uma
invocação
explícita
do
mesmo,
então
“conta.saldo”
é
a
mesma
coisa
que
escrever
“[conta
saldo]”,
o
compilador
vai
fazer
a
mágica
de
transformar
o
primeiro
no
segundo
pra
você.
Já
o
segundo
caso:
[ conta transferir:250 para: destino ]
Aqui
nós
vemos
um
exemplo
da
chamada
do
método
“transferir:para:”,
junto
com
o
transferir
nós
temos
o
valor
que
vai
ser
transferido
e
logo
depois
de
para
temos
o
objeto
que
vai
receber
a
transferência,
veja
que
não
existem
vírgulas
separando
os
parâmetros,
eles
são
separados
normalmente
pelos
espaços
entre
os
nomes
que
formam
o
método
e
os
parâmetros
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
nós
quisermos
definir
uma
forma
personalizada?
Simples,
criamos
um
método
de
inicialização.
No
nosso
caso
queremos
poder
criar
contas
com
um
saldo
que
seja
diferente
de
zero.
Começamos
por
definir
o
método
“initWithSaldo”
em
“Conta.h”:
Listagem
10
–
Conta.h
–
declarando
o
método
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
23. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
23
Como
não
existem
construtores
realmente
dentro
da
linguagem,
o
que
nós
fazemos
é
definir
métodos
que
inicializem
o
objeto
com
o
valor
que
nos
interessa,
vejamos
a
implementação
agora
pra
entender
um
pouco
mais
o
que
está
acontecendo
e
porque
é
necessário
criar
esses
métodos:
Listagem
11
–
Conta.m
#import "Conta.h"
@implementation Conta
- (Conta *) initWithSaldo:(float)valor {
if ( self = [ self init]) {
saldo = valor;
}
return self;
}
// todo aquele código que você já viu
@end
Mais
um
caso
de
idioma
da
linguagem
surge
então
pra
nós
nesse
momento:
if ( self = [ self init]) {
Por
mais
estranho
que
pareça,
esse
código
está
realmente
atribuindo
um
valor
a
variável
“self”
(“self”
é
equivalente
ao
“this”
em
Java
e
C#,
é
uma
referência
para
o
objeto
onde
o
método
em
execução
atual
foi
chamado)
dentro
do
seu
objeto.
Mas
porque
alguém
iria
querer
fazer
isso?
Na
implementação
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
não
ser
exatamente
um
NSString,
mas
uma
subclasse
dele.
As
classes
que
nós
vemos
“do
lado
de
fora”
funcionam
apenas
como
um
meio
pra
se
acessar
as
classes
que
fazem
realmente
o
trabalho,
mas
esses
detalhes
de
implementação
ficam
escondidos
graças
a
essa
pequena
mágica
do
método
init
(atribuir
um
novo
valor
a
self
e
retornar
esse
valor).
No
caso
da
nossa
classe
não
seria
necessário
fazer
essa
mágica,
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
padrão
da
linguagem
não
se
esquecer
e
terminar
com
bugs
estranhos
no
seu
código.
Outra
coisa
importante
também
é
lembrar-‐se
de
chamar
o
método
“init”
da
sua
classe,
se
você
estiver
implementando
um
novo
inicializador
(como
nós
fazemos
nesse
código)
ou
chamar
o
método
init
da
sua
superclasse
(com
[super
init])
se
você
estiver
sobrescrevendo
o
método
“init”,
assim
você
não
perde
o
código
de
inicialização
que
já
tenha
sido
implementado
na
classe
atual
e
nas
suas
superclasses.
Definindo
propriedades
automaticamente
nos
objetos
Nós
vimos
que
o
compilador
é
inteligente
o
suficiente
pra
aceitar
que
“[conta
saldo]”
seja
chamado
como
“conta.saldo”,
mas
além
disso
nós
também
podemos
24. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
24
instruir
o
compilador
para
que
ele
gere
os
métodos
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 *) initWithSaldo: (float) valor;
- (BOOL) depositar: (float) valor;
- (BOOL) sacar: (float) valor;
- (BOOL) transferir: (float) valor para: (Conta *) destino;
@end
Nós
definimos
as
duas
variáveis
de
instância,
“agencia”
e
“conta”,
e
logo
depois
temos
as
declarações
das
propriedades,
com
“@property”:
@property (copy, nonatomic) NSString * conta;
Isso
indica
ao
compilador
que
nós
vamos
ter
os
métodos
abaixo
definidos:
-‐ (NSString
*
)
conta;
-‐ (void)
setConta:
(
NSString
*
);
As
instruções
“copy”
e
“nonatomic”
são
atributos
que
vão
ser
utilizados
na
geração
da
implementação
dos
métodos.
-‐ “copy”
indica
que
quando
um
objeto
for
recebido
como
parâmetro,
deve
ser
criada
uma
cópia
desse
objeto
e
essa
cópia
é
quem
vai
ser
atribuída
a
variável
de
instância,
isso
é
necessário
especialmente
se
você
está
recebendo
dados
da
interface,
pois
os
strings
que
vem
dela
podem
ser
recolhidos
da
memória
a
qualquer
momento
nos
ambientes
onde
não
há
coletor
de
lixo,
como
iPads
e
iPhones.
-‐ “nonatomic”
indica
que
os
métodos
gerados
não
vão
fazer
nenhum
controle
sobre
o
acesso
de
forma
concorrente.
Esse
normalmente
é
o
caso
pra
maior
parte
das
aplicações,
mas
se
você
vai
utilizar
esse
objeto
em
um
ambiente
com
concorrência,
onde
várias
threads
vão
acessar
o
mesmo
objeto
e
chamar
seus
métodos,
deve
remover
isso.
-‐ “readonly”
indica
que
apenas
o
método
“getter”,
que
lê
o
valor
da
variável,
vai
ser
gerado,
o
método
set,
que
altera
o
valor
da
variável
não
vai
ser
gerado.
25. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
25
Com
os
métodos
definidos,
agora
voltamos
pra
“Conta.m”
pra
declarar
o
código
que
vai
fazer
com
que
os
métodos
sejam
realmente
gerados,
vejamos
como
fica
o
código
agora:
Listagem
13
–
Conta.m
com
a
definição
das
propriedades
e
gerenciamento
de
memória
#import "Conta.h"
@implementation Conta
@synthesize agencia, conta, saldo;
- (void) dealloc {
[ self.agencia release ];
[ self.conta release ];
[ super dealloc ];
}
// todo o resto do código que você já conhece aqui
@end
A
mágica
de
verdade
vive
no
“@synthesize”,
ele
instrui
o
compilador
a
ler
as
informações
das
propriedades
definidas
através
de
“@property”
e
gerar
os
métodos.
Junto
com
isso
chegamos
a
um
detalhe
importante
da
programação
com
Objective-‐C,
especialmente
se
você
estiver
planejando
programar
para
iOS,
o
gerenciamento
de
memória.
Com
a
definição
das
propriedades
nós
definimos
também
o
método
“dealloc”
que
é
chamado
quando
um
objeto
vai
ser
removido
da
memória,
para
que
ele
possa
limpar
da
memória
também
os
objetos
para
os
quais
ele
aponta.
Quando
você
está
programando
em
Objective-‐C
para
iOS,
não
existe
um
coletor
de
lixo
automático,
liberar
a
memória
é
responsabilidade
do
programador,
então
é
necessário
que
você
tome
cuidado
para
não
vazar
memória
no
seu
código
e
estourar
a
memória
do
dispositivo.
Em
Objective-‐C
o
controle
de
memória,
quando
não
é
feito
através
do
coletor
de
lixo,
acontece
através
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
vês
que
você
chama
“release”
(como
em
“[objeto
release]”)
o
contador
diminui
em
1.
Quando
o
contador
de
referencias
atingir
0,
o
objeto
é
removido
da
memória.
No
nosso
caso,
as
propriedades
“conta”
e
“agencia”
são
definidas
como
“copy”,
isso
quer
dizer
que
o
objeto
que
vai
ser
colocado
na
variável
de
instância
vai
ser
clonado
e
o
clone
é
o
objeto
que
vai
finalmente
ficar
disponível
para
a
nossa
classe.
Como
o
clone
é
um
objeto
recém-‐criado
com
base
em
outro
objeto
a
sua
contagem
de
referencias
é
1
(um),
o
que
quer
dizer
que
quando
chamarmos
“release”
neles,
eles
vão
ser
removidos
da
memória.
Pra
limpar
a
memória
que
estamos
usando,
precisamos
ajustar
o
nosso
teste
para
fazer
o
“release”
dos
objetos
conta
que
estão
sendo
criados.
Vamos
fazer
o
26. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
26
release
da
variável
de
instância
conta
no
método
tearDown
e
da
conta
destino
em
cada
um
dos
testes,
vejamos
o
que
muda
na
nossa
classe
teste:
Listagem
14
–
ContaTest.m
com
o
código
de
gerenciamento
de
memória
@implementation ContaTest
//métodos não mostrados aqui não 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
27. Curso
de
desenvolvimento
de
aplicações
para
iOS
usando
Objective-‐C
Maurício
Linhares
27
Adicionamos
a
nossa
implementação
o
método
“tearDown”
que
envia
um
“release”
para
o
objeto
conta
e
também
fazemos
o
release
dos
objetos
destino
criados
nos
testes
de
transferência.
Você
nunca
deve
chamar
o
método
dealloc
diretamente
nos
seus
objetos,
sempre
chame
release
e
deixe
que
o
próprio
runtime
do
Objective-‐C
vai
fazer
a
chamada
a
dealloc
quando
for
a
hora
correta.
É
possível
definir
algumas
regrinhas
básicas
na
hora
de
lidar
com
a
gerência
de
memória
em
aplicações
escritas
em
Objective-‐C:
• Se
você
pegou
um
objeto
através
de
“alloc/new/copy”,
esse
objeto
tem
um
contador
de
1
e
você
deve
se
lembrar
de
liberar
esse
objeto
quando
ele
não
for
mais
necessário;
• 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á,
não
faça
nada
com
ele,
quem
passou
ele
pra
você
provavelmente
vai
limpá-‐lo
quando
for
necessário.
• 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
não
vai
ser
liberado
da
memória.
• Sempre
que
você
dá
“retain”
em
um
objeto,
deve
garantir
que
vai
dar
um
“release”
nele
em
algum
momento,
se
você
não
der
o
“release”,
com
certeza
vai
estar
vazando
memória
na
sua
aplicação;
Gerenciamento
de
memória
é
um
tópico
longo
e
vamos
nos
aprofundar
mais
nele
conforme
avançamos
para
a
construção
das
nossas
aplicações
para
iOS,
essa
introdução
é
apenas
para
que
você
entenda
o
básico
de
como
esse
conceito
funciona
dentro
da
linguagem.