A Computational Framework for Sound Segregation in Music Signals using Marsyas
ObjC Classe Veículo
1. Programação Orientada a Objectos
(OOP) - Parte 2: ObjC
Cursos de Verão na Católica 2010
Jorge C. S. Cardoso, Luís Gustavo Martins
jorgecardoso@ieee.org, lmartins@porto.ucp.pt
2. Classe Veículo em ObjC
Divisã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
3. Classe Veículo em ObjC
#import <Foundation/Foundation.h>
Interface - Veiculo.h
@interface Veiculo : NSObject {
// instance variables
int velMax;
int velActual;
int numRodas;
int numLugares;
}
//setters and getters
O ObjC "obriga" ao uso de getters e setters - (void) setVelMax: (int)vel;
- (int) velMax;
- (void) setVelActual: (int)vel;
--> Encapsulamento! - (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
4. Classe Veículo em ObjC
Implementação - Veiculo.m
#import "Veiculo.h"
@implementation Veiculo
//setter and getters
-(int)velMax {
return velMax;
}
-(void) setVelMax: (int)vel {
velMax = vel; ● Implementar setters/getters
}
//... similar for other setter/getters ● Implementar métodos
//other methods
-(void) arrancar {
Getters e setters podem ser
//implementação do método arrancar... criados automaticamente...
} - properties
-(void) travar { - synthesize
// ...
}
//... other methods...
@end
5. Classe Veículo em ObjC
Uso de Properties e Synthesized Getters e Setters
#import <Foundation/Foundation.h>
#import <Foundation/Foundation.h>
@interface Veiculo : NSObject {
// instance variables @interface Veiculo : NSObject {
int velMax; // instance variables
int velActual; int velMax;
int numRodas; int velActual;
int numLugares; int numRodas;
} int numLugares;
//setters and getters }
- (void) setVelMax: (int)vel; //properties
- (int) velMax; @property velMax;
- (void) setVelActual: (int)vel; @property velActual;
- (int) velActual; @property numRodas, numLugares;
- (void) setNumRodas: (int)numRodas;
- (int) numRodas; // other method declarations
- (void) setNumLugares: (int)numLugares; - (void) arrancar;
- (int) numLugares; - (void) travar;
// other method declarations - (void) acelerar;
- (void) arrancar; - (void) buzinar;
- (void) travar; - (BOOL) estaParado;
- (void) acelerar; - (void) mostrarEstado;
- (void) buzinar; @end
- (BOOL) estaParado;
- (void) mostrarEstado;
@end
6. Classe Veículo em ObjC
Uso de Properties e Synthesized Getters e Setters
#import "Veiculo.h" #import "Veiculo.h"
@implementation Veiculo @implementation Veiculo
//setter and getters //synthesized setter and getters
-(int)velMax { @synthesize velMax;
return velMax; @synthesize velActual:
} @synthesize numRodas;
-(void) setVelMax: (int)vel { @synthesize numLugares;
velMax = vel;
} //other methods
//... similar for other setter/getters -(void) arrancar {
//implementação do método arrancar...
//other methods }
-(void) arrancar {
//implementação do método arrancar... -(void) travar {
} // ...
}
-(void) travar {
// ... //... other methods...
}
@end
//... other methods...
@end
7. Classe Veículo em ObjC
Uso 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...)
8. 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
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
9. 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;
...
10. 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];
11. 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
Veiculo *meuVeiculo; //assume this exists...
int speed1 = [meuVeiculo velActual]; //message
int speed2 = meuVeiculo.velActual; //dot syntax
[meuVeiculo setVelActual: 120]; //message
meuVeiculo.velActual = 60; //dot syntax
○ O dot-syntax faz uso dos setters e getters!!
■ Não quebra o ENCAPSULAMENTO!!
12. 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
13. ObjC: self e super
● self - mensagens para o próprio Objecto
#import "Veiculo.h"
@implementation Veiculo
-(BOOL) isFamilyVehicle {
return ([self numLugares] >= 4);
}
//other method implementations...
● super - mensagens para o "pai" do Objecto
-(void) doSomething {
//call superclass implementation first...
[super doSomething];
//now do our own stuff...
int foo = bar;
//...
}
14. 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"
15. 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
■ Construtor
Veiculo *meuVeiculo = nil;
#import "Veiculo.h" meuVeiculo = [[Veiculo alloc] init];
@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
16. 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];
}
17. 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
18. 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!
19. ObjC: ciclo de vida de objectos
● Destruição de Objectos - REFERENCE COUNTING
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
20. 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!!
21. 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...
22. 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
23. 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!”;
24. 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"
25. 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];
26. 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");
}
27. 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
28. 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
29. ObjC: reponsabilidade pela vida de Objectos
#import "Veiculo.h" Setter para um objecto criado pelo
nosso objecto
@implementation Veiculo Solução 1 (errada)
- (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"...
30. ObjC: reponsabilidade pela vida de Objectos
#import "Veiculo.h" Setter para um objecto criado pelo
nosso objecto
@implementation Veiculo Solução 2 (ainda errada)
- (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!!
31. ObjC: reponsabilidade pela vida de Objectos
#import "Veiculo.h"
Setter para um objecto criado pelo
@implementation Veiculo nosso objecto
Solução 3a (CORRECTA!)
- (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
32. ObjC: reponsabilidade pela vida de Objectos
#import "Veiculo.h"
Setter para um objecto criado pelo
@implementation Veiculo
nosso objecto
Solução 3b (CORRECTA!)
- (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...
33. ObjC: reponsabilidade pela vida de Objectos
● Se alocamos... temos de "desalocar"!!
○ Caso contrário provocamos uma "fuga de memória" (memory leak)
#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
Oh Yeah! Embrace the power!! ;-)
34. ObjC: reponsabilidade pela vida de Objectos
● Retornar um objecto...
#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
● ERRADO! fuga de memória!
○ [NSString alloc] incrementa o retain count...
○ Mas em lado algum é feito o correspondente release!
35. ObjC: reponsabilidade pela vida de Objectos
● Retornar um objecto...
#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
● 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?!?!
36. ObjC: reponsabilidade pela vida de Objectos
● Retornar um objecto...
#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
● 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"??!
37. 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!
38. 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!!
NSMutableString *string = [[NSMutableString alloc] init];
// We are responsible for calling -release or -autorelease
[string autorelease];
○ Todos os outros métodos devolvem (i.e. retornam) objectos
autoreleased (é apenas uma convenção!!)
NSMutableString *string = [NSMutableString string];
// The method name doesn’t indicate that we need to release it
// So don’t- we’re cool!
39. 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??
40. ObjC: reponsabilidade pela vida de Objectos
● Como funciona o autorelease?
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
41. ObjC: reponsabilidade pela vida de Objectos
● Como funciona o autorelease?
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
42. ObjC: reponsabilidade pela vida de Objectos
● Como funciona o autorelease?
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
43. ObjC: reponsabilidade pela vida de Objectos
● Como funciona o autorelease?
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
44. ObjC: reponsabilidade pela vida de Objectos
● Como funciona o autorelease?
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
45. ObjC: reponsabilidade pela vida de Objectos
● Como funciona o autorelease?
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
46. ObjC: reponsabilidade pela vida de Objectos
● Como funciona o autorelease?
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
47. ObjC: reponsabilidade pela vida de Objectos
● Como funciona o autorelease?
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
48. ObjC: reponsabilidade pela vida de Objectos
● Como funciona o autorelease?
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
49. ObjC: reponsabilidade pela vida de Objectos
● Como funciona o autorelease?
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-winter
50. 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!!
51. 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;
}
52. Fim
Cursos de Verão na Católica 2010
http://porto.ucp.pt/cvc/
Jorge C. S. Cardoso, Luís Gustavo Martins
jorgecardoso@ieee.org, lmartins@porto.ucp.pt
http://slideshare.net/jorgecardoso (tag: cvc2010)
Código fonte: http://db.tt/AOFOfA2