Você está na página 1de 175

!"!

#
INSTITUTO DE ARTES INTERATIVAS

!"!#
INSTITUTO DE ARTES INTERATIVAS
!"!#
INSTITUTO DE ARTES INTERATIVAS

iPhone SDK
Mdulo 3
!"!#
INSTITUTO DE ARTES INTERATIVAS

XML
Leitura de XML com NSXMLParser
O que so arquivos XML? !"!#
INSTITUTO DE ARTES INTERATIVAS

UM FORMATO UNIVERSAL PARA ARMAZENAR


DADOS, J USADO E DIFUNDIDO EM LARGA
ESCALA NA WEB

<biblioteca> CHAMAMOS ESTE ELEMENTO DE TAG


<livro>
<titulo>Anjos e Demnios</titulo>
<autor>Dan Brown</autor>
</livro>
ESTE O CONTEDO DA TAG AUTOR!
</biblioteca>

A BARRA / INDICA UM FIM DE TAG


XML e iPhone !"!#
INSTITUTO DE ARTES INTERATIVAS

Muitas vezes utilizamos este formato para


receber dados do servidor.
O iPhone j tem um biblioteca para leitura
relativamente rpido para ler (mais
rpido que plist, menos que sql)
NSXMLParser !"!#
INSTITUTO DE ARTES INTERATIVAS

Mtodos mais usados

// Cria um novo NSXMLParser utilizando um XML


// tranformado em NSData
- (id)initWithData:(NSData *)data;

// Define quem ser o objeto delegate, o que


// ser chamado enquanto a classe l o
// documento XML
- (void)setDelegate:(id <NSXMLParserDelegate>)
delegate;

// Inicia a ler o documento


- (BOOL)parse;
NSXMLParserDelegate !"!#
INSTITUTO DE ARTES INTERATIVAS

Protoclo que define os mtodos disparados


pelo Parser enquanto est lendo o arquivo
Contm mtodos para cada situao que o
parser encontrar enquanto pesquisa o XML

ENCONTREI UM ELEMENTO INICIANDO

<livro> ENCONTREI TEXTO


<titulo>Anjos e Demnios</titulo>
<autor>Dan Brown</autor>
</livro> ENCONTREI UM ELEMENTO FINALIZANDO
NSXMLParserDelegate !"!#
INSTITUTO DE ARTES INTERATIVAS

ENCONTREI UM ELEMENTO INICIANDO

- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName ...

ENCONTREI TEXTO

- (void)parser:(NSXMLParser *)parser
foundCharacters:(NSString *)string

ENCONTREI UM ELEMENTO FINALIZANDO

- (void)parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName ...
Prtica !"!#
INSTITUTO DE ARTES INTERATIVAS

Nosso leitor acessar um xml com dados


fictcios da bolsa de valores

<stocks>
<data>
<date>13/09/2009</date>
<max>29.99</max>
<min>22.80</min>
<open>25.4</open>
<close>23.9</close>
.xml </data>
<data>
<date>14/09/2009</date>
<max>32.99</max>
<min>21.80</min>
<open>26.4</open>
<close>27.9</close>
</data>
</stocks>
Criando o projeto !"!#
INSTITUTO DE ARTES INTERATIVAS

Inicie um novo projeto


no XCode, selecionando
a opo Navigation
Based Aplication

D a ele o nome
de XMLParser
Adicionando a classe XMLParser !"!#
INSTITUTO DE ARTES INTERATIVAS

Adicione ao projeto um novo


arquivo no folder Classes

Faa um arquivo do tipo Objective-C class


subclasse de NSObject

Nomei-o como XMLParser.m


Este ser nosso leitor de XML!
Configurando o Header !"!#
INSTITUTO DE ARTES INTERATIVAS

Altere o documento XMLParser.h de modo que


tenha estas variveis:
XMLParser.h
#import <Foundation/Foundation.h>

@interface XMLParser : NSObject <NSXMLParserDelegate>{


! NSXMLParser *nsparser;
! NSString *currentTag;
! NSMutableString *currentValue;
NSMutableDictionary *currentData;
! NSMutableArray *values;
}

@end

Precisaremos das variveis auxiliares: currentTag, currentValue,


currentData e values. Na sequncia: para armazenar o nome da
tag atual, para armazenar os dados da tag conforme o parser caminha
pelo arquivo, para armazenar um dicionrio de um grupo de dados e
para guardar todos valores obtidos em um vetor.
Iniciando o parser !"!#
INSTITUTO DE ARTES INTERATIVAS

Escreva o mtodo init da classe XMLParser:


CRIA UM NSDATA A PARTIR DO XMLParser.m

NSData *data = [[NSData alloc]


ENDEREO DO ARQUIVO XML
initWithContentsOfURL:
[NSURL URLWithString:
@"http://iai.art.br/escola/iphonesdk3/stocks.xml"]];

values = [[NSMutableArray alloc] init];

INICIA O VETOR ONDE SERO ARMAZENADOS OS DADOS

nsparser = [[NSXMLParser alloc] initWithData:data];

UTILIZA O NSDATA PARA CRIAR O NOSSO NSXMLPARSER!

[data release];
Definindo o delegate !"!#
INSTITUTO DE ARTES INTERATIVAS

Continuando o mtodo init da classe XMLParser:

XMLParser.m

[nsparser setDelegate:self];
!!
DIZ PARA O NOSSO OBJETO PARSER QUE ESTA CLASSE O DELEGATE, OU
SEJA, QUEM TER DE TRATAR AS MENSAGENS QUE nsparser GERA

[nsparser parse];

FINALMENTE, INICIA O PARSER, NESTE


PONTO O XML SER LIDO
Recebendo o contedo !"!#
INSTITUTO DE ARTES INTERATIVAS

Precisamos agora adicionar os mtodos que recebero os


dados vindos do parser. Primeiro o mtodo que chamado
quando h uma tag iniciando:
XMLParser.m

- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName attributes:
(NSDictionary *)attributeDict{
ESTE MTODO SER CHAMADO SEMPRE QUE O
PARSER ENCONTRAR UMA TAG ABRINDO!
}

Vamos adicionar um NSLog para testar se nossa funo est se


comportando como deveria. Dentro do mtodo, adicione:
XMLParser.m
NSLog(@"abriu o elemento: %@", elementName);
Recebendo o contedo !"!#
INSTITUTO DE ARTES INTERATIVAS

Agora o mtodo que ser chamado quando houver uma


tag fechando:
XMLParser.m
- (void)parser:(NSXMLParser *)parser didEndElement:
(NSString *)elementName namespaceURI:(NSString *)
namespaceURI qualifiedName:(NSString *)qName{
NSLog(@"fechou o elemento: %@", elementName);
}

E o mtodo para quando achamos texto:


XMLParser.m

- (void)parser:(NSXMLParser *)parser
foundCharacters:(NSString *)string{
! NSLog(@"achou texto: %@", string);
}
Nossa classe fica assim: !"!#
INSTITUTO DE ARTES INTERATIVAS

INICIALIZAO

LEITURA DO XML
Testando os mtodos !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos testar nosso parser! No RootViewController, importe a


nossa classe recm criada:
RootViewController.h
#import <UIKit/UIKit.h>
#import "XMLParser.h"

@interface RootViewController : UITableViewController {

Neste mesmo arquivo, crie uma varivel do tipo XMLParser


dentro da interface RootViewController, assim:
RootViewController.m

@interface RootViewController : UITableViewController {


180

! XMLParser *parser;
}

@end
Testando os mtodos !"!#
INSTITUTO DE ARTES INTERATIVAS

Agora que temos nossa varivel declarada no Header (.h) vamos


inici-la no arquivo RootViewController.m, dentro do
mtodo viewDidLoad RootViewController.m

- (void)viewDidLoad { DESCOMENTE O MTODO viewDidLoad


E ADICIONE ESTA LINHA
[super viewDidLoad];
parser = [[XMLParser alloc] init];
}

Pronto! J podemos testar!


CLIQUE EM BUILD AND GO

E VEJA NO CONSOLE O RESULTADO!


Testando os mtodos !"!#
INSTITUTO DE ARTES INTERATIVAS

Se voc est conectado a internet e tudo est em seu lugar


neste momento voc ver os logs que geramos no parser. Isso
significa que o arquivo j foi lido corretamente!

ESTES SO NOSSOS LOGS! : )

PERCEBA QUE O PARSER ENCONTRA


AT AS STRINGS DE PULA LINHA!
Prximo passo! !"!#
INSTITUTO DE ARTES INTERATIVAS

J sabemos que nosso parser funciona, agora o que queremos


o resultado que ele gera, para isso vamos guardar os dados lidos
por ele em um vetor. Isso ser feito em 4 passos. Primeiro:
XMLParser.m

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName


namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict{

! NSLog(@"abriu o elemento: %@", elementName); ... E, CASO A TAG SEJA data,


! INICIAMOS A VARIVEL QUE
! currentTag = elementName; GUARDAR SEUS VALORES:
GUARDAMOS O NOME DA TAG ATUAL... currentData

! if ([currentTag isEqualToString:@"data"]) {
! ! currentData = [[NSMutableDictionary alloc] init];
! }else if([currentTag isEqualToString:@"stocks"] == NO){
! ! currentValue = [[NSMutableString alloc] init];
! }
!
} CASO SEJA QUALQUER OUTRA (exceto a raiz stocks),
INICIAMOS currentValue
Armazenando os valores !"!#
INSTITUTO DE ARTES INTERATIVAS

Segundo: agora devemos armazenar todos caracteres encontrados,


com exceo dos que esto nas tags stocks e data.
XMLParser.m
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
! NSLog(@"achou texto: %@", string);
!
! ! if (![currentTag isEqualToString:@"data"] && currentTag != nil &&
! ! ![currentTag isEqualToString:@"stocks"] ) {
! ! [currentValue appendString:string];
! }
! ADICIONAMOS EM currentValue O TEXTO ENCONTRADO
}

As tags data e stocks no armazenam caracteres, apenas agrupam


outras tags! Por isso aqui s armazenamos o contedo das outras
tags do documento.
Criando o vetor de resultado !"!#
INSTITUTO DE ARTES INTERATIVAS

Terceiro passo: finalmente, quando uma tag fechada, analisamos


qual elemento e atuamos da maneira mais apropriada
XMLParser.m

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName


namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
! NSLog(@"fechou o elemento: %@", elementName);
!
[currentTag release];! AQUI A TAG TERMINA, ENTO PRECISAMOS ANULAR
A REFERNCIA CONTIDA EM currentTag
currentTag = nil;

! if ([elementName isEqualToString:@"data"]) {
! ! [values addObject:currentData];

ADICIONAMOS O DADO CAPTURADO PELO DICIONRIO AO VETOR

! }else if([elementName isEqualToString:@"stocks"] == NO){


! ! [currentData setObject:currentValue forKey:elementName];
! }
} CASO SEJA UMA DAS TAGS INTERNAS, O VALOR ENCONTRADO,
currentValue, SER ARMAZENADO EM currentData
Definindo o acesso ao resultado !"!#
INSTITUTO DE ARTES INTERATIVAS

Quarto e ltimo passo: provemos um meio de acesso aos valores.


Crie a assinatura deste novo mtodo em XMLParser.h
XMLParser.h
! NSMutableString *currentValue;
! NSMutableDictionary *currentData;
! NSMutableArray *values;
}

-(NSArray*) getXMLValues;

@end

Agora adicione o mtodo que retorna a array, assim:


XMLParser.m

-(NSArray*) getXMLValues{
! return [NSArray arrayWithArray:values];
}
Recebendo os dados no ViewController !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos voltar ao view controller e adicionar uma varivel do tipo


NSArray para acessar os resultados em um table view.
RootViewController.h
@interface RootViewController : UITableViewController {
! XMLParser *parser;
! NSArray *values;
}

@end

E referenciar os resultados do parser nela! Faremos isto logo aps


iniciar nosso parser, no mtodo viewDidLoad
RootViewController.m

[super viewDidLoad];
! parser = [[XMLParser alloc] init];
! values = [[parser getXMLValues] retain];

TEMOS QUE RETER ESTA VARIVEL, ASSIM PODEREMOS UTILIZ-LA EM TODA NOSSA CLASSE
Configurando o Table View !"!#
INSTITUTO DE ARTES INTERATIVAS

Agora faa o seguinte: configure a sua tabela para que o nmero


de linhas seja igual ao nmero de objetos contidos na varivel
values.
RootViewController.m
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
if(values != nil) return [values count];
! return 0;
} NOS CERTIFICAMOS QUE O VETOR values J CONTM UM OBJETO VALIDO!

Tambm altere a cell para que tenha o estilo


UITableViewCellStyleSubtitle em cellForRowAtIndexPath
RootViewController.m
bleViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle: UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier] autorelease];
Adicionando o textLabel !"!#
INSTITUTO DE ARTES INTERATIVAS

O ltimo passo configurar o texto da clula no mesmo mtodo.


Vamos mostrar cada linha como um dia, e nos detalhes dizer ao
usurio se este foi um dia de baixa ou de alta.
RootViewController.m
! // Configure the cell.
! BUSCAMOS O VALOR A PARTIR DO indexPath
! NSDictionary *value =
(NSDictionary*)[values objectAtIndex:indexPath.row];
!
cell.textLabel.text = [value objectForKey:@"date"];
!
! float open = [[value objectForKey:@"open"] floatValue];
! float close = [[value objectForKey:@"close"] floatValue];
!
VALOR DE ABERTURA E FECHAMENTO CONVERTIDOS EM FLOAT
!
if(open > close){
! ! cell.detailTextLabel.text = @"baixa";
! }else if(open < close){ ANALISE SE HOUVE
! ! cell.detailTextLabel.text = @"alta"; UMA ALTA OU UMA BAIXA
! }else {
! ! cell.detailTextLabel.text = @"estvel";
! }
Exerccios !"!#
INSTITUTO DE ARTES INTERATIVAS

Com isto terminamos de


implementar nosso XMLParser!

Exerccios
1) Tente criar uma nova view para
mostrar em detalhes o dia, com os
valores de abertura, fechamento,
mximo e mnimo. Empilhe esta view
quando uma das clulas for selecionada

2) Procure na internet imagens de


setas para cima e para baixo e as use
para indicar alta ou baixa no dia!
!"!#
INSTITUTO DE ARTES INTERATIVAS

SQLITE
Banco de dados SQL Built-in
Porque usar SQLITE? !"!#
INSTITUTO DE ARTES INTERATIVAS

EM ALGUMAS SITUAES PRECISAMOS SALVAR


UMA GRANDE QUANTIDADE DE DADOS E LOGO
EM SEGUIDA BUSCAR, AGRUPAR E ORDENAR
ESTAS INFORMAES

Para isso temos esta ferramenta: o Banco de dados!


Quais so as vantagens? !"!#
INSTITUTO DE ARTES INTERATIVAS

SQLite j est embutido no SDK.

a maneira mais rpida de buscar dados quando o


volume de informaes grande.

Sua estrutura organizada e bem definida.


Classe padro no Iphone !"!#
INSTITUTO DE ARTES INTERATIVAS

O SQLite no iphone composto por vrias


funes de C, como sqlite3_open, por
exemplo. Todas sempre comeando com o
prfixo sqlite3. Veja alguns exemplos:

sqlite3_open ABRE UMA CONEXO COM O BANCO DE DADOS

sqlite3_exec EXECUTA UM TRECHO DE SCRIPT SQL

sqlite_column_int RECUPERA UM VALOR INT DO RESULTADO


Prtica !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos fazer uma agenda para guardar


contatos, com telefone, cidade e email.
Criando o projeto !"!#
INSTITUTO DE ARTES INTERATIVAS

Inicie um novo projeto


no XCode, selecionando
a opo Navigation
Based Aplication

D a ele o nome
de SQLiteAgenda
Pr-requisitos !"!#
INSTITUTO DE ARTES INTERATIVAS

Lembre-se sempre de incluir em todos


arquivos que utilizam o sqlite o header:
#import "sqlite3.h"
Alm disso, inclua tambm o framework

ADICIONE O FRAMEWORK libsqlite3.dylib


Script inicial !"!#
INSTITUTO DE ARTES INTERATIVAS

Escreva este script inicial, que segue nosso diagrama


entidade-relacionamento

start_script

CREATE TABLE IF NOT EXISTS Friends(


! id INTEGER PRIMARY KEY,
! name TEXT,
! phone TEXT,
! email TEXT,
! city TEXT
);
Criar o banco !"!#
INSTITUTO DE ARTES INTERATIVAS

Primeiro, precisamo criar o banco de dados.


Vamos fazer isso pelo Terminal
Abrir o sql e rodar o script de incializao
Adicionar o arquivo ao nosso projeto
Criar objeto Contato !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos manipular um array de contatos em nosso


aplicativo.
Para isso criamos uma sub-classe de NSObject para
armazenar cada item do banco
@interface Contato : NSObject {
int idContat;
! NSString* name;
! NSString* phone;
! NSString* email;
! NSString* city;
}
@property(nonatomic,assign)int idContat;
@property(nonatomic,retain)NSString* name;
@property(nonatomic,retain)NSString* phone;
@property(nonatomic,retain)NSString* email;
@property(nonatomic,retain)NSString* city;

-(id)initWithID:(int)umId andName:(NSString*)umName andPhone:(NSString*)umPhone


andEmail:(NSString*)umEmail andCity:(NSString*)umCity;

@end
Criar um objeto para os dados !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos manipular um array de contatos em nosso


aplicativo.
Para isso criamos uma sub-classe de NSObject para
armazenar cada item do banco
Inicializar o objeto !"!#
INSTITUTO DE ARTES INTERATIVAS

Criar o mtodo de inicializao do objeto


@implementation Contato

@synthesize idContat, name, phone, email, city;

-(id)initWithID:(int)umId andName:(NSString*)umName andPhone:(NSString*)umPhone


andEmail:(NSString*)umEmail andCity:(NSString*)umCity {

if ((self = [super init])) {


self.idContat = umId;
self.name = umName;
self.phone = umPhone;
self.email = umEmail;
self.city = umCity;
}
return self;
}

-(void)dealloc {
[name release];
[phone release];
[email release];
[city release];
}

@end
AppDelegate - gerencia o banco !"!#
INSTITUTO DE ARTES INTERATIVAS

No AppDelegate.h, criamos as nossas variveis,


properiedades e mtodos que vamos usar no nosso
aplicativo
SQLiteAgendaAppDelegate.h
#import <UIKit/UIKit.h>
#import "sqlite3.h"
#import "Contato.h"

@interface SQLiteAgendaAppDelegate : NSObject <UIApplicationDelegate> {


UIWindow *window;
UINavigationController *navigationController;
NSString* databasePath;
NSMutableArray* contatosArray;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
@property (nonatomic, retain) NSMutableArray* contatosArray;

-(void)iniciarBancoDeDados;
-(void)atualizarComDadosDoBanco;
-(NSMutableArray*)arrayFiltradoComQuery:(NSString*)query;
-(void)adicionarItemAoBanco:(Contato*)oContato;

@end
Banco - copiar para Documents !"!#
INSTITUTO DE ARTES INTERATIVAS

No AppDelegate, criar um mtodo que copia o banco do


bundle para o Documents directory
SQLiteAgendaAppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:
(NSDictionary *)launchOptions {

[window addSubview:navigationController.view];
[window makeKeyAndVisible];
[self iniciarBancoDeDados];
[self atualizarComDadosDoBanco];
return YES;
}

-(void)iniciarBancoDeDados {
contatosArray = [[NSMutableArray alloc] init];
databasePath = [[NSHomeDirectory() stringByAppendingPathComponent:@"Documents/
Agenda.sql"] retain];

! if ([[NSFileManager defaultManager] fileExistsAtPath:databasePath])


return;

! NSString* pathBundle = [[NSBundle mainBundle] pathForResource:@"Agenda"


ofType:@"sql"];

! [[NSFileManager defaultManager] copyItemAtPath:pathBundle toPath:databasePath


error:nil];! !
}
Atualizando o array !"!#
INSTITUTO DE ARTES INTERATIVAS

Criar um mtodo que re-popula o nosso array de


Contatos.
Primeio criamos as variaveis do banco e criamos um
statement - uma query SQLiteAgendaAppDelegate.m

-(void)atualizarComDadosDoBanco {
// Inicializo o objeto do banco
! sqlite3* database;

! // Remover todos os itens


! [contatosArray removeAllObjects];

! // Abrir o banco
! if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {

! ! // Criar a chamada SQL e verificar se esta valida


! ! const char *sqlStatement = "SELECT * from Friends";

! ! sqlite3_stmt *compiledStatement;
! ! // Se tudo ok, vamos varrer o banco
! ! if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement,
NULL) == SQLITE_OK) { .......
Atualizando o array - continua !"!#
INSTITUTO DE ARTES INTERATIVAS

Percorrer por todas as linhas do banco, criar um


Contato e adicionar ao array SQLiteAgendaAppDelegate.m
...
! ! if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement,
NULL) == SQLITE_OK) {
! ! ! // Chamar cada item do banco e adiciona-los ao array
! ! ! while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
! ! ! ! // Read the data from the result row
! ! ! ! int oId = (int)sqlite3_column_int(compiledStatement, 0);
! ! ! ! NSString *aName = [NSString stringWithUTF8String:(char *)
sqlite3_column_text(compiledStatement, 1)];
! ! ! ! NSString *aPhone = [NSString stringWithUTF8String:(char *)
sqlite3_column_text(compiledStatement, 2)];
! ! ! ! NSString *aEmail = [NSString stringWithUTF8String:(char *)
sqlite3_column_text(compiledStatement, 3)];
! ! ! ! NSString *aCity = [NSString stringWithUTF8String:(char *)
sqlite3_column_text(compiledStatement, 4)];
! ! ! !
! ! ! ! // Criar o objeto Contato e adiconar ao array
! ! ! ! Contato *oContato = [[Contato alloc] initWithID:oId andName:aName
andPhone:aPhone andEmail:aEmail andCity:aCity];
! ! ! ! [contatosArray addObject:oContato];
! ! ! ! [oContato release];
! ! ! }
! ! }
Atualizando o array - final !"!#
INSTITUTO DE ARTES INTERATIVAS

Finalizar as variaveis do sql


SQLiteAgendaAppDelegate.m
! ! // Tirar o compiledStatement de memria
! ! sqlite3_finalize(compiledStatement);
! !
! }
! // Fechar o banco
! sqlite3_close(database);

}
Query no banco !"!#
INSTITUTO DE ARTES INTERATIVAS

Criar mtodo que retorna um array com os resultados


de uma query SQL
Ele igual ao mtodo anteriro com algumas pequenas
alteraes
SQLiteAgendaAppDelegate.m
-(NSMutableArray*)arrayFiltradoComQuery:(NSString*)query {

NSMutableArray* arrayFiltrado = [NSMutableArray array];

// Inicializo o objeto do banco


! sqlite3* database;

! // Abrir o banco
! if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
! ! // Criar a chamada SQL e verificar se esta valida
! ! const char *sqlStatement = [query
cStringUsingEncoding:NSUTF8StringEncoding];
! ! sqlite3_stmt *compiledStatement;
! ! if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL)
== SQLITE_OK) {
Query no banco - continua !"!#
INSTITUTO DE ARTES INTERATIVAS

Usar o string recebido e adicionar objetos ao array


temporrio.
SQLiteAgendaAppDelegate.m
! ! ! !
! ! ! ! // Criar o objeto Contato passando os parametros do banco para ele
! ! ! ! Contato *oContato = [[Contato alloc] initWithID:oId andName:aName
andPhone:aPhone andEmail:aEmail andCity:aCity];
! ! ! !
! ! ! ! // Adicionar o objeto Animal ao array de Animals
! ! ! ! [arrayFiltrado addObject:oContato];
! ! ! !
! ! ! ! [oContato release];
! ! ! }
! ! }
else {
// Retornar vazio se a query for invalida
return nil;
}
! ! // Tirar o compiledStatement de memria
! ! sqlite3_finalize(compiledStatement);
! }
! // Fechar o banco
! sqlite3_close(database);

//Retornar resultado
return arrayFiltrado;
Adicionar item no banco !"!#
INSTITUTO DE ARTES INTERATIVAS

Criar um mtodo que recebe o Contato e o adiciona no


banco
SQLiteAgendaAppDelegate.m
-(void)adicionarItemAoBanco:(Contato*)oContato {
!sqlite3 *dataBase;
! if (sqlite3_open([databasePath UTF8String], &dataBase) == SQLITE_OK){
! ! const char *sqlStatement = "INSERT INTO Friends (name, phone, email, city) VALUES
(?, ?, ?, ?)";
! ! sqlite3_stmt *compiledStatement;
! ! if(sqlite3_prepare_v2(dataBase, sqlStatement, -1, &compiledStatement, NULL) ==
SQLITE_OK) {
! ! ! sqlite3_bind_text(compiledStatement, 1, [oContato.name UTF8String] , -1,
SQLITE_TRANSIENT);
! ! ! sqlite3_bind_text(compiledStatement, 2, [oContato.phone UTF8String] , -1,
SQLITE_TRANSIENT);
! ! ! sqlite3_bind_text(compiledStatement, 3, [oContato.email UTF8String] , -1,
SQLITE_TRANSIENT);
! ! ! sqlite3_bind_text(compiledStatement, 4, [oContato.city UTF8String] , -1,
SQLITE_TRANSIENT);
! ! ! sqlite3_step(compiledStatement);
! ! }
! ! sqlite3_finalize(compiledStatement);
! }
! sqlite3_close(dataBase);
! [self atualizarComDadosDoBanco];
}
Remove item do banco !"!#
INSTITUTO DE ARTES INTERATIVAS

Criar um mtodo que recebe o Contato e o remove do


banco
SQLiteAgendaAppDelegate.m
-(void)removerItemDoBanco:(Contato*)oContato {
sqlite3 *dataBase;
!
! if (sqlite3_open([databasePath UTF8String], &dataBase) == SQLITE_OK){
! !
! ! const char *sqlStatement = "DELETE FROM Friends WHERE id = ?";
! ! sqlite3_stmt *compiledStatement;
! ! if(sqlite3_prepare_v2(dataBase, sqlStatement, -1, &compiledStatement, NULL)
== SQLITE_OK) {
! ! ! sqlite3_bind_int(compiledStatement, 1, oContato.idContat);
! ! ! sqlite3_step(compiledStatement);
! ! }
! ! sqlite3_finalize(compiledStatement);
! }
! sqlite3_close(dataBase);
!
! [self atualizarComDadosDoBanco];

}
Criando a tela de cadastro !"!#
INSTITUTO DE ARTES INTERATIVAS

J temos as funes do banco. Vamos montar uma tela


para criar novos contatos

ENTRE AS CLASSE COCOA

ESCOLHA VIEWCONTROLER

E LEMBRE-SE DE INCLUIR O XIB

O NOME DO ARQUIVO SER


NovoContatoViewController
Campos da tela de cadastro !"!#
INSTITUTO DE ARTES INTERATIVAS

Configure a tela
NovoContatoViewController.xib, crie e
conecte os IBOutlets e declare que essa
classe vai implementar os mtodos do text
field.

NovoContatoViewController.h
#import <UIKit/UIKit.h>
#import "SQLiteAgendaAppDelegate.h"
#import "Contato.h"

@interface NovoContatoViewController :
UIViewController <UITextFieldDelegate>{

IBOutlet UITextField* nomeField;


IBOutlet UITextField* phoneField;
IBOutlet UITextField* emailField;
IBOutlet UITextField* cidadeField;
}

-(void)salvarContato;
NovoContatoViewController.xib
Boto de adicionar Contato !"!#
INSTITUTO DE ARTES INTERATIVAS

No viewDidLoad do RootViewController adicionamos um boto na


direita do navigationController

Colocar o campo de nome como foco do aplicativo, assim j exibindo


o teclado
NovoContatoViewController.m
#import "NovoContatoViewController.h"

@implementation NovoContatoViewController

- (void)viewDidLoad {
[super viewDidLoad];

self.title = @"Contatos";

UIBarButtonItem* salvarButton = [[UIBarButtonItem alloc] initWithTitle:@"Salvar"


style:UIBarButtonItemStylePlain target:self action:@selector(salvarContato)];
self.navigationItem.rightBarButtonItem = salvarButton;
[salvarButton release];

[nomeField becomeFirstResponder];

}
Mtodo de salvar !"!#
INSTITUTO DE ARTES INTERATIVAS

Aqui pegamos o AppDelegate para usar os mtodos de banco de


dados dele.
NovoContatoViewController.m

-(void)salvarContato {

Contato* novoContato = [[Contato alloc] initWithID:nil andName:nomeField.text


andPhone:phoneField.text andEmail:emailField.text andCity:cidadeField.text];

SQLiteAgendaAppDelegate* appDelegate = (SQLiteAgendaAppDelegate*)[[UIApplication


sharedApplication] delegate];

[appDelegate adicionarItemAoBanco:novoContato];

[novoContato release];
}
Administrando o teclado !"!#
INSTITUTO DE ARTES INTERATIVAS

Fazer o primeiro campo ficar ativo no inicio da tela

Quando usurio apertar o enter, vai para o prximo campo

NovoContatoViewController.m

-(BOOL) textFieldShouldReturn:(UITextField *)textField {

if (textField == nomeField)
[phoneField becomeFirstResponder];
if (textField == phoneField)
[emailField becomeFirstResponder];
if (textField == cidadeField)
[nomeField becomeFirstResponder];
}
Exibindo os dados !"!#
INSTITUTO DE ARTES INTERATIVAS

De volta ao RootViewController, vamos declarar algumas


variveis e mtodos necessrios

#import <UIKit/UIKit.h> RootViewController.h


#import "NovoContatoViewController.h"

@interface RootViewController : UITableViewController {

UISegmentedControl* filtroSegment;
NSMutableArray* arrayTabela;
}

-(void)filtrarConteudo:(UISegmentedControl*)segmento;

@end
Editando a lista !"!#
INSTITUTO DE ARTES INTERATIVAS

De volta ao RootViewController, vamos adicionar um boto para


abrir a nossa tela de NovoContato e um para editar a tabela, e um
segmented controll para filtrar o contedo
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"Contatos"; RootViewController.m

UIBarButtonItem* addButton = [[UIBarButtonItem alloc]


initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector
(adicionarContato)];
self.navigationItem.leftBarButtonItem = addButton;
[addButton release];

self.navigationItem.rightBarButtonItem = self.editButtonItem;

NSArray* segmentosArray = [NSArray arrayWithObjects:@"Todos",@"Email",nil];


filtroSegment = [[UISegmentedControl alloc] initWithItems:segmentosArray];
filtroSegment.segmentedControlStyle = UISegmentedControlStyleBar;
filtroSegment.selectedSegmentIndex = 0;
[filtroSegment addTarget:self action:@selector(filtrarConteudo:)
forControlEvents:UIControlEventValueChanged];
self.navigationItem.titleView = filtroSegment;

arrayTabela = [[NSMutableArray alloc] init];

[self filtrarConteudo:filtroSegment];
}
Filtrar o contedo !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos exibir todos os contatos ou somente aqueles que tem email

Vamos utilzar este mtodo sempre para atualizar a interface no


viewWillAppear por exemplo
-(void)filtrarConteudo:(UISegmentedControl*)segmento { RootViewController.m

[arrayTabela removeAllObjects];

SQLiteAgendaAppDelegate* appDelegate = (SQLiteAgendaAppDelegate*)[[UIApplication


sharedApplication] delegate];

if (segmento.selectedSegmentIndex == 0) {
[arrayTabela addObjectsFromArray:appDelegate.contatosArray];
}
else {
NSMutableArray* filteredArray = [appDelegate arrayFiltradoComQuery:@"SELECT * FROM
Friends WHERE email <> ''"];
[arrayTabela addObjectsFromArray:filteredArray];
}
[self.tableView reloadData];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self filtrarConteudo:filtroSegment];
}
Montar tabela para exibir contatos !"!#
INSTITUTO DE ARTES INTERATIVAS

Implementar mtodos do table view data source e delegate com o


array de contatos que esta no AppDelegate
RootViewController.m
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

return [arrayTabela count];


}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)
indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier] autorelease];
}

Contato* oContato = [arrayTabela objectAtIndex:indexPath.row];

cell.textLabel.text = oContato.name;
cell.detailTextLabel.text = oContato.email;

return cell;
}
Removendo contatos !"!#
INSTITUTO DE ARTES INTERATIVAS

Implementar mtodo do delegate do table view para remover o


item do banco e do array da tabela.
RootViewController.m

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {


return YES;
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)


editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

if (editingStyle == UITableViewCellEditingStyleDelete) {

SQLiteAgendaAppDelegate* appDelegate = (SQLiteAgendaAppDelegate*)[[UIApplication


sharedApplication] delegate];
Contato* oContato = [arrayTabela objectAtIndex:indexPath.row];
[appDelegate removerItemDoBanco:oContato];
[arrayTabela removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
}
}
!"!#
INSTITUTO DE ARTES INTERATIVAS

Core Graphics
API de grficos 2D para iPhone
Porque utilizar o Core Graphics? !"!#
INSTITUTO DE ARTES INTERATIVAS

Vrias aplicaes necessitam de processamento de


imagens em tempo de execuo. Pense por exemplo
no grfico da bolsa de valores

NESTE CASO O GRFICO TEM DE


SER CRIADO A CADA CASO, POIS
OS VALORES MUDAM TODOS OS
DIAS. PARA ISSO UTILIZAMOS
FERRAMENTAS COMO CORE
GRAPHICS!

fonte: UOL Economia


Porque utilizar o Core Graphics? !"!#
INSTITUTO DE ARTES INTERATIVAS

Outro exemplo de utilizao: tratamento de imagens!

Com Core Graphics podemos acessar cada um dos


pixels da imagem e, com isso, transform-los.

NESTE EXEMPLO APLICADO O EFEITO SPIA NA


IMAGEM, QUE RETIRA O CANAL DE COR AZUL E
REALA OS CANAIS VERMELHO E VERDE
No iPhone !"!#
INSTITUTO DE ARTES INTERATIVAS

Voc j deve ter observado por objetos pertencentes ao


Framework CoreGraphics, que usa o prefixo CG, pelo
menos uma vez. Por exemplo CGPoint, que pertence
ao CoreGraphics.

Alm do CGPoint, o CoreGraphics define muitas outras


estruturas e tambm alguns mtodos, todos em C.

CGContextFillRect AQUI EST UM EXEMPLO DE FUNO DO C.G. EM C,


UTILIZADA PARA DESENHAR UM RETNGULO NA TELA.
Como ter acesso ao CG !"!#
INSTITUTO DE ARTES INTERATIVAS

Para fazer nosso primeiro exemplo vamos precisar


acessar o Contexto de desenho do CG.

Para isto precisaremos de uma UIView hospedeira e


em seguida, capturar este contexto.

Sempre que vamos desenhar algo com Core Graphics precisamos de um


contexto, uma varivel do tipo CGContext, que vai informar ao CG
quem o destino, onde sero aplicados os comandos de desenho. Pode
ser, por exemplo, uma UIView ou ento um bitmap!
Eixos no CoreGraphics !"!#
INSTITUTO DE ARTES INTERATIVAS

UIKit Core Graphcis

x
Ordem de desenho !"!#
INSTITUTO DE ARTES INTERATIVAS

Quando trabalhamos com CG precisamos ficar atentos


a ordem que as coisas so feitas, pois isso altera o
resultado!

COR VERMELHO; COR VERMELHO;


DESENHA QUADRADO; DESENHA QUADRADO;
COR AZUL; COR VERDE;
DESENHA QUADRADO; DESENHA QUADRADO;
COR VERDE; COR AZUL;
DESENHA QUADRADO; DESENHA QUADRADO;
Prtica !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos fazer um relgio analgico utilizando


Core Graphics!
Criando o projeto !"!#
INSTITUTO DE ARTES INTERATIVAS

Inicie um novo ViewBasedApplication, d a


ele o nome de CGRelogio.
Criando um Custom View !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos dar a ela o nome de UIViewRelogio.


Configurando o XIB !"!#
INSTITUTO DE ARTES INTERATIVAS

Na lista de arquivos do projeto, clique duas


vezes no CGRelogioViewController.xib e
edite-o deste modo:

1 . SELECIONE A VIEW

2 . ABRA A TAB IDENTITY

3. PREENCHA O CAMPO CLASS COM O NOME


DA NOSSA CLASSE UIViewRelogio!

CGRelogioViewController.xib

Quando alteramos a Class do objeto, dizemos ao Interface Builder que


este item no apenas uma UIView, mas sim a nossa classe customizada.
Capturando o contexto !"!#
INSTITUTO DE ARTES INTERATIVAS

Voltando a implementao, encontre o mtodo


de desenho, descomente-o e adicione a linha a
seguir:
UIViewRelogio.m
// An empty implementation adversely affects performance du
- (void)drawRect:(CGRect)rect {
// Drawing code

! CGContextRef cgref = UIGraphicsGetCurrentContext();

Este cdigo captura o contexto, com esta varivel agora vamos poder
informar ao Core Graphics quem o destino dos comandos de desenho.
Desenhando um quadraro !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos desenhar um quadrado na tela. Assim


podemos conferir se as ligaes esto okay e
que o Core Graphics tem acesso a tela.
UIViewRelogio.m
// Drawing code

! CGContextRef cgref = UIGraphicsGetCurrentContext();

! CGContextSetRGBFillColor(cgref, 0.5, 0.5, 0.9, 1);

! CGContextFillRect(cgref, CGRectMake(10, 10, 80, 80));


}

Este cdigo captura o contexto, com est varivel podemos informar


ao Core Graphics quem o destino dos comandos de desenho.
Teste seu aplicativo !"!#
INSTITUTO DE ARTES INTERATIVAS

Execute e veja o resultado!


Desenhamos um quadrado na tela
com apenas 3 linhas de CG. Agora
vamos partir para conceitos mais
avanados.

10

80

SO EXATAMENTE AS MEDIDAS
QUE DEFINIMOS NO CGRECT!
Alinhamento !"!#
INSTITUTO DE ARTES INTERATIVAS

Modifique seu cdigo desta maneira:


UIViewRelogio.m

- (void)drawRect:(CGRect)rect {
// Drawing code
! CGContextRef cgref = UIGraphicsGetCurrentContext();
!
! CGContextSetRGBFillColor(cgref, 0.5, 0.5, 0.9, 1);

! CGContextFillRect(cgref, CGRectMake(
rect.size.width/2,
rect.size.height/2,
h/2
80, 80));

}
A VARIVEL rect ARMAZENA A REA DA VIEW DISPONVEL PARA
DESENHO. QUANDO USAMOS size.width/2 ESTAMOS
CONSIDERANDO A METADE DA LARGURA DA VIEW. O MESMO VALE
PARA size.height/2. NOTE QUE MESMO ASSIM AINDA NO
CONSEGUIMOS CENTRALIZ-LO!
Desenhando o relgio !"!#
INSTITUTO DE ARTES INTERATIVAS

Agora temos um quadrado alinhado ao centro, mas ainda no


resolve nosso problema! Queremos um relgio de parede, que
tem bordas circulares. Vamos ento alterar o cdigo e
desenhar um circulo!

UIViewRelogio.m

- (void)drawRect:(CGRect)rect { NOSSO RELGIO TEM BORDA PRETA


// Drawing code
! CGContextRef cgref = UIGraphicsGetCurrentContext();
!
! CGContextSetRGBFillColor(cgref, 0.0, 0.0, 0.0, 1);
!
! CGContextFillEllipseInRect(cgref, CGRectMake(
! ! ! ! rect.size.width/2 - 40,
! ! ! ! rect.size.height/2 - 40,
! ! ! ! 80, 80));

}
SUBSTITUA RECT POR ELLIPSE!
Desenhando o relgio, parte 2 !"!#
INSTITUTO DE ARTES INTERATIVAS

Temos nossa borda! Agora vamos desenhar acima da borda


outro crculo, desta vez branco.
UIViewRelogio.m
! CGContextSetRGBFillColor(cgref, 0.0, 0.0, 0.0, 1);
!
! CGContextFillEllipseInRect(cgref, CGRectMake(
! ! ! ! rect.size.width/2 - 40,
! ! ! ! rect.size.height/2 - 40,
! ! ! ! 80, 80));
!
! CGContextSetRGBFillColor(cgref, 1.0, 1.0, 1.0, 1);
!
! CGContextFillEllipseInRect(cgref, CGRectMake(
! ! ! ! ! ! ! ! ! ! ! ! rect.size.width/2 - 35,
! ! ! ! ! ! ! ! ! ! ! ! rect.size.height/2 - 35,
! ! ! ! ! ! ! ! ! ! ! ! 70, 70));

}
REPARE QUE A ORDEM AQUI FAZ DIFERENA!
Desenhando o relgio, parte 2 !"!#
INSTITUTO DE ARTES INTERATIVAS

Agora a vez do ponteiro! Vamos utilizar um path. Veja como


fica o cdigo:
UIViewRelogio.m
! ! ! ! ! ! ! ! ! ! ! ! rect.size.width/2 - 35,
! ! ! ! ! ! ! ! ! ! ! ! rect.size.height/2 - 35,
! ! ! ! ! ! ! ! ! ! ! ! 70, 70));
!
! //inicia o path
! CGContextBeginPath(cgref);
! //desenha o ponteiro
! CGContextMoveToPoint(cgref, 320/2, 460/2);
! CGContextAddLineToPoint(cgref, 320/2, 460/2 - 30);
! // pinta o patg
! CGContextSetRGBStrokeColor(cgref, 0.0, 0.0, 0.0, 1);
! CGContextStrokePath(cgref);

} DIZEMOS QUE A LINHA EST NO MESMO


PONTO X, TANTO EM SEU INCIO (MoveToPoint)
QUANDO EM SEU TRMINO (AddLineToPoint) E
QUE EM RELAO AO EIXO Y, ELA COMEA NO
CENTRO E DEPOIS DESCE 30 PIXELS!
Utilizando matemgica! !"!#
INSTITUTO DE ARTES INTERATIVAS

Isso mantm o ponteiro no posio certa, mas somente para


este caso! Como podemos fazer para alinhar o ponteiro a cada
minuto, de maneira que siga toda tragetria?
Vamos utilizar a funo matemtica SENO e COS! Em obj-c
elas se chamam sin e cos.

sin e cos
sin =

cos =
Desenhando o ponteiro com sin e cos !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos precisar de uma varivel que cresa infinitamente,


assim como o grfico da pgina anterior cresce no eixo X.
UIViewRelogio.h
#import <UIKit/UIKit.h>

@interface UIViewRelogio : UIView {


! float contador;
}

@end

UIViewRelogio.m
! ! ! ! ! ! ! ! ! ! ! ! rect.size.width/2 - 35,
! ! ! ! ! ! ! ! ! ! ! ! rect.size.height/2 - 35,
! ! ! ! ! ! ! ! ! ! ! ! 70, 70));
SIN ESPERA UM ANGULO EM RADIANOS, QUE
! VAI DE 0 AT 2*PI, AQUI DIVIDIMOS ESTE VALOR
! contador += (2*M_PI)/60; POR 60, OU SEJA, 60 MUDANAS DE POSIO
! AT COMPLETAR UMA VOLTA.
! //inicia o path
! CGContextBeginPath(cgref);
Desenhando o ponteiro com sin e cos !"!#
INSTITUTO DE ARTES INTERATIVAS

Agora precisamos somente passar este contador para definir a


posio do ponteiro!
UIViewRelogio.h
! //inicia o path
! CGContextBeginPath(cgref);
! //desenha o ponteiro
! CGContextMoveToPoint(cgref, 320/2, 460/2);
! CGContextAddLineToPoint(cgref,
320/2 + sin(contador) * 30,
460/2 + cos(contador) * 30);
! // pinta o patg
! CGContextSetRGBStrokeColor(cgref, 1.0, 0.0, 0.0, 1);
! CGContextStrokePath(cgref);
!
! contador += (2*M_PI)/60;!
}

SIN E COS SEMPRE RETORNAM VALORES ENTRE


-1 e 1, AQUI MULTIPLICAMOS POR 30, QUE
O TAMANHO DESEJADO PARA O PONTEIRO!
Animando o ponteiro !"!#
INSTITUTO DE ARTES INTERATIVAS

Toda vez que chamamos o mtodo setNeedsDisplay a view


ser resenhada, portanto ao fim do mtodo vamos colocar um
timer que automaticamente pede o prximo quadro da
animao aps 1 segundo
UIViewRelogio.h

! // pinta o patg
! CGContextSetRGBStrokeColor(cgref, 1.0, 0.0, 0.0, 1);
! CGContextStrokePath(cgref);
!
! contador += (2*M_PI)/60;
!
! [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:@selector(setNeedsDisplay)
userInfo:nil repeats:NO];
!
}
DESTA MANEIRA NOSSA FUNCO QUE DESENHA O PONTEIRO SER
CHAMADA A CADA SEGUNDO : )
Exerccios !"!#
INSTITUTO DE ARTES INTERATIVAS

Este nosso relgio em


CoreGraphics!

Exerccios
1) Faa tambm o ponteiro das horase
dos minutos!

2) Com NSDate, capture o horrio


atual e utilize as horas e minutos reais
no relgio.

3) Faa as marcaes de hora e minuto


na borda do relgio.
!"!#
INSTITUTO DE ARTES INTERATIVAS

GameKit
Conectividade sem fio utilizando Gamekit
Introduo !"!#
INSTITUTO DE ARTES INTERATIVAS

O framework gamekit foi lanado na verso 3.0 do iPhone


SDK, com o objetivo de oferecer conectividade sem fio entre
iPhones. Na verso 4.0, agora do iOs, o gamekit tornou-se
uma central para compartilhar e desafiar amigos, entre outras
funes que faltaram na era 3.0.
Mesmo sem todas as funcionalidades desejadas, o GameKit foi
muito til, pois provia um meio fcil, oficial e documentado de
conectar iphones e trocar informaes.
Em nosso curso, veremos como desenvolver um Chat sem fio
entre iPhones utilizando este framework!
Classes e Protocolos !"!#
INSTITUTO DE ARTES INTERATIVAS

Para utilizar o GameKit sempre estar em jogo um objeto da


classe GKSession. Alm dele tambm vamos utilizar o
protocolo GKSessionDelegate para receber os avisos que a
rede gera durante a execuo.

NOSSO PONTO DE ENTRADA PARA REDE.VAI NOS


DIZER O NOME DOS DEVICES NA REDE, HABILITAR O
ACESSO E NOS MANTER DISPONVEIS NA REDE GKSession

SO ELES QUE DIZEM A NOSSA CLASSE QUEM EST


CONECTADO, DISPONVEL, DESCONECTADO. ALM
DE AVISAR QUANDO ALGUM PEDE PARA SE
CONECTAR OU QUANDO H FALHAS! GKSessionDelegate
Aplicativos que utilizam a rede !"!#
INSTITUTO DE ARTES INTERATIVAS

Veja que agora nossa aplicao no est mais sozinha, ela


recebe informaes de outros devices e tambm tem de estar
pronta para responder! Todo esse processo pode paracer
complexo a primeira vista, mas basta ter em mente de quem
parte os sinais e quem recebe para captar a lgica!

APP GAME KIT APP

2. POSSO CONECTAR?
1. PEA PARA 3. QUER CONECTAR
CONECTAR COM A?
COM B
A
B
6. USURIO B
CONECTADO! 4. RESPONDA SIM

5. SIM!
Criando o projeto !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos iniciar um novo projeto. Chame-o de GKChat.


Adicionando o framework !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos utilizar um framework chamado


GameKit.framework
Adicione-o ao projeto!
Criando a classe que monitora a rede !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos agora criar a classe que monitora a rede, envia os


pedidos de conexo, por meio da GKSession.

NA PASTA Classes ADICIONE UM NOVO


ARQUIVO.VAMOS CHAMA-LO DE
ControleRede!

ELE UM Objective-C class


SUBCLASSE DE NSObject
Criando a classe que monitora a rede !"!#
INSTITUTO DE ARTES INTERATIVAS

Nesta nova classe vamos fazer inicialmente duas coisas: Incluir


o framework Gamekit e depois definir uma varivel do tipo
GKSession

ControleRede.h

#import <Foundation/Foundation.h>
#import <GameKit/GameKit.h>

@interface ControleRede : NSObject {

! GKSession *chatSession;

@end
Iniciando a sesso na rede. !"!#
INSTITUTO DE ARTES INTERATIVAS

Partindo para a implementao, vamos, no mtodo init, iniciar


nossa sesso!
ControleRede.m

@implementation ControleRede

- (id) init O MTODO INIT TEM UM ATALHO: init+<esc>+<enter> !


{
! self = [super init];
! if (self != nil) { O SESSION ID IDENTIFICA UNICAMENTE O
! ! SERVIO. QUEM TEM O MESMO ID PODE SE
! ! chatSession = [[GKSession alloc]! COMUNICAR, CADA APLICAO DEVE TER O SEU
! ! ! initWithSessionID:@"GKChar"
! ! !
ESTE SER SEU NOME NA REDE!
displayName:[UIDevice currentDevice].name
! ! !

sessionMode:GKSessionModePeer];
! !
! ! TEMOS 3 MODOS DE REDE : CLIENT,
! } SERVER E PEER. PARA O CHAT, VAMOS
UTILIZAR O MODO PEER!
! return self;
}
Configurando-se como delegate. !"!#
INSTITUTO DE ARTES INTERATIVAS

Precisamos receber as notificaes do Gamekit sobre a


atividade na rede, para isso devemos ser seu delegate.
ControleRede.m

! ! ! displayName:[UIDevice currentDevice].name
! ! ! sessionMode:GKSessionModePeer];
! !
! ! chatSession.delegate = self;
! }
! return self;
}

Dizemos tambm que nossa classe implementa o protoclo


necessrio aos delegates do Gamekit.
ControleRede.h
#import <GameKit/GameKit.h>

@interface ControleRede : NSObject <GKSessionDelegate> {


! GKSession * chatSession;
}
Ativando a rede !"!#
INSTITUTO DE ARTES INTERATIVAS

O prximo passo implementar o mtodo de delegate do


GKSession que avisa sobre o estado dos outros usurios na
rede e, logo aps, ativar nossa rede no mtodo init!
ControleRede.m

- (void)session:(GKSession *)session peer:(NSString *)peerID


! ! didChangeState:(GKPeerConnectionState)state{
!
! NSLog(@"o usurio %@ mudou de estado!", ESTE MTODO RETORNA O
! ! [chatSession displayNameForPeer:peerID]); PeerID E SEU NOVO ESTADO

}
PARA TRANSFORMAR O peerID EM UM NOME,
UTILIZAMOS O MTODO displayNameForPeer

ControleRede.m

! ! chatSession.delegate = self;
! ! chatSession.available = YES; ATIVAMOS A REDE DESTA MANEIRA
! } DENTRO DO MTODO INIT
! return self;
Anlisando os estados !"!#
INSTITUTO DE ARTES INTERATIVAS

Nosso mtodo precisa tomar uma ao quando um peer avisa


que mudou de estado. Estes so os estados possveis:

GKPublicConstants.h

typedef enum ESTE USURIO EST DISPONVEL NA REDE, MAS VOC


{ PRECISA SOLICITAR UMA CONEXO PARA TROCAR DADOS

! GKPeerStateAvailable,
O USURIO NO EST MAIS DISPONVEL
! GKPeerStateUnavailable,
ESTE USURIO ACEITOU A CONEXO E VOC J PODE
! GKPeerStateConnected, TROCAR DADOS COM ELE

! GKPeerStateDisconnected, A CONEXO FOI INTERROMPIDA ( SE O USURIO FECHOU A


APLICAO, POR EXEMPLO, OU SAIU DA REA DE ALCANCE )
! GKPeerStateConnecting,
O PROCESSO DE CONEXO EST EM ANDAMENTO
} GKPeerConnectionState;
Tratando o estado disponvel !"!#
INSTITUTO DE ARTES INTERATIVAS

Em nosso Chat vamos apenas tratar o caso disponvel, nele


solicitamos conexo com aquele usurio!

ControleRede.m

- (void)session:(GKSession *)session peer:(NSString *)peerID


! ! didChangeState:(GKPeerConnectionState)state{
!
! NSLog(@"o usurio %@ mudou de estado!", PEDIMOS PARA O NOSSO GKSession
! ! [chatSession displayNameForPeer:peerID]); CONECTAR COM O USURIO!
!
! if(state == GKPeerStateAvailable){
! ! [chatSession connectToPeer:peerID withTimeout:6];
! }else if(state == GKPeerStateConnected){
NSLog(@"o usurio %@ conectou!", [chatSession
displayNameForPeer:peerID]);
! } VAMOS MANTER TAMBM UM LOG DE
QUEM EST CONECTADO.
}
Preparando um ambiente de teste !"!#
INSTITUTO DE ARTES INTERATIVAS

Neste ponto j podemos testar a rede, portanto vamos focar


em um teste simples: iniciar a rede e verificar se h logs de
usurios disponveis. Para isso vamos voltar ao nosso
ViewController e definir uma varivel para monitorar a rede.
GKChatViewController.h
#import <UIKit/UIKit.h>
#import "ControleRede.h"
LEMBRE-SE DE IMPORTAR O ARQUIVO ControleRede.h

@interface GKChatViewController : UIViewController {


! ControleRede *rede;
}
@end

E inici-la no mtodo viewDidLoad


GKChatViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
! rede = [[ControleRede alloc] init];
}
Verificando usurios disponveis. !"!#
INSTITUTO DE ARTES INTERATIVAS

Teste a aplicao! Voc vai precisar de dois aplicativos rodando


em dois devices ao mesmo tempo para conseguir conexo. O
simulador tambm pode ser utilizado para este teste.

NO CONSOLE PODEMOS VER OS LOGS


DE MUDANA DE ESTADO
Aceitando a conexo !"!#
INSTITUTO DE ARTES INTERATIVAS

O prximo passo aceitar a conexo com o outro usurio,


vamos implementar esta situao no nosso controlador de rede

ControleRede.m

- (void)session:(GKSession *)session
! ! didReceiveConnectionRequestFromPeer:(NSString *)peerID{
!
! [chatSession acceptConnectionFromPeer:peerID error:nil];
!
}

Nosso aplicativo, que um chat, aceita conexo de qualquer usurio,


contudo neste ponto seu aplicativo pode aceitar ou no um usurio
(baseado em uma blacklist, por exemplo)
Testando novamente !"!#
INSTITUTO DE ARTES INTERATIVAS

Agora nosso aplicativo j aceita conexes. Vamos testar


novamente para confirmar que os usurios se conectam

PRIMEIRO O USURIO
FICA DISPONVEL
ACEITA A CONEXO E
EST DISPONVEL PARA
TROCAR DADOS!
Interface do Chat !"!#
INSTITUTO DE ARTES INTERATIVAS

Prepare a interface, vamos


precisar de um campo de texto e
um text view. Deixe um espao
embaixo para o teclado!

O TECLADO OCUPA O MESMO ESPAO DE


UM PICKER.VOC PODE UTILIZ-LO
COMO BASE PARA MEDIR NA TELA.

GKChatViewController.h
FAA TAMBM OS IBOutlets E
CONECTE-OS A INTERFACE
@interface GKChatViewController :
UIViewController {
! ControleRede *rede;
! IBOutlet UITextField *uitMensagem;
! IBOutlet UITextView *uitvMensagens;
GKChatViewController.xib }
@end
Preparando o mtodo de enviar. !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos preparar nossa classe de rede de modo que ela j


disponibilize um mtodo para enviar as mensagens
ControleRede.h
! GKSession *chatSession;
}

-(void) enviaMensagem:(NSString*)msg;

@end

E a sua implementao:
ControleRede.m
-(void) enviaMensagem:(NSString*)msg{

! NSData *data = [msg dataUsingEncoding:NSUTF8StringEncoding];


! [chatSession sendDataToAllPeers:data
withDataMode:GKSendDataReliable error:nil];

}
Recebendo dados !"!#
INSTITUTO DE ARTES INTERATIVAS

Agora vamos nos preparar para receber os dados. Para isso


precisamos dizer ao session que nossa classe que vai querer
receber os dados que vem da rede.
ControleRede.m
! ! chatSession.available = YES
! ! [chatSession setDataReceiveHandler:self withContext:nil];
! }
! return self;

E a implementao:
ControleRede.m

- (void) receiveData:(NSData *)data fromPeer:(NSString *)peer inSession:


(GKSession *)session context:(void *)context{
!
! NSString *mensagem = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
!
}
Passando os dados recebidos !"!#
INSTITUTO DE ARTES INTERATIVAS

Perceba que podemos agora chamar o mtodo


enviaMensagem de nosso view controller, j que temos uma
instncia desta classe. Contudo, ainda no podemos fazer o
contrrio, enviar a mensagem recebida da rede para nosso
view controller. Para isso existe a tcnica de delegate. Vamos
marcar uma referncia do nosso view controller na classe de
rede, assim ela poder acessar o view controller e chamar
mtodos dele. Faremos isto criando uma varivel na classe
ControleRede chamada delegate.
ControleRede.h
#import <GameKit/GameKit.h>

@interface ControleRede : NSObject <GKSessionDelegate> {


! GKSession *chatSession;
ADICIONE UMA VARIVEL DO TIPO
! id delegate;
id, OU SEJA, QUALQUER OBJETO!
}

-(void) enviaMensagem:(NSString*)msg;
Referenciando o delegate !"!#
INSTITUTO DE ARTES INTERATIVAS

Agora usaremos esta varivel para armazenar a ligao at


nosso view controller. Ento vamos precisar declarar uma
property deste delegate.
ControleRede.h
! GKSession *chatSession;
! id delegate;
}

@property (nonatomic, retain) id delegate; DECLARE A PROPRIEDADE

-(void) enviaMensagem:(NSString*)msg;

E sintetiz-lo no .m de nossa classe, assim:


ControleRede.m
@implementation ControleRede

@synthesize delegate;

- (id) init
SINTETIZE-A NO .m
{
! self = [super init];
Atribuindo o delegate !"!#
INSTITUTO DE ARTES INTERATIVAS

ControleRede.m
- (void)viewDidLoad {
[super viewDidLoad];
! rede = [[ControleRede alloc] init]; self SIGNIFICA ESTE OBJETO. SEU
ENDEREO NA APLICAO, QUEM O TEM
! rede.delegate = self;
PODE CHAMAR MTODOS DESTE OBJETO
}

Pronto! agora temos uma comunicao de duas vias,


podemos chamar mtodos do ViewController para o
ControleRede e , por meio do delegate, do ControleRede para
o ViewController!
Veja a explicao passo a passo a seguir
Atribuindo o delegate. Passo a passo. !"!#
INSTITUTO DE ARTES INTERATIVAS

rede
(GKChatViewController) self
(GKSession) chatSession
(ControleRede) rede
ACESSA O OBJETO DO TIPO (id) delegate
(UITextField) uitMensagem
ControleRede QUE
(UITextView) uitvMensagens
INICIAMOS NO NOSSO VIEW
CONTROLLER.
GKChatViewController ControleRede

rede.delegate
(GKChatViewController) self
(GKSession) chatSession
(ControleRede) rede
(id) delegate
CHAMA A PROPRIEDADE (UITextField) uitMensagem
delegate DA NOSSA (UITextView) uitvMensagens
.
VARIVEL rede.
GKChatViewController ControleRede

rede.delegate = self; =
(GKChatViewController) self
(GKSession) chatSession
ATRIBUI O ENDEREO DO (ControleRede) rede
(id) delegate
NOSSO VIEW CONTROLLER A (UITextField) uitMensagem
PROPRIEDADE delegate DO (UITextView) uitvMensagens
OBJETO ControleRede .
CHAMADO rede.
GKChatViewController ControleRede
Utilizando o delegate !"!#
INSTITUTO DE ARTES INTERATIVAS

ControleRede.m

- (void) receiveData:(NSData *)data fromPeer:(NSString *)peer inSession: (GKSe


!
! NSString *mensagem = [[NSString alloc] initWithData:data encoding:NSUTF8StringEn
! [delegate recebeMensagem:mensagem];
!
}
Lembre-se: o delegate uma referncia
ao nosso view controller! Ele quem
receber esta chamada.

Mas perceba que este mtodo no foi declarado ainda em


nosso view controller. Uma chamada para um mtodo
inexistente far o aplicativo terminar instantaneamente!
Para isso existe um recurso chamado Protocol!
Definindo o protocolo !"!#
INSTITUTO DE ARTES INTERATIVAS

ControleRede.h

#import <Foundation/Foundation.h>
#import <GameKit/GameKit.h>
required INFORMA QUE ESTES
MTODOS ABAIXO TEM DE EXISTIR
OBRIGATORIAMENTE
@protocol ControleRedeDelegate

@required
-(void) recebeMensagem:(NSString*) texto;

@end

@interface ControleRede : NSObject <GKSessionDelegate> {


! GKSession *chatSession;
! id delegate;
}

Um protocolo define um lista de mtodos, sem implement-


los, que podem ser required ou optional!
Marcao no delegate !"!#
INSTITUTO DE ARTES INTERATIVAS

Precisamos agora informar a nossa varivel que ela pode sim


ser de qualquer tipo, mas que tem de implementar aqueles
mtodos listados no ControleRedeDelegate. Fazemos isto
adicionando esta marcao no tipo da varivel:

ControleRede.h

@interface ControleRede : NSObject <GKSessionDelegate> {


! GKSession *chatSession;
! id<ControleRedeDelegate> delegate;
}
Marcao no View Controller !"!#
INSTITUTO DE ARTES INTERATIVAS

O mesmo vale para o outro lado. Precisamos marcar no nosso


delegate que implementamos estes mtodos requiridos.
Fazemos isso da seguinte maneira:

GKChatViewController.h

#import <UIKit/UIKit.h>
#import "ControleRede.h"

@interface GKChatViewController : UIViewController <ControleRedeDelegate>{


!
! ControleRede *rede;
! IBOutlet UITextField *uitMensagem;
! IBOutlet UITextView *uitvMensagens;
}

@end
Recebendo o texto !"!#
INSTITUTO DE ARTES INTERATIVAS

Pronto! Agora podemos implementar o mtodo que receber


os textos do ControleRede.
GKChatViewController.m

// Implement viewDidLoad to do additional setup after loading the view, typically


- (void)viewDidLoad {
[super viewDidLoad];
! rede = [[ControleRede alloc] init];
! rede.delegate = self;
}

-(void) recebeMensagem:(NSString*) texto{


! uitvMensagens.text = texto; IMPLEMENTE O MTODO recebeMensagem
} DESTA MANEIRA

/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)
Enviando pelo view controller !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos partir para implementao do mtodo que envia o texto.


Faremos isso assim que o usurio tocar em confirmar, no teclado.
GKChatViewController.h
#import "ControleRede.h"

@interface GKChatViewController : UIViewController <ControleRedeDelegate, UITextFieldDelegate>{


!
! ControleRede *rede; ADICIONE O PROTOCOLO UITextFieldDelegate
! IBOutlet UITextField *uitMensagem;

GKChatViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
! rede = [[ControleRede alloc] init];
! rede.delegate = self;
! uitMensagem.delegate = self; PEDIMOS AO CAMPO DE TEXTO QUE NOS INFORME DOS EVENTOS QUE SE
} PASSAR, POR MEIO DO PROTOCOLO UITextFieldDelegate

- (BOOL)textFieldShouldReturn:(UITextField *)textField{
! [rede enviaMensagem:uitMensagem.text];
! uitMensagem.text = @""; ENVIAMOS O TEXTO PARA O CONTROLE DE REDE, LIMPAMOS
[uitMensagem resignFirstResponder]; O CAMPO DE TEXT E ESCONDEMOS O TECLADO
return YES;
}
Exerccios !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos adicionar mais funcionalidades


ao nosso chat?
Exerccios
1) Utilizando NSMutableString, faa
com que cada linha seja concatenada e
o textview mostre toda conversa

2) Sempre que receber uma mensagem


mostre o nome do usurio. Lembre-se
do mtodo displayNameForPeer, ele vai
te ajudar!

3) Mostre tambm as mensagens que


voc enviou.
!"!#
INSTITUTO DE ARTES INTERATIVAS

NSThread
Processamento paralelo utilizando Threads
Introduo !"!#
INSTITUTO DE ARTES INTERATIVAS

Diferente de aplicaes web ou gameloops (como em um


aplicativo Adobe Flash), no iPhone temos threads. Alm disso,
nossa aplicao est sendo executada numa Thread especial,
chamada MainThread, a thread principal.
Junto com nosso cdigo tambm ser processado todo cdigo
responsvel por controlar os eventos e o grfico exibido na
tela. Dito isso, no podemos executar cdigos que ocupem
muito tempo, porque isso geraria um atraso na exibio e no
manejo de eventos.
Para estas operaes que demandam tempo temos as
Threads!
So trechos de cdigo processados em paralelo, sem interferir
na execuo da MainThread.
Classe padro no Iphone !"!#
INSTITUTO DE ARTES INTERATIVAS

Utilizamos a classe NSThread para manusear Threads. Os


mtodos mais utilizados so:

+detachNewThreadSelector:toTarget:withObject:

CRIA A NOVA THREAD, O SELECTOR PASSADO SER EXECUTADO EM PARALELO AT


SEU FIM, BEM COMO TODAS AS CHAMADAS QUE ELE REALIZAR INTERNAMENTE

- initWithTarget:selector:object:

SEMELHANTE AO ANTERIOR, MAS AQUI PODEMOS ARMAZENAR A THREAD EM UMA


VARIVEL PARA ACESSLA POSTERIORMENTE
- start

INICIA A EXECUO DA THREAD ARMAZENADA NA VARIVEL.

+sleepForTimeInterval:

AGUARDA UM INTERVALO DE TEMPO, EM SEGUNDOS.


Criando o projeto !"!#
INSTITUTO DE ARTES INTERATIVAS

Faa um novo projeto View-Bassed Application. Chame-o de


ThreadGallery. Clique em build and run e certifique-se de que o
aplicativo funciona.
Criando o projeto !"!#
INSTITUTO DE ARTES INTERATIVAS

Em nosso view controller, vamos criar um Array que


armazenar os links de todas as imagens de nossa galeria.
ThreadGalleryViewController.h
#import <UIKit/UIKit.h>

@interface ThreadGalleryViewController : UIViewController {


! NSMutableArray *links;
}

@end

E inici-lo, ainda vazio, assim que a interface estiver carregada.


ThreadGalleryViewController.m

- (void)viewDidLoad {
[super viewDidLoad];
links = [[NSMutableArray alloc] init];
}
LEMBRE-SE DE RETIRAR AS MARCAES DE COMENTRIO NO MTODO
Adicionando os links ao vetor !"!#
INSTITUTO DE ARTES INTERATIVAS

Adicione links de imagens de sua preferncia ao Array.

ThreadGalleryViewController.m

! links = [[NSMutableArray alloc] init];


!
! [links addObject:@"http://upload.wikimedia.org/wikipedia/commons/thumb/d/
df/Evacuated_Highway_401_Color.jpg/800px-Evacuated_Highway_401_Color.jpg"];
! [links addObject:@"http://upload.wikimedia.org/wikipedia/commons/thumb/
2/21/Eritrean_Railway_-_Tivedshambo_2008-11-04-edit1.jpg/800px-
Eritrean_Railway_-_Tivedshambo_2008-11-04-edit1.jpg"];
! [links addObject:@"http://upload.wikimedia.org/wikipedia/commons/thumb/e/
ee/Gordon_Dam.jpg/394px-Gordon_Dam.jpg"];
! [links addObject:@"http://upload.wikimedia.org/wikipedia/commons/thumb/a/
ab/Oil_platform_P-51_%28Brazil%29.jpg/800px-Oil_platform_P-51_%28Brazil
%29.jpg"];
! [links addObject:@"http://upload.wikimedia.org/wikipedia/commons/thumb/
0/04/International_Space_Station_after_undocking_of_STS-132.jpg/800px-
International_Space_Station_after_undocking_of_STS-132.jpg"];
!
}

ADICIONE LINKS DE IMAGENS NO SEU ARRAY links


ImageView da imagem atual !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos criar um IBOutlet para uma UIImageView, tambm um


UIImageView no xib e conect-lo no interface builder
ThreadGalleryViewController.h

@interface ThreadGalleryViewController : UIViewController {


! NSMutableArray *links;
! IBOutlet UIImageView *imagem;
}

@end

CRIE UM UIImageView E AJUSTE-O PARA


OCUPAR TODO ESPAO NA VIEW
CONECTE O IBOutlet imagem AO
UIImageView
Configurando o ImageView !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos ajustar nosso UIImageView da seguinte maneira

UTILIZE O Content Mode Aspect Fill. ASSIM


A IMAGEM PREENCHE TODA TELA, MAS NO
SER DISTORCIDA.
Carregando uma imagem da internet !"!#
INSTITUTO DE ARTES INTERATIVAS

Logo aps o mtodo viewDidLoad, vamos criar um mtodo


para carregar um dado link e retorn-lo como UIImage.

ThreadGalleryViewController.m

! [links addObject:@"http://upload.wikimedia.org/wikipedia/commons/
! [links addObject:@"http://upload.wikimedia.org/wikipedia/commons/
!
}

-(UIImage*) carregaDaInternet:(NSString*) link{


! NSURL *url = [NSURL URLWithString:link];
! NSData *content = [NSData dataWithContentsOfURL:url];
! return [UIImage imageWithData:content];
}

PEGAMOS O CONTEDO DA INTERNET E TRANSFORMAMOS EM


NSData, EM SEGUIDA CRIAMOS UM UIImage COM ESTES DADOS
Testando nosso mtodo !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos testar e verificar se nosso mtodo realmente est


carregando a imagem da internet.

ThreadGalleryViewController.m

! [links addObject:@"http://upload.wikimedia.org/wikipedia/commons/
! [links addObject:@"http://upload.wikimedia.org/wikipedia/commons/
!
! imagem.image = [self carregaDaInternet:[links objectAtIndex:0]];
!
}

-(UIImage*) carregaDaInternet:(NSString*) link{


! NSURL *url = [NSURL URLWithString:link];

O aplicativo ir demorar alguns instantes para


exibir a imagem. Isso se deve ao fato de os
dados estarem sendo capturados da Internet!
Preparando a Thread !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos preparar nosso mtodo que ser executado em


paralelo! Obrigatoriamente ele ter de conter uma varivel
NSAutoReleasePool, para gerenciar a memria.
ThreadGalleryViewController.m

-(void) exibeImagens{ GERENCIAMENTO DE MEMRIA.


!
! NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
! int contador = 0;
! GUARDA QUAL A IMAGEM ATUAL
! while (1) {
! ! NSString *link = [links objectAtIndex:contador%[links count]];

! ! BUSCAMOS O LINK DA IMAGEM


! }
!
! [pool release];
!
}
Continuao !"!#
INSTITUTO DE ARTES INTERATIVAS

Agora capturamos a imagem deste link e utilizamos como


imagem do nosso image view.
ThreadGalleryViewController.m

-(void) exibeImagens{
!
! NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
! int contador = 0;
!
! while (1) {
! ! NSString *link = [links objectAtIndex:contador%[links count]];

UIImage *resultado = [self carregaDaInternet:link];


! ! [imagem performSelectorOnMainThread:@selector(setImage:)
withObject:resultado waitUntilDone:YES];
! }
! PRECISAMOS MOSTRAR A IMAGEM NA MainThread. TODA
! [pool release]; OPERAO DE INTERFACE VISUAL NO PODE SER
! EXECUTADA EM UMA THREAD SECUNDRIA!
}
Continuao !"!#
INSTITUTO DE ARTES INTERATIVAS

Agora precisamos atualizar a imagem atual para a prxima


imagem!
ThreadGalleryViewController.m

-(void) exibeImagens{
!
! NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
! int contador = 0;
!
! while (1) {
! ! NSString *link = [links objectAtIndex:contador%[links count]];

UIImage *resultado = [self carregaDaInternet:link];


! ! [imagem performSelectorOnMainThread:@selector(setImage:)
withObject:resultado waitUntilDone:YES];
contador++;
! }
!
! [pool release];
!
}
Executando a Thread !"!#
INSTITUTO DE ARTES INTERATIVAS

Pronto! Agora precisamos apenas chamar este mtodo para


ser executado em paralelo.
ThreadGalleryViewController.m

! [links addObject:@"http://upload.wikimedia.org/wikipedia/commons/
! [links addObject:@"http://upload.wikimedia.org/wikipedia/commons/
!
! [NSThread detachNewThreadSelector:@selector(exibeImagens)
toTarget:self withObject:nil];
!
}
NO VAMOS MAIS PRECISAR DO TESTE QUE ESTAVA AQUI
-(UIImage*) carregaDaInternet:(NSString*) link{
! NSURL *url = [NSURL URLWithString:link];
Teste o aplicativo !"!#
INSTITUTO DE ARTES INTERATIVAS

Ai est nossa galeria!


As imagens so
grandes, ento deve
haver um delay ao
exibi-las
Exerccios !"!#
INSTITUTO DE ARTES INTERATIVAS

Nossa galeria pode ficar ainda


melhor!
Exerccios
1) Adicione um Activity Indicator para
informar ao usurio que a imagem est
carregando

2) Faa botes de prxima imagem e


anterior

3) Faa dois botes de controle: um


play e um pause.
!"!#
INSTITUTO DE ARTES INTERATIVAS

POST
Recebendo e enviando dados a Internet via POST
Introduo !"!#
INSTITUTO DE ARTES INTERATIVAS

H vrias maneiras de se comunicar com a internet dentro do


contexto http, contudo as mais comuns e largamente utilizadas
so os mtodos GET e POST.
Existem algumas diferenas entre eles, mas o princpio o
mesmo: enviar variveis a um endereo e receber uma
resposta com os dados desejados
Vamos criar uma aplicao que utilize POST!
Classe padro no Iphone !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos precisar no s de um objeto, mas vrios. Veja quais


so e suas principais funes:
!

VAI CUIDAR DO ENDEREO DE DESTINO DO NOSSO PEDIDO

NSURL
!
NSURLRequest CUIDA DA REQUISIO, ALM DA URL, CRIA UM PACOTE COM
A DESCRIO DO NOSSO PEDIDO, INCLUSIVE AS VARIVEIS!

!!
NSURLConnection
FAZ O TRFEGO DE REDE, ENVIA O PEDIDO, CAPTURA A
RESPOSTA
Server Side !"!#
INSTITUTO DE ARTES INTERATIVAS

Neste exerccio vamos


utilizar a API do Flickr
para fazer as
requisies e receber
as respostas.

Veja mais detalhes em


www.flickr.com/
services

Para utilizar a API voc


precisa de um conta
gratuita no Flickr.
Precisar tambm
solicitar uma chave
que ser utilizada nas
requisies.
Padro da requisio !"!#
INSTITUTO DE ARTES INTERATIVAS

Para receber dados, por exemplo, de um galeria, precisamos


enviar alguns dados ao servidor do Flickr. Este o fluxo:

INTERNET

iPhone
Flickr
REQUISIO

RESPOSTA

Como exemplo, veja como seria a requisio para receber as


fotos de uma galeria:
method=flickr.galleries.getPhotos&gallery_id=6065-72157617483228192
Criando o projeto !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos fazer um novo projeto, view based, chamado


FlickrPOST.
Criando uma NSURL !"!#
INSTITUTO DE ARTES INTERATIVAS

Comeamos criando a URL da requisio.


FlickrPOSTViewController.m

- (void)viewDidLoad {
[super viewDidLoad];
!
! NSURL *url = [NSURL URLWithString:@"http://api.flickr.com/services/rest/"];

} ESTE ENDEREO UM PADRO DESCRITO NA API DO


FLICKR. CONFIRA A VERSO MAIS RECENTE CASO TENHA
PROBLEMAS PARA ACESSAR.
Utilizando a url para criar um Request !"!#
INSTITUTO DE ARTES INTERATIVAS

Agora em posse da URL, vamos criar um NSMutableRequest.


Ele mutable porque vamos adicionar informaes a ele.

FlickrPOSTViewController.m

- (void)viewDidLoad {
[super viewDidLoad];
!
NSURL *url = [NSURL URLWithString:@"http://api.flickr.com/services/rest/"];

NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];


[req setHTTPMethod:@"POST"];

}
PODEMOS CONFIGURAR O REQUEST COM OS
VALORES DE HTTPMethod: POST OU GET
Criando o corpo da requisio !"!#
INSTITUTO DE ARTES INTERATIVAS

O prximo passo configurar o contedo da requisio. Veja


as variveis que o flickr pede para retornar a galeria:
FlickrPOSTViewController.m
! !
! [req setHTTPMethod:@"POST"];

NSMutableString *body = [[NSMutableString alloc] init];


! // h vrios mtodos que podemos acessar,
! // nesse caso vamos pegar as fotos de uma galeria
! [body appendString:@"method=flickr.galleries.getPhotos"];
! // voc pode, para este aplicativo, utilizar a chave do iAi
! // mas s para este teste, caso faa um aplicativo utilizando
! // o flickr, crie sua prpria chave gratuitamente :)
! [body appendString:@"&api_key=5cffcd172126ae9a5a90430088879891"];
! // vamos acessar um galeria public, ai est uma interessante
! [body appendString:@"&gallery_id=6065-72157617483228192"];
! // pedimos 10 itens por pgina e queremos a primeira pgina
! [body appendString:@"&per_page=10&page=1"];
! // aqui est o token do iAi, mas uma vez: se criar uma aplicao
! // que acesse o flickr, crie seu prprio token gratuitamente!
! // os tokens tem limite de acesso dirio, criando o seu previne
! // um bloqueio indevido da conta ;)
! [body appendString:@"&auth_token=72157624609285382-74c74531577a3627&"];
! [body appendString:@"api_sig=53e52931aa2d11deb06aca77b8f43d05"];
Adicionando o body ao NSURLRequest !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos transformar est string em um NSData e inclu-la ao


corpo da requisio

FlickrPOSTViewController.m

! [body appendString:@"api_sig=53e52931aa2d11deb06aca77b8f43d05"];
!
! NSData *myRequestData = [NSData dataWithBytes:
[body UTF8String] length:[body length]];

! [req setHTTPBody:myRequestData]; A CLASSE NSData CUIDA DE TRANFORMAR A


! STRING EM DADOS
}
ASSIM INCLUMOS AS VARIVEIS A REQUISIO!
Criando a conexo !"!#
INSTITUTO DE ARTES INTERATIVAS

J configuramos nossa requisio, agora vamos focar na


conexo que vai enviar estes dados e receber a resposta da
rede

FlickrPOSTViewController.m

! NSData *myRequestData = [NSData dataWithBytes:


[body UTF8String] length:[body length]];
! [req setHTTPBody:myRequestData];
!
! [NSURLConnection connectionWithRequest:req delegate:self];
!
}
NO PRECISO ARMAZENAR A CONECTION EM
UMA VARIVEL, BASTA CONFIGURAR O
DELEGATE QUE RECEBER A RESPOSTA!
Configurando o delegate !"!#
INSTITUTO DE ARTES INTERATIVAS

Somos delegate da NSURLConnection, portanto precisamos


implementar o seu protocolo!
FlickrPOSTViewController.m

! NSData *myRequestData = [NSData dataWithBytes:


[body UTF8String] length:[body length]];
! [req setHTTPBody:myRequestData];
!
! [NSURLConnection connectionWithRequest:req delegate:self];
!
}

-(void) connection:(NSURLConnection *)connection didFailWithError:


(NSError *)error{
!
ADICIONE ESTES DOIS MTODOS!
}

-(void)connection:(NSURLConnection *)connection didReceiveData:


(NSData *)data {

}
Lidando com os erros !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos implementar primeiro o mtodo que recebe um aviso


de erro quando, por algum motivo, no foi possvel conectar e
acessar os dados.
FlickrPOSTViewController.m

! [NSURLConnection connectionWithRequest:req delegate:self];


!
}

-(void) connection:(NSURLConnection *)connection


didFailWithError:(NSError *)error{
! UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:@"Ops!"
! ! message:@"No foi possvel receber os dados!"
delegate:nil
cancelButtonTitle:@"ok"
otherButtonTitles:nil];
! [alert show];
! [alert release];
}
Recebendo os dados !"!#
INSTITUTO DE ARTES INTERATIVAS

Finalmente vamos capturar a resposta enviada pelo flicker!

FlickrPOSTViewController.m

cancelButtonTitle:@"ok"
otherButtonTitles:nil];
! [alert show];
! [alert release];
}

-(void)connection:(NSURLConnection *)connection
didReceiveData:(NSData *)data {
!
! NSString *str = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
! NSLog(@"resposta: %@", str);
!
}
VAMOS VER NO CONSOLE QUAL FOI A RESPOSTA
DO SERVIDOR DA API DO Flickr!
Recuperando o link da imagem !"!#
INSTITUTO DE ARTES INTERATIVAS

Com o XML podemos fazer um parser, como voc j aprendeu


neste curso. Mas voc deve ter notado que no h um link
para imagem neste XML! Ento como vou acess-la?
Existe um padro! Voc precisa montar a URL a partir dos
dados enviados no xml, veja:
PADRO DO LINK

http://farm{farm-id}.static.ickr.com/{server-id}/{id}_{secret}.jpg

EXEMPLO DE RESPOSTA

<photo id="3411384625" owner="23534352@N07" secret="74167a8895"


server="3374" farm="4" title="_MG_0611" ispublic="1" isfriend="0" isfamily="0" />

LINK PARA ESTA IMAGEM

http://farm4.static.ickr.com/3374/3411384625_74167a8895.jpg
Exerccios !"!#
INSTITUTO DE ARTES INTERATIVAS

Utilize seus conhecimentos para


finalizar est galeria!
Exerccios
1) Faa um NSXMLParser que leia este
XML recebido.

2) Crie uma NSThread para exibir as


imagens

3) Crie botes de controle, como:


prximo, anterior, play e pause!
!"!#
INSTITUTO DE ARTES INTERATIVAS

OpenGL
Introduo ao 3D utilizando OpenGL
Introduo !"!#
INSTITUTO DE ARTES INTERATIVAS

OpenGL uma ferramenta usada amplamente no mercado.


Consiste em uma API que descreve maneiras de acessar o
hardware de acelerao 3D em baixo nvel.
Veremos em nosso curso alguns conceitos bsicos desta
ferramenta que, sem dvida, muito poderosa.
Vale lembrar que os iPhones e iPods touch so equipados com
uma GPU PowerVR MBX Lite 3D, um processador acelerador
grfico dedicado compatvel com a especificao OpenGL ES.
Framework !"!#
INSTITUTO DE ARTES INTERATIVAS

Para utilizar o OpenGL em nossa aplicaes preciso incluir


um framework chamado OpenGLES.
As funes contidas neste pacote esto escritas em C. Em sua
maioria, comeam com o prefixo gl_, como gl_enable, por
exemplo.
Alm disso o OpenGL utiliza nomes especiais para os tipos,
como GLFloat, para nmeros reais. Isso se deve ao fato de que
esta biblioteca est disponvel para uma infinidade de devices,
de celulares a computadores e video games.
Funcionamento !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos, em nosso projeto, criar uma aplicao simples e


didtica que utiliza alguns conceitos bsicos do OpenGl, como
vrtices, arestas e faces!
Todo objeto em nossa aplicao ser montado a partir de
triangulos. E estes so construidos com vrtices interligadas
por arestas, assim um cubo seria visto desta maneira:

A
Note que os pontos A,B e C so
vrtices. De A at B existe uma aresta. A
unio das arestas de AB, BC,CA formam
o tringulo(face) em vermelho

C B
Adquirindo o projeto !"!#
INSTITUTO DE ARTES INTERATIVAS

Para este exemplo vamos usar em projeto pr-configurado,


pois os detalhes no OpenGL so muitos.

iai.art.br/escola/iphonesdk3/opengl/projeto.zip

Faa o download do projeto e


descompacte. Abra o xcodeproj
e teste. Uma tela no simulador
azul deve aparecer.
Desenhando o primeiro tringulo !"!#
INSTITUTO DE ARTES INTERATIVAS

GLViewController.m
@implementation GLViewController

- (void)drawView:(GLView*)view{
!
! static const Vertex3D vertices[]= {
! ! {-13, 20, 0}, // 0
! ! { 13, 20, 0}, // 1!!
NOSSOS VRTICES
! ! {-13, 0, 0}, // 2
! };
!
! static const GLubyte elementFaces[] = {
! ! 0,1,2
! };
NOSSAS FACES
!
! glLoadIdentity();!
! glTranslatef(0, 0, -35); AJUSTAMOS A VISO
!
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glDrawElements(GL_TRIANGLES, 3,
GL_UNSIGNED_BYTE, elementFaces);
!
}
DESENHAMOS OS PONTOS
Adicionando cor !"!#
INSTITUTO DE ARTES INTERATIVAS

GLViewController.m
! ! { 13, 20, 0}, // 1!
! ! {-13, 0, 0}, // 2
! };
!
! static const Color3D colors[] = {
! ! {0.0, 1.0, 0.0, 1.0},
! ! {0.0, 1.0, 0.0, 1.0},
! ! {0.0, 0.0, 1.0, 1.0}, UMA COR PARA CADA VRTICE
! };
!
! static const GLubyte elementFaces[] = {
! ! 0,1,2
! };
! HABILITAMOS O VETOR DE CORES
! glLoadIdentity();!
! glTranslatef(0, 0, -35);
!
! glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
! glEnableClientState(GL_VERTEX_ARRAY);
! glEnableClientState(GL_COLOR_ARRAY); ADICIONAMOS O COLOR POINTER
! glVertexPointer(3, GL_FLOAT, 0, vertices);
! glColorPointer(4, GL_FLOAT, 0, colors);
! glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, elementFaces);
! glDisable(GL_VERTEX_ARRAY);
! glDisable(GL_COLOR_ARRAY); VOLTAMOS AO ESTADO NATURAL
}
Algumas consideraes !"!#
INSTITUTO DE ARTES INTERATIVAS

Vejamos com mais detalhes algumas linhas do trecho que


acabamos de escrever

static const Vertex3D vertices[]= {


! {-13, 20, 0}, // 0
ESTES SO NOSSO VERTCES. SO 3 NMEROS PARA DEFINIR
! { 13, 20, 0}, // 1! ! CADA UM DELES: COORDENADA X, Y e Z. O VALOR DEPENDE
! {-13, 0, 0}, // 2 DAS PROPORES DO ESPAO E PODE VARIAR BASTANTE.
};
!
! static const Color3D colors[] = { A REGRA : UMA COR PARA CADA VRTICE NA MESMA ORDEM
! ! {0.0, 1.0, 0.0, 1.0}, EM QUE FORAM DECLARADOS. OS TRS NMEROS SO OS
! ! {0.0, 1.0, 0.0, 1.0}, COMPONENTES Vermelho, Verde e Azul DA COR,
! ! {0.0, 0.0, 1.0, 1.0}, RESPECTIVAMENTE, QUE PODEM VARIAR DE 0.0 A 1.0
! };
!

! glLoadIdentity();! ESTA LINHA DIZ QUE O PONTO ONDE AS


! glTranslatef(0, 0, -35); FACES SERO DESENHADAS EST DESLOCADO
PARA TRS DA ORIGEM 0,0,0 (-35 NO EIXO Z)
Algumas consideraes !"!#
INSTITUTO DE ARTES INTERATIVAS

Alm disso, considere que este mtodo ser chamado vrias


vezes por segundo, pois est em loop. Portanto devemos
realinhar os objetos a cada chamada do mtodo

LIMPA TODAS AS TRANFORMAES ANTERIORES, COMO A DE


glLoadIdentity();! TRANSLAO DE -35 EM Z.

! glClear(GL_COLOR_BUFFER_BIT | VAI LIMPAR A TELA PARA QUE O OBJETO POSSA SER


GL_DEPTH_BUFFER_BIT); DESENHADO NOVAMENTE. A CADA FRAME TODOS ELEMENTOS
SO APAGADOS E REDESENHADOS!
Mais poligonos !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos adicionar mais polgonos ao nosso aplicativo

GLViewController.m
! static const Vertex3D vertices[]= {
! ! {-13, 20, 0}, // 0
! ! { 13, 20, 0}, // 1!!
! ! {-13, 0, 0}, // 2 VERTCES
! ! { 13, 0, 0}, // 0
! };
!

! static const Color3D colors[] = {


! ! {0.0, 1.0, 0.0, 1.0},
! ! {0.0, 1.0, 0.0, 1.0},
! ! {0.0, 0.0, 1.0, 1.0}, COR
! ! {0.0, 0.0, 1.0, 1.0},
! };

! static const GLubyte elementFaces[] = {


! ! 0,1,2, FACE
! ! 1,2,3
! };

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, elementFaces);

NMERO DE ELEMENTOS A DESENHAR. IGUAL AO NMERO DE TENS NO VETOR elementFaces


Animando !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos girar este objeto, assim veremos como funciona uma


animao simples em OpenGL, mas que j cria um efeito
interessante
GLViewController.h
@class GLView;
@interface GLViewController : UIViewController {
! GLfloat delta;
}
- (void)drawView:(GLView*)view;
- (void)setupView:(GLView*)view;

@end VAMOS UTILIZAR A VARIVEL delta PARA MANIPULAR A


ROTAO DO NOSSO OBJETO. A CADA CHAMADA DE DO
MTODO drawView VAMOS INCREMENT-LA.

GLViewController.m
- (void)drawView:(GLView*)view{
!
! delta += 4.5;
!
! static const Vertex3D vertices[]= {
! ! {-13, 20, 0}, // 0
! ! { 13, 20, 0}, // 1!!
! ! {-13, 0, 0}, // 2
Aplicando a variao !"!#
INSTITUTO DE ARTES INTERATIVAS

Agora basta repassar esta rotao para o mtodo de


tranformaco, similar ao de translao

GLViewController.m
! ! 0,1,2,
! ! 1,2,3
! };
!
! glLoadIdentity();
! glTranslatef(0, 0, -35);
! glRotatef(delta, 0.0, 1.0, 0.0);
!
! glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

A FUNO DE ROTAO RECEBE QUATRO PARMETROS: A


QUANTIDADE DE ROTAO EM RADIANOS E AS PROPORES DESTA
ROTAO EM X, Y E Z.
Teste a aplicao !"!#
INSTITUTO DE ARTES INTERATIVAS

Veja que agora podemos perceber claramente o espao 3 na


aplicao!
Adiciondo UIKit !"!#
INSTITUTO DE ARTES INTERATIVAS

possivel tambm adicionar elementos do UIKit para interagir


com o OpenGL!
GLViewController.m
! glView.animationInterval = 1.0 / kRenderingFrequency;
! [glView startAnimation];
! [glView release];
!
! UISlider *slider = [[UISlider alloc] initWithFrame:
CGRectMake(20, 265, 280, 20)];
! slider.maximumValue = 1.0;
! slider.minimumValue = .10;
! slider.value = .35;
! [window addSubview:slider];
!
! [window makeKeyAndVisible];
Exerccios !"!#
INSTITUTO DE ARTES INTERATIVAS

OpenGL muito potente e requer


habilidade! Vamos fazer alguns exerccios?

Exerccios
1) Adicione novos pontos, faces e crie
um cubo!

2) Utilize o UIKit para criar um slider


que controle a velocidade da rotao

3) Faa uma animao similar ao flip


das views modais! Para isso anime a
rotao e a distncia do eixo Z.
!"!#
INSTITUTO DE ARTES INTERATIVAS

Instruments
Gerenciamento de memria
Introduo !"!#
INSTITUTO DE ARTES INTERATIVAS

O iPhone tem muito potencial! Chegamos ao fim do curso e


voc deve ter notado que ele d possibilidades aos
programadores de maneiras nunca antes vistas em
plataformas mobile!
Contudo, dada essa caracterstica, os aplicativos ficam mais
complexos e as analises e preveno de buracos na memria
(leaks) ficam cada vez mais difceis.
Para nos ajudar nesta tarefa a Apple disponibiliza o
Instruments!
Leaks !"!#
INSTITUTO DE ARTES INTERATIVAS

Ao contrrio de Java, Javascript, Action Script e Ruby o


Objective C que roda no iPhone no tem um Garbage Colector.
Isso significa que cabe aos programadores reservar e liberar a
memria para suas variveis.
Um leak acontence quando reservamos dada memoria e no
devolvemos ao sistema operacional logo aps utiliz-la! Nestes
casos este buraco na memria ficar l at que o aplicativo
termine sua execuo.
Se uma aplicao tem muitos leaks, depois de um certo tempo
de uso comea a ficar sem espao para trabalhar de tanto
espao ocupado na memria pelos leaks!
Temos que nos preparar para isso!
Criando um caso de teste !"!#
INSTITUTO DE ARTES INTERATIVAS

Vamos criar propositalmente uma aplicao que gere um leak


na memria. Basicamente vamos alocar uma varivel quando
um boto for ativado e no devolveremos ao sistema
operacional.
Comee criando um view based application, chamado
ExemploLeak.
Ajuste a interface !"!#
INSTITUTO DE ARTES INTERATIVAS

No interface builder, crie um boto e um UITextView. Em


seguida faa os Outlets e conecte-os.

ExemploLeakViewController.m

#import <UIKit/UIKit.h>

@interface ExemploLeakViewController :
UIViewController {
! IBOutlet UITextView *texto;
}

-(IBAction) criaLeak;

@end
Implementao do IBAction !"!#
INSTITUTO DE ARTES INTERATIVAS

O IBAction que simula um leak fica assim:

ExemploLeakViewController.h
-(IBAction) criaLeak{
!

!
! NSMutableString *textoLeak = [NSMutableString string];
!
! for (int i = 0; i < 100 ; i ++) {
! !
! ! NSArray *frases = [[NSArray alloc ] initWithObjects:@"lorem ipsum dolor",
! ! ! ! ! ! @"sit er elit lamet",
! ! ! ! ! ! @"consectetaur cillium adipisicing pecu",
! ! ! ! ! ! @"sed do eiusmod tempor incididunt ut ",
! ! ! ! ! ! @"labore et dolore magna aliqua" ,
! ! ! ! ! ! nil];
! !
! ! [textoLeak appendString:[frases objectAtIndex:arc4random()%[frases
count]]];
! }
! CRIA UMA NSSTRING COM 100 FRASES
! texto.text = textoLeak; ALEATRIAS A PARTIR DO VETOR frases

}
MOSTRA A FRASE NO UITextView
Teste !"!#
INSTITUTO DE ARTES INTERATIVAS

O compilador vai aceitar o cdigo sem problemas e a aplicao


tambm funciona corretamente! Ento qual o problema?

Funciona!
No o suficiente?
Analizando o cdigo !"!#
INSTITUTO DE ARTES INTERATIVAS

Agora tente o
seguinte: Clique
em run, no
menu superior, e
escolha a opco
Run with
Performance
Tool, depois
escolha Leaks.
Instruments !"!#
INSTITUTO DE ARTES INTERATIVAS

Clique vrias vezes no boto e veja que o Instruments vai


registrar alguns buracos na memria, nem sempre
imediatamente, mas eles esto l!

APS 1 MINUTO DE ATIVIDADE A


APLICAO J ESTAVA COM 46KB EM LEAKS!
Resultado !"!#
INSTITUTO DE ARTES INTERATIVAS

O Instruments mostra aos programadores a atividade na


memria enquanto o aplicativo est em uso. Contudo,
podemos utilizar outra ferramenta quando o assunto leak!

Clique em build,
no menu
superior, e
escolha a opco
Build and
Analyze.
Analisando mais a fundo !"!#
INSTITUTO DE ARTES INTERATIVAS

O analizador nos dir que dentro deste for existe um objeto


que pode gerar um leak na memria!
Analisando mais a fundo !"!#
INSTITUTO DE ARTES INTERATIVAS

Com duplo clique voc pode conferir os detalhes


Concluso !"!#
INSTITUTO DE ARTES INTERATIVAS

O analizador nos disse que este NSArray est sendo retido na


mmoria quando utilizamos o mtodo alloc e init. Mas nunca
foi liberado, ou seja, precisamos chamar o mtodo release
assim que terminar de utiliz-lo, assim:

ExemploLeakViewController.m

! ! ! ! ! ! @"sed do eiusmod tempor incididunt ut ",


! ! ! ! ! ! @"labore et dolore magna aliqua" ,
! ! ! ! ! ! nil];
! !
! ! [textoLeak appendString:[frases objectAtIndex:
arc4random()%[frases count]]];
! ! [frases release];
! }
!
! texto.text = textoLeak;
SEMPRE QUE FAZEMOS UM ALLOC DEVE HAVER UM
RELEASE! TAMBM PRECISO UM RELEASE QUANDO
} FAZEMOS UM RETAIN!
Exerccios !"!#
INSTITUTO DE ARTES INTERATIVAS

O Instruments e o analisador so
nossos amigos e evitam problemas
futuros, use-os sempre!
Exerccios
1) Analise com o instruments e o
analisador todos aplicativos que voc j
fez, veja se h algo para corrigir!

2) Acostume-se a sempre analisar seu


cdigo, principalmente antes de
entregar um projeto ou envi-lo a
AppStore!
Apostila SDK Modulo 3 !"!#
INSTITUTO DE ARTES INTERATIVAS

Desenvolvimento
Luiz Gustavo Lino

Reviso
Lucas Longo
Omar Jardin Pavel

Edio
Primeira edio
Instituto de Artes Interativas
2010