27
Curso de desenvolvimento de aplicações para iOS usando ObjectiveC Maurício Linhares 1 Desenvolvendo aplicações para iOS usando ObjectiveC Maurício Linhares [email protected] DESENVOLVIMENTO DE APLICAÇÕES PARA IOS USANDO OBJECTIVEC 1 INTRODUÇÃO 2 CAPÍTULO 1CONHECENDO OBJECTIVEC 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 OBJECTIVEC 8 IMAGEM 7–CRIANDO A NOSSA PRIMEIRA CLASSE EM OBJECTIVEC 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 “TEST13 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.MEM 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 CONSTRUTORPARA 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

Curso de desenvolvimento de aplicações para iOS com Objective-C

Embed Size (px)

DESCRIPTION

Primeira versão do material do curso de desenvolvimento de aplicações para iOS usando Objective-C.

Citation preview

Page 1: Curso de desenvolvimento de aplicações para iOS com Objective-C

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  [email protected]    

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    

   

Page 2: Curso de desenvolvimento de aplicações para iOS com Objective-C

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.  

   

Page 3: Curso de desenvolvimento de aplicações para iOS com Objective-C

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:  

Page 4: Curso de desenvolvimento de aplicações para iOS com Objective-C

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:  

Page 5: Curso de desenvolvimento de aplicações para iOS com Objective-C

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:  

Page 6: Curso de desenvolvimento de aplicações para iOS com Objective-C

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”.  

Page 7: Curso de desenvolvimento de aplicações para iOS com Objective-C

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:  

Page 8: Curso de desenvolvimento de aplicações para iOS com Objective-C

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’”:  

Page 9: Curso de desenvolvimento de aplicações para iOS com Objective-C

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

Page 10: Curso de desenvolvimento de aplicações para iOS com Objective-C

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ê  

Page 11: Curso de desenvolvimento de aplicações para iOS com Objective-C

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,  

Page 12: Curso de desenvolvimento de aplicações para iOS com Objective-C

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:  

Page 13: Curso de desenvolvimento de aplicações para iOS com Objective-C

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:  

Page 14: Curso de desenvolvimento de aplicações para iOS com Objective-C

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  

Page 15: Curso de desenvolvimento de aplicações para iOS com Objective-C

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ê  

Page 16: Curso de desenvolvimento de aplicações para iOS com Objective-C

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  

 

Page 17: Curso de desenvolvimento de aplicações para iOS com Objective-C

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:  

Page 18: Curso de desenvolvimento de aplicações para iOS com Objective-C

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  

Page 19: Curso de desenvolvimento de aplicações para iOS com Objective-C

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  

Page 20: Curso de desenvolvimento de aplicações para iOS com Objective-C

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" );

Page 21: Curso de desenvolvimento de aplicações para iOS com Objective-C

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" );

Page 22: Curso de desenvolvimento de aplicações para iOS com Objective-C

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

Page 23: Curso de desenvolvimento de aplicações para iOS com Objective-C

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  

Page 24: Curso de desenvolvimento de aplicações para iOS com Objective-C

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.  

Page 25: Curso de desenvolvimento de aplicações para iOS com Objective-C

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  

Page 26: Curso de desenvolvimento de aplicações para iOS com Objective-C

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

Page 27: Curso de desenvolvimento de aplicações para iOS com Objective-C

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.