Introdução à programação em Android e iOS - OOP em ObjC
-
Upload
luis-gustavo-martins -
Category
Technology
-
view
1.450 -
download
3
description
Transcript of Introdução à programação em Android e iOS - OOP em ObjC
Programação Orientada a Objectos (OOP) - Parte 2: ObjC
Jorge C. S. Cardoso, Luís Gustavo [email protected], [email protected]
Cursos de Verão na Católica 2010
Classe Veículo em ObjCDivisão do código em duas partes:
1. Interface■ declarada num ficheiro Veiculo.h
2. Implementação■ definida num ficheiro Veiculo.m
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
Classe Veículo em ObjCInterface - Veiculo.h
O ObjC "obriga" ao uso de getters e setters
--> Encapsulamento!
#import <Foundation/Foundation.h>
@interface Veiculo : NSObject { // instance variables int velMax; int velActual; int numRodas; int numLugares;}//setters and getters- (void) setVelMax: (int)vel;- (int) velMax;- (void) setVelActual: (int)vel;- (int) velActual;- (void) setNumRodas: (int)numRodas;- (int) numRodas;- (void) setNumLugares: (int)numLugares;- (int) numLugares;// other method declarations- (void) arrancar;- (void) travar;- (void) acelerar;- (void) buzinar;- (BOOL) estaParado;- (void) mostrarEstado;@end
Classe Veículo em ObjCImplementação - Veiculo.m#import "Veiculo.h"
@implementation Veiculo
//setter and getters-(int)velMax { return velMax;}-(void) setVelMax: (int)vel { velMax = vel;}//... similar for other setter/getters
//other methods-(void) arrancar { //implementação do método arrancar...}
-(void) travar { // ...}
//... other methods...
@end
● Implementar setters/getters● Implementar métodos
Getters e setters podem ser criados automaticamente... - properties - synthesize
Classe Veículo em ObjCUso de Properties e Synthesized Getters e Setters
#import <Foundation/Foundation.h>
@interface Veiculo : NSObject { // instance variables int velMax; int velActual; int numRodas; int numLugares;}//setters and getters- (void) setVelMax: (int)vel;- (int) velMax;- (void) setVelActual: (int)vel;- (int) velActual;- (void) setNumRodas: (int)numRodas;- (int) numRodas;- (void) setNumLugares: (int)numLugares;- (int) numLugares;// other method declarations- (void) arrancar;- (void) travar;- (void) acelerar;- (void) buzinar;- (BOOL) estaParado;- (void) mostrarEstado;@end
#import <Foundation/Foundation.h>
@interface Veiculo : NSObject { // instance variables int velMax; int velActual; int numRodas; int numLugares;}//properties@property velMax;@property velActual;@property numRodas, numLugares;
// other method declarations- (void) arrancar;- (void) travar;- (void) acelerar;- (void) buzinar;- (BOOL) estaParado;- (void) mostrarEstado;@end
Classe Veículo em ObjCUso de Properties e Synthesized Getters e Setters
#import "Veiculo.h"
@implementation Veiculo
//setter and getters-(int)velMax { return velMax;}-(void) setVelMax: (int)vel { velMax = vel;}//... similar for other setter/getters
//other methods-(void) arrancar { //implementação do método arrancar...}
-(void) travar { // ...}
//... other methods...
@end
#import "Veiculo.h"
@implementation Veiculo
//synthesized setter and getters@synthesize velMax;@synthesize velActual:@synthesize numRodas;@synthesize numLugares;
//other methods-(void) arrancar { //implementação do método arrancar...}
-(void) travar { // ...}
//... other methods...
@end
Classe Veículo em ObjCUso de Properties e Synthesized Getters e Setters
● É possível alterar o comportamento do setter sintetizado para uma variável membra, usando modificadores
Num setter do tipo:
-(void) setVar: (SomeClass *)value
Se o sintetizarmos com os seguintes modificadores, teremos no corpo do setter (sintetizado) as seguintes atribuições:
@property (assign) var
var = value; //simple assignation
@property (retain) var var = [value retain]; //assignation with reference counter increment
@property (copy) var
var = [value copy]; //object is copied (must conform to the NSCopying protocol...)
Herança em ObjC● O ObjC suporta herança simples
○ ou seja, uma classe apenas pode herdar de uma classe pai■ Tal como o Java (outras linguagens, como o C++, suportam herança
múltipla)○ Em vez de herança multipla, o ObjC suposta o uso de "categories" e
"protocols" (semelhantes às "interfaces" do Java)■ http://developer.apple.
com/iphone/library/documentation/cocoa/conceptual/objectivec/Articles/ocCategories.html■ http://developer.apple.com/iphone/library/documentation/cocoa/conceptual/objectivec/Articles/ocProtocols.
html#//apple_ref/doc/uid/TP30001163-CH15-SW1
NSObject
• Root class
• Implements many basics
■ Memory management ■ Introspection ■ Object equality
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
ObjC: Métodos de Classe e de Instância
● Instâncias respondem a métodos de instância: - (id) init; - (void) setVelMax: (int) vel; - (int) velMax; - (void) travar; ...
● Classes respondem a métodos de classe: + (id) alloc; + (id) Veiculo; + (Veiculo *) sharedVeiculo; ...
ObjC: Mensagens para Objectos● Em ObjC, em vez de se "chamar" métodos de objectos
(como em Java ou C++), enviam-se "mensagens"
○ Sintaxe: [receiver message]
[receiver message:argument]
[receiver message:arg1 andArg:arg2]
● Exemplos: Veiculo *meuVeiculo; //assume this exists...
[meuVeiculo trava];
[meuVeiculo setVelMax:300] //you wish!! ;-)[meuVeiculo vira:90 andPiscaPisca:YES];
int speed = [meuVeiculo velActual];
ObjC: Mensagens para Objectos● O "Dot-Syntax"
○ O ObjC 2.0 introduziu uma outra forma de se aceder a variáveis membras de um objecto
○ O dot-syntax faz uso dos setters e getters!!■ Não quebra o ENCAPSULAMENTO!!
Veiculo *meuVeiculo; //assume this exists...
int speed1 = [meuVeiculo velActual]; //messageint speed2 = meuVeiculo.velActual; //dot syntax
[meuVeiculo setVelActual: 120]; //messagemeuVeiculo.velActual = 60; //dot syntax
ObjC: Mensagens para Objectos● O "Dot-Syntax" - Um problema frequente...
○ O que é que acontece quando o seguinte código executa?
@implementation Person - (void)setAge:(int)newAge { //setter self.age = newAge; //age é uma variável membra } @end
○ É equivalente a: @implementation Person - (void)setAge:(int)newAge { //setter [self setAge:newAge]; // Infinite loop! } @end
ObjC: self e super● self - mensagens para o próprio Objecto
● super - mensagens para o "pai" do Objecto
#import "Veiculo.h"
@implementation Veiculo
-(BOOL) isFamilyVehicle { return ([self numLugares] >= 4);}
//other method implementations...
-(void) doSomething { //call superclass implementation first... [super doSomething]; //now do our own stuff... int foo = bar; //... }
ObjC: tipos dinâmicos e estáticos● Objectos com tipos dinâmicos
○ id anObject; ■ apenas id e não id*
■ a não ser que se saiba o que se está a fazer...■ tipo genérico: pode ser usado para apontar para qualquer
objecto
● Objectos com tipos estáticos
○ Veiculo *meuVeiculo;
● O ObjC implementa verificação de tipos em compile-time (e não em run-time)
● O ObjC usa sempre "dynamic binding"
ObjC: ciclo de vida de objectos● Criação de Objectos
○ Processo de dois passos:■ alocar memória para o objecto: +alloc■ inicializar o estado do objecto: -init
■ ConstrutorVeiculo *meuVeiculo = nil;meuVeiculo = [[Veiculo alloc] init];#import "Veiculo.h"
@implementation Veiculo
-(id)init { // allow superclass to initialize its state first if (self = [super init]) { velMax = 120; velActual = 0; numRodas = 4; numLugares = 4; } return self;} @end
ObjC: ciclo de vida de objectos● Criação de Objectos - Métodos init (construtores)
○ Uma classe pode definir múltiplos métods init■ -(id) init; ■ -(id) initWithVelMax:(int) vel; ■ -(id) initWithVelMax:(int) vel velActual:(int) vel;■ ...
○ Métodos menos específicos chamam tipicamente métodos mais específicos usando valores por omissão:
-(id) init {return [self initWithVelMax: 120];}
-(id) initWithVelMax:(int) vel { return [self initWithVelMax:vel velActual:0];}
ObjC: ciclo de vida de objectos● Destruição de Objectos
○ Depois de criado com com alloc (normalmente seguido de init), e no caso de não mais ser necessário, um objecto deve ser "limpo" da memória!
■ Para cada alloc deverá haver um dealloc■ caso contrário criam-se "fugas de memória"!!
■ No entanto, dealloc nunca é chamado directamente!■ com uma excepção (ver mais à frente...)■ existe um mecanismo para "desalocar" sem chamar dealloc ...■ REFERENCE COUNTING
ObjC: ciclo de vida de objectos● Destruição de Objectos
○ REFERENCE COUNTING
■ Todos os objectos implementam um "retain count"■ Herdado de NSObject■ enquanto o "retain count" > 0, objectivo é mantido em
memória e válido
■ +alloc e -copy criam objectos com "retain count" == 1■ -retain incrementa o "retain count"■ -release decrementa o "retain count"
■ Quando o "retain count" atinge o valor 0 o objecto é destruído!■ -dealloc é chamado automaticamente■ Ponto de não retorno!
ObjC: ciclo de vida de objectos● Destruição de Objectos - REFERENCE COUNTING
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
ObjC: ciclo de vida de objectos● Destruição de Objectos
Veiculo *meuVeiculo = nil;
meuVeiculo = [[Veiculo alloc] init];
[meuVeiculo setVelMax:120];[meuVeiculo arranca];[meuVeículo setVelActual: 50];//...[meuVeiculo para];
//no more need for this object...[meuVeiculo release];
//meuVeiculo will be destroyed in case its retain//count is zero (i.e. no one else is pointing to it)//And in that case, sending messages to it will CRASH![meuVeiculo arranca];//CRASH!!
ObjC: ciclo de vida de objectos● Destruição de Objectos
Veiculo *meuVeiculo = nil;
meuVeiculo = [[Veiculo alloc] init];
[meuVeiculo setVelMax:120];[meuVeiculo arranca];[meuVeículo setVelActual: 50];//...[meuVeiculo para];
//no more need for this object...[meuVeiculo release];
meuVeiculo = nil; //good programming practice!
[meuVeiculo arranca];//No longer crashes!:-) No effect...
ObjC: ciclo de vida de objectos● Destruição de Objectos - Destrutor
○ Implementação do método -dealloc
#import "Veiculo.h"
@implementation Veiculo
-dealloc { //this is an override of NSObject dealloc //do any cleanup that is necessary... //...
//when done, ask super to also clean itself up [super dealloc]; //only time you call dealloc explicitly!}
//other method implementations...
@end
ObjC: a classe NSString● �Suporte genérico para strings Unicode
○ Unicode é um sistema de codificação de caracteres que suporta todas as linguagens do mundo
● Consistentemente usada na API Cocoa e Cocoa Touch○ em prejuízo das C-strings (i.e. char *)○ sem dúvida uma das classes mais usadas em Cocoa
● Em ObjC, "constant strings" são definidas como:
@“just as simple”
● E "constant strings" são na realidade instâncias de NSString NSString *aString = @”Hello World!”;
ObjC: a classe NSString● Formatação de Strings
○ Semelhante ao usado em Java e C++ (e.g. printf)■ %d - para ints■ %f - para floats■ %c - para chars■ etc...■ %@ - para objectos!! --> ObjC
NSString *aString = @”Johnny”; NSString *log = [NSString stringWithFormat: @”It’s ‘%@’”, aString]; //log would have been set to: "It’s ‘Johnny’"
NSLog(@”I am a %@, I have %d items”, [array className], [array count]); //Would print: "I am a NSArray, I have 5 items"
ObjC: apontadores nulos - nil● Apontadores em ObjC podem ser nulos:
int *numberPtr = nil;
● Testando um apontador nulo, explicitamente:
if (numberPtr == nil) {return;}
● Testando um apontador nulo, implicitamente:
if (!numberPtr) {return;}
● Podem ser usados em atribuições ou argumentos: numberPtr = nil; [myCalculator setValue: nil];
● Pode-se enviar mensagens para nil (são ignoradas...): myObject = nil; [myObject doSomething];
ObjC: Identidade versus Igualdade entre Objectos
● Identidade○ Teste da igualdade dos respectivos apontadores○ "É o mesmo Objecto?"
if (object1 == object2) {NSLog(@"Same exact object instance");}
● Igualdade○ Teste da igualdade dos atributos (i.e. variáveis membras de cada objecto)○ "Os Objectos têm o mesmo conteudo?"
if ([object1 isEqual: object2]) { NSLog(@"Logically equivalent, but may be different object instances"); }
ObjC: reponsabilidade pela vida de Objectos#import <Foundation/Foundation.h>
@interface Veiculo : NSObject {
// instance variables NSString *marca; //Veiculo class “owns” the NSString object 'marca' int velMax; //... }
// method declarations- (void)init; - (NSString *)marca; - (void)setMarca:(NSString *)novaMarca; - (int)velMax;- (void)setVelMax:(int)vel;//... @end
ObjC: reponsabilidade pela vida de Objectos
#import "Veiculo.h"
@implementation Veiculo
-(id)init { // allow superclass to initialize its state first if (self = [super init]) { marca = @"não definida"; //this is a NSString velMax = 120; velActual = 0; numRodas = 4; numLugares = 4; } return self;}
//other method implementations... @end
ObjC: reponsabilidade pela vida de Objectos#import "Veiculo.h"
@implementation Veiculo
- (NSString *)marca { return marca;}
- (void)setMarca:(NSString *)novaMarca { marca = novaMarca; //!!! memory leak!!} @end
● Se marca apontasse para uma NSString já existente (e.g. alocada no construtor init da classe Veiculo) essa zona de memória ficaria "em fuga"...
Setter para um objecto criado pelo nosso objecto
Solução 1 (errada)
ObjC: reponsabilidade pela vida de Objectos#import "Veiculo.h"
@implementation Veiculo
- (NSString *)marca { return marca;}
- (void)setMarca:(NSString *)novaMarca { [marca release]; //what if marca == novaMarca?!? marca = novaMarca;} @end
● Se por acaso novaMarca apontasse para a mesma NSString que marca aponta (pode acontecer!!), ao fazer release do apontador marca correria-se o risco de o retain counter cair para zero, e a NSString ser destruida!!
○ perder-se-ia a string que se pretendia usar para passar para o nosso objecto!!
Setter para um objecto criado pelo nosso objecto
Solução 2 (ainda errada)
ObjC: reponsabilidade pela vida de Objectos#import "Veiculo.h"
@implementation Veiculo
- (NSString *)marca { return marca;}
- (void)setMarca:(NSString *)novaMarca { if (marca != novaMarca) { [marca release]; marca = [novaMarca retain]; // marca’s retain count has been bumped up by 1 }} @end ● Antes de tudo verifica-se se por acaso não estamos a receber um
apontador para um objecto NSString para o qual já estamos a apontar
○ Caso não seja, liberta-se o objecto anterior e aponta-se para o que é passado como argumento
Setter para um objecto criado pelo nosso objecto
Solução 3a (CORRECTA!)
ObjC: reponsabilidade pela vida de Objectos#import "Veiculo.h"
@implementation Veiculo
- (NSString *)marca { return marca;}
- (void)setMarca:(NSString *)novaMarca { if (marca != novaMarca) { [marca release]; marca = [novaMarca copy]; // marca’s retain count has been bumped up by 1 }} @end ● Neste caso não copiamos apenas o apontador...
○ É criada uma cópia do objecto!!■ Evita que alterações na string por alguém que partilhe
apontadores para a "nossa" NSString marca■ Na realidade, como o objecto NSString é imutável,
esse problema não se coloca...
Setter para um objecto criado pelo nosso objecto
Solução 3b (CORRECTA!)
ObjC: reponsabilidade pela vida de Objectos
#import "Veiculo.h"
@implementation Veiculo
//...-(void) dealloc { //do any clean up that is needed... [marca release];
//ask super to do its own clean up [super dealloc]; } @end
● Se alocamos... temos de "desalocar"!!○ Caso contrário provocamos uma "fuga de memória" (memory leak)
Oh Yeah! Embrace the power!! ;-)
ObjC: reponsabilidade pela vida de Objectos
#import "Veiculo.h"
@implementation Veiculo
//...-(NSString *) descricao {
NSString *descricao;
descricao = [[NSString alloc] initWithFormat:@"Veículo de %d rodas, com %d lugares...", [self numRodas], [self numLugares]);
//remember: [NSString alloc] above bumps the retain count (i.e. +1)!
return descricao; } @end
● Retornar um objecto...
● ERRADO! fuga de memória!○ [NSString alloc] incrementa o retain count...○ Mas em lado algum é feito o correspondente release!
ObjC: reponsabilidade pela vida de Objectos
#import "Veiculo.h"
@implementation Veiculo
//...-(NSString *) descricao {
NSString *descricao;
descricao = [[NSString alloc] initWithFormat:@"Veículo de %d rodas, com %d lugares...", [self numRodas], [self numLugares]); //remember: [NSString alloc] above bumps the retain count (i.e. +1)!
[descricao release]; //will this fix the memory leak? Yes... but we return bogus... :-\
return descricao; } @end
● Retornar um objecto...
● ERRADO! Retorna um apontador para um objecto inválido!○ [NSString alloc] incrementa o retain count...○ O release decrementa-o para zero
■ dealloc é chamado... objecto é destruído■ Como resolver?!?!
ObjC: reponsabilidade pela vida de Objectos
#import "Veiculo.h"
@implementation Veiculo
//...-(NSString *) descricao {
NSString *descricao;
descricao = [[NSString alloc] initWithFormat:@"Veículo de %d rodas, com %d lugares...", [self numRodas], [self numLugares]); //remember: [NSString alloc] above bumps the retain count (i.e. +1)!
[descricao autorelease]; //nice! ;-)
return descricao; } @end
● Retornar um objecto...
● CORRECTO!○ É feito o release ao objecto, mas não imediatamente...
■ Dá-se assim tempo ao código que chamou o método de receber o apontador para um objecto que (ainda é válido!) e de logo a seguir fazer um retain
○ Quando é então feito o "autorelease"??!
ObjC: reponsabilidade pela vida de Objectos● O autorelease de Objectos
○ chamando -autorelease "marca" um objecto para ser enviado um release num momento futuro...
○ Cumpre-se com o requisito de "emparelhar" cada alloc com um release
■ Dando algum tempo ao objecto para sobreviver
○ Forma conveniente de gerir memória■ muito útil em métodos que retornam objectos!
ObjC: reponsabilidade pela vida de Objectos● O autorelease e nomes de métodos
○ Métodos cujos nomes comecem por alloc, copy ou new devolvem (i.e. retornam) objectos com retain count == 1
■ É necessário fazer release quando o objecto não for mais necessário!!
○ Todos os outros métodos devolvem (i.e. retornam) objectos autoreleased (é apenas uma convenção!!)
NSMutableString *string = [[NSMutableString alloc] init]; // We are responsible for calling -release or -autorelease [string autorelease];
NSMutableString *string = [NSMutableString string]; // The method name doesn’t indicate that we need to release it // So don’t- we’re cool!
ObjC: reponsabilidade pela vida de Objectos● Como funciona o autorelease?
○ Objectos são adicionados a um "autorelease pool"
○ Este "autorelease pool" monitoriza objectos "marcados" para serem libertados (i.e. released)
■ Quando a própria "autorelease pool" é libertada, todos os objectos por ela monitorizados são também libertados (i.e. released)
○ Quando é a "autorelease pool" libertada??
ObjC: reponsabilidade pela vida de Objectos● Como funciona o autorelease?
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
ObjC: reponsabilidade pela vida de Objectos● Como funciona o autorelease?
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
ObjC: reponsabilidade pela vida de Objectos● Como funciona o autorelease?
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
ObjC: reponsabilidade pela vida de Objectos● Como funciona o autorelease?
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
ObjC: reponsabilidade pela vida de Objectos● Como funciona o autorelease?
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
ObjC: reponsabilidade pela vida de Objectos● Como funciona o autorelease?
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
ObjC: reponsabilidade pela vida de Objectos● Como funciona o autorelease?
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
ObjC: reponsabilidade pela vida de Objectos● Como funciona o autorelease?
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
ObjC: reponsabilidade pela vida de Objectos● Como funciona o autorelease?
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
ObjC: reponsabilidade pela vida de Objectos● Como funciona o autorelease?
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
ObjC: reponsabilidade pela vida de Objectos● E não se corre o risco de "a qualquer momento" um objecto
criado com autorelease com ficar inválido e não poder usar um apontador para ele??
○ Nesse caso, há que fazer retain!
name = [NSMutableString string]; //autoreleased
// We want to name to remain valid! [name retain];
// ...
// Eventually, we’ll release it (maybe in our -dealloc?) [name release];
NOTA: autorelease não é Garbage Collection!!
Exercício: Classe Calculator e Fraction● Implementar em ObjC uma classe Fraction:
○ armazena fracções (i.e. numerador / denominador)○ imprime a fracção para a consola○ realiza operações (+, -, *, /) entre fracções
#import <Foundation/Foundation.h>#import "Fraction.h"int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];Fraction *frac1 = [[Fraction alloc] init]; Fraction *frac2 = [[Fraction alloc] init];[frac1 setTo: 1 over: 3];[frac1 print]; //print to console something like "1/3" [frac2 setTo: 5 over: 4];
Fraction* result = [frac1 add: frac2]; //adds two fractions [result print];[frac1 release]; [frac2 release]; [result release][pool drain];return 0;}
Fim
Cursos de Verão na Católica 2010http://porto.ucp.pt/cvc/
Jorge C. S. Cardoso, Luís Gustavo [email protected], [email protected]
http://slideshare.net/jorgecardoso (tag: cvc2010)
Código fonte: http://db.tt/AOFOfA2