curso iosx

161
Desenvolvimento de Apps para iOS

Upload: marcio-canto

Post on 13-Mar-2016

227 views

Category:

Documents


6 download

DESCRIPTION

Curso iosx

TRANSCRIPT

Page 1: Curso iosx

Desenvolvimento de Apps para iOS

Page 2: Curso iosx

Índice de Conteúdo

Introdução

Pré-requisitos

A plataforma iPhone/iPod/iPad

Vantagens da plataforma iOS

Cocoa Touch Framework

Sobre o Apple Developer Program

iOS SDK

Xcode

Interface Builder

iOS Simulator

Hello World

Apresentando a interface

Criando a interface

Referências aos objetos da interface

Conexões da view x controller

Implementações

Refinando a mensagem de exibição

A linguagem de programação

Padrão MVC

Model

View

Controller

MVC no Objective-C

Estrutura e padrões do código

Declaração de funções e métodos

Declaração de métodos estáticos

Declaração de métodos com um objeto de retorno

Ciclo de vida de um objeto

Orientação a objeto em poucas linhas

Criando as classes em objC

Padrões de mensagens

NSLog

Variáveis e Objetos

Strings

NSString e NSMutableString

Formas de inicialização

Principais métodos

Números

Valores lógicos

Arrays

Principais métodos

Dicionários

Principais métodos

Page 3: Curso iosx

Objeto id

Condições

Laços de repetição

O loop "for"

Laços "while" e "do...while"

Getters, Setters e propriedades

Declaração de propriedades

Atributos das propriedades

Protocolos

Na prática

Configurando as variáveis de instância

Implementando a classe

Usando a classe

Exemplos de uso

Objetos de interface com o usuário

Sintaxe padrão para declarar um objeto no Xcode

Sintaxe padrão para declarar uma ação a um evento

Label, textfield, textview e botão

Na prática

Cabeçalhos

Implementações

Switch e Activity Indicator

Na Prática

Segmented Control e Image View

Na Prática

Criando o código

Slider e Progress View

Na prática

Criando o código

Classes relacionadas

UIColor

Cores pré-definidas

UIFont

UIImage

Windows e views

Métodos das views

Métodos do App Delegate

Navigation Bar

TabBar Controller

Propriedades

TableView Controller

Propriedades especiais nas células

Títulos da célula

Ícones de navegação

Modal views

Transições

Mensagens de alerta

Page 4: Curso iosx

Na prática

Configurando a Tab Bar

Incluindo a Tab Bar ao Window

Ícones

Modal Views

Subview a ser aberta

Declarando os métodos do ModalViews.h

Implementando os métodos no ModalViews.m

Alerts

View Padrão - SubView

ViewPadrao

Table View

Acesso a dados e sandbox

NSUserDefaults

Na prática

Acesso aos arquivos do sandbox

PLists

Na prática

Implementação

Core data

Na prática

Criando a tabela

TableListView Controller

Implementação da classe

Configurando a TableListView

Listando os registros

Implementando a navegação

Formulário

Implementando o formulário

Dados padrão nos campos

Salvando o registro

Excluindo o registro

Tornando o formulário visível

Hora de abrir o registro pela tabela

Resumindo

XML

Métodos do NSXMLParserDelegate

Webview

Operações com a webview

Classes relacionadas

Projeto final

Planejando o app

Mãos a obra!

Modelo de dados

Leitura dos feeds

Estrutura do RSS

Objetos relacionados

Page 5: Curso iosx

Implementações

Parser

Implementação e init

didStartElement:

foundCharacters:

didEndElement:

Título do feed

Fechamento da tag item

Dados dos posts

Fechamento da tag RSS

Verificação do cadastro do feed

Cadastro do feed

Verificação dos posts do feed

Cadastro dos posts

O código do bloco na íntegra

parse:

A view principal

View EditFeeds

Controller EditFeeds

Controller da lista de feeds

Implementação do controller

abreDados:

Configurações da tabela

View para lista de posts

Cabeçalhos

Implementação

Lista de posts

Configuração da tabela

Abrindo esta view

View de exibição do post

Cabeçalhos

Implementação

Formatação CSS

Exibindo a view pela lista de posts

A view da aba Novidades

Implementação do arquivo Novidades.m

Configurações da tabela

Refinamentos

Desafios propostos para melhorias

Considerações finais

Page 6: Curso iosx

Introdução (1)

Olá! Seja bem-vindo ao curso de desenvolvimento para iOS com objC do iMasters PRO. Neste

curso abordaremos temas que, até o final, você se tornará capaz de desenvolver boa parte dos

tipos de aplicativos que estão publicados na AppStore, sendo introduzido aos recursos e às

ferramentas necessárias.

Através de exemplos práticos e explicativos, você terá uma melhor noção de como funciona a

lógica das ferramentas e dos objetos, para que em pouco tempo, já esteja caminhando com as

próprias pernas, e claro, ganhando dinheiro com seus apps!

Pré-requisitos (2)

Para rodar o Xcode (plataforma de desenvolvimento para iPhone), é necessário ter um

computador da Apple com o MacOS X, pois ainda não há versão em outros sistemas

operacionais. Desejável que se tenha um dispositivo (iPhone ou iPod Touch ou iPad). Na

maioria dos testes é possível utilizar o simulador disponível no pacote de desenvolvimento.

Para realizar testes nos dispositivos, é necessário que se tenha a chave de desenvolvedor

acoplada (Provisioning profile).

Houve casos de pessoas que conseguem rodar o MacOS X em máquinas virtuais no Windows

sem problemas, tal instrução não será colocada aqui pois o procedimento pode variar de acordo

com a máquina e versão do MacOS, mas é possível achar facilmente na Internet os

procedimentos.

A plataforma iPhone/iPod/iPad (3)

Um ponto pode parecer muito óbvio agora, mas na hora de desenvolver, muita gente esquece: o

quesito de limitações de hardware. Vocês já devem ter ouvido falar, por aí, que “smartphone

não é um PC” ou algo do gênero. Pois bem, isso é bem verdade. O fato é que, apesar de ser algo

em teoria inferior, não impede que possamos fazer o melhor uso do que temos em mãos.

Na hora de projetar uma aplicação, pense nela na forma mais otimizada possível. Pense que, ao

invés de criar um aplicativo grande, com vários recursos que muitas vezes não serão utilizados,

considere a possibilidade de dividí-los em apps menores, com tarefas mais focadas.

Vantagens da plataforma Ios (4)

Única fonte de distribuição. Apesar de parecer algo monopolista e centralizador, facilita

muito na hora de gerenciar a venda do aplicativo, por deixar que um meio apenas zele pela

parte comercial do seu programa.

Público alvo, em boa parte, elitizado. Por ser um produto muito conhecido pelo status, boa

parte dos usuários de iOS não se importam em pagar por programas que, em sua maioria, têm

valores irrisórios.

Page 7: Curso iosx

Total compatibilidade com hardware. Salvo algumas exceções, como em atualizações e dos recursos de telefonia apenas disponíveis apenas para iPhone, no geral, não há preocupação com o hardware no qual o app será usado, justamente pela exclusividade da plataforma iOS estar presente em dispositivos móveis da Apple.

Cocoa Touch Framework (5)

Consiste numa biblioteca de APIs, objetos e runtimes que herdam a camada de

desenvolvimento do sistema operacional. No MacOS, trabalha-se com o Cocoa, que

engloba todos os mecanismos do sistema operacional para o desenvolvimento de

aplicações (janelas, menus, botões, etc), enquanto no iOS se utiliza do Cocoa Touch,

com o mesmo background do Cocoa. No entanto, com funções específicas para a

plataforma móvel, como multitouch, views, gps, acelerômetro, etc.

Hierarquia do Cocoa Touch Framework

Sobre o Apple Developer Program (6)

Até o momento, a única maneira de distribuir seus aplicativos oficialmente para os

usuários finais é através da AppStore da Apple. A inscrição é um processo um pouco

burocrático e demorado, sendo necessário o envio de cópias dos seus documentos via

fax para a Apple. Além disso, todo aplicativo submetido deverá passar pelo controle de

qualidade antes de ser publicado.

Page 8: Curso iosx

A taxa anual do programa é de US$ 99,00 para o programa padrão, que permite a

distribuição na AppStore. Há um programa para empresas que desejam desenvolver

apps in-house, sem distribuição pública (na AppStore). Para a inscrição deste programa,

o valor anual é de US$ 299,00 e a empresa deverá comprovar o endereço nos EUA, o

que já elimina boa parte dos aspirantes ao programa.

Maiores informações, visite o site do programa http://developer.apple.com/ iOS SDK (7)

O iOS SDK contém um conjunto completo de ferramentas para desenvolvimento em

iOS, para Mac e tudo que esteja relacionado a Apple. No nosso curso, vamos focar

apenas nas ferramentas que diz respeito ao iOS. São elas: o Xcode, Interface Builder e o

iOS Simulator.

Você pode adquirir o iOS SDK gratuitamente no site

http://developer.apple.com/xcode/index.php. É necessário que se faça um cadastro antes

de baixá-la. Xcode (8)

É onde todo código relacionado ao seu app será feito. Todos os frameworks, classes,

arquivos adicionais, XIBs, tudo estará concentrado neste programa, além da compilação

e execução.

Interface padrão do Xcode 4

Page 9: Curso iosx

Interface Builder (9)

Toda a parte visual do seu app será desenvolvido no Interface Builder. Nele você

encontra todo o conjunto de ferramentas e objetos herdados do Cocoa Touch

Framework. Os arquivos gerados nele (NIBs) não contém nenhum código acoplado,

apenas a disposição dos elementos da interface.

Na versão 3 do SDK, o IB ainda é um programa à parte. Na versão 4, ele já se torna

único com o Xcode. Neste curso, o foco será dado à versão 4.2.

Apesar dos arquivos do Interface Builder (IB) serem chamados de NIB (NextStep

Interface Builder), a extensão é .xib, pois atualmente se usa do XML para a formatação.

Por razões históricas, mantém-se esta nomenclatura.

Entenda as janelas do IB

Janela de Projeto

Este é o gerenciador de projeto. Centraliza todos componentes necessários para a

criação da interface. Por padrão, os três primeiros ícones estarão incluídos no projeto

(File’s owner, First responder e o Controller), que são fundamentais para a integração

com o código. O objeto Window já corresponde à parte visual, sendo todos os

elementos gráficos subordinados a ele.

Library

Page 10: Curso iosx

A Library contém essencialmente os objetos para serem usados. Podemos compará-la

com uma caixa de ferramentas, onde tudo está disponível para o uso.

View

Page 11: Curso iosx

Esta é a sua área de trabalho, sua tela onde será desenhada a interface gráfica do seu

app. Cada agrupamento de objetos dentro da janela (window), denomina-se view.

Inspector

O Inspector permite a personalização dos objetos inseridos na view. Toda a

configuração, desde a parte visual até a definição dos métodos é feita nesta tela.

Estudaremos com mais detalhes adiante

Page 12: Curso iosx

iOS Simulator (10)

Para testar seu aplicativo sem a necessidade de um iPhone ou iPad, você pode usar o

iOS Simulator, que engloba a maioria das funções do dispositivo móvel. Claro que, para

um teste mais apurado e fiel, o iPhone é mais recomendado, mas para a maioria dos

casos, o iOS Simulator atende bem.

iPhone Simulator

Page 13: Curso iosx

iPad Simulator

Hello World (11)

Seguindo os protocolos de boas maneiras para o aprendizado de uma linguagem de

programação, vamos quebrar o gelo com o Hello World.

Inicie um novo projeto no XCode. Se estiver na tela inicial, escolha Create New

XCode Project, ou vá em File -> New Project ou aperte Cmd + shift + N.

Page 14: Curso iosx

Tela inicial do XCode

Tenha certeza que você está em iOS/Application. Escolha Single View Application.

Em product tenha certeza que tenha escolhido iPhone. Clique em choose e dê o nome

de PrimeiroApp.

Importante, para todos os exemplos adotados neste curso, a opção USE

STORYBOARD deve está desmarcada.

Page 15: Curso iosx

Novo projeto

Page 16: Curso iosx

Apresentando a interface (12)

A seguir, você tem a área de trabalho do XCode. À esquerda, você verá os arquivos

com as classes, frameworks, Supporting Files e etc. E, à direita, a área no qual você vai

editar estes arquivos.

XCode com o projeto aberto

Em Supporting Files, clique duas vezes em ViewController.xib. Este arquivo contém a

view no qual a nossa interface será criada. Ao fazer isso, abriremos o Interface Builder.

Page 17: Curso iosx

Criando a interface (13)

Abra o arquivo ViewController.xib e verás o Interface Builder.

Deixaremos o fundo da view branca, para isso, no Inspector, mudaremos a cor do fundo

de acordo com a imagem abaixo.

Page 18: Curso iosx

Na lista de objetos, clique e arraste um objeto Label para dentro da view. Dê um clique

duplo sobre ela e coloque o texto Digite seu nome:.

Page 19: Curso iosx

Faça o mesmo com o objeto TextField. Coloque abaixo do Label. Redimensione-o pela

lateral.

Insira agora um botão abaixo do TextField. Dê um clique duplo e coloque o texto Diga

olá!

Page 20: Curso iosx

E por fim, insira mais um label abaixo do botão. Redimensione-o para que que ocupe a

largura da view e altere a cor para vermelho. Este label responderá ao evento do botão.

Page 21: Curso iosx

E pronto! agora precisamos de fazer as conexões entre os elementos ao controller, para

que o nosso app possa funcionar.

Page 22: Curso iosx

Referências aos objetos da interface (14)

Agora, de volta ao XCode. Abra o arquivo ViewController.h. Neste arquivo vamos

criar as referências aos objetos criados na view, para que possamos passar os eventos e

recolher as propriedades.

Logo abaixo do @interface, vamos declarar o label que vai receber a mensagem e o

textfield no qual vai passar o valor para ser processado.

IBOutlet UILabel *mensagem;

IBOutlet UITextField *nome;

E logo abaixo, depois das {}, vamos declarar o método que vai receber o evento do

toque sobre o botão.

-(IBAction) dizerOla;

O código no final deverá estar assim:

@interface ViewController : UIViewController

{

IBOutlet UILabel *mensagem;

IBOutlet UITextField *nome;

}

-(IBAction) dizerOla;

@end

Page 23: Curso iosx

Conexões da view x controller (15)

Abra o ViewController.xib e tenha a janela Project a vista. Clique com o botão direito

no File's Owner, arraste e solte sobre o TextField. Um menu suspenso aparecerá.

Escolhe o nome.

Faça o mesmo com label Olá. Marque a opção mensagem.

Page 24: Curso iosx

Agora vamos atribuir o evento dizerOla: ao botão. Mas neste caso, faremos o caminho

inverso, clique com o botão direito sobre o botão e arraste sobre o File's Owner.

Escolha o método dizerOla:.

Page 25: Curso iosx

Pronto, todas as conexões estão feitas entre o View e o Controller.

Page 26: Curso iosx

Implementações (16)

Feitas as conexões, vamos ao código. O que fizemos antes no arquivo .h foi a

declaração dos cabeçalhos. A partir dele, precisamos implementar a classe. Faremos no

arquivo ViewController.m.

Logo abaixo do @implementation, colocaremos o método que declaramos

anteriormente:

-(IBAction) dizerOla

{

}

O nosso objetivo ao acionar o botão Diga Olá, é que o label mensagem receba a

mensagem que foi escrita no textfield. Isso se fará com a seguinte linha, que será

inserida dentro das chaves { }

-(IBAction) dizerOla

{

[mensagem setText:[nome text]];

}

Sendo:

mensagem e nome: os IBOutlets declarados e ligados a view.

setText: comando para alterar a propriedade text do label mensagem.

Execute e verá como fica

Page 27: Curso iosx

Execução

Refinando a mensagem de exibição (17)

Podemos melhorar um pouco a exibição da mensagem, já o que o botão está dizendo

“Diga olá!”, vamos fazer o label atender desta forma.

[mensagem setText:[NSString stringWithFormat:@"Olá %@!", [nome text]]];

Sendo:

NSString: objeto de manipulação de Strings.

stringWithFormat: método para formatar strings com caracteres curinga. Estes são

representados pelo sinal % e seguido do símbolo que representa o tipo.

%@ : caracter curinga que representa a saída de qualquer objeto.

Execute e veja como ficou!

Page 28: Curso iosx

A linguagem de programação (18)

Apesar de existirem vários frameworks de desenvolvimento para iOS alternativos,

como para HTML5, Flash e afins, a linguagem padrão, e que na prática roda as

aplicações, é o Objective-C. Esta linguagem, apesar de parecer um pouco estranha no

começo, com a prática se torna de simples compreensão e que com poucas linhas de

código você fará bastante coisa.

O Objective-C (também chamada de objC) é uma linguagem de programação simples

com sofisticados meios de orientação a objeto. Pode ser definida como um conjunto de

extensões do ANSI C, a fim de dar ao C uma completa implementação de orientação a

objetos, numa maneira mais simples e direta.

Page 29: Curso iosx

Padrão MVC (19)

O Modelo MVC (Model, View, Controller) é um padrão que isola a interface gráfica

(view) do núcleo do sistema (model), permitindo que ambas as partes possam ser

desenvolvidas independentes de uma da outra, além de ter um melhor re-

aproveitamento do código. O controller faz o papel de ponte entre o model e a view.

Padrão MVC

Model (20)

Gerencia os dados e estados do app

Sem preocupação com a interface gráfica, apenas os dados

Funcionamento persistente

O mesmo modelo pode ser reutilizado em várias interfaces diferentes

View (21)

Mostra ao usuário os dados contidos no Model

Permite a manipulação dos dados

Não salva dados (no caso do iOS, a exceção está no cache state, que veremos com detalhes no

capítulo sobre views)

Reutilizável e configurável para exibr diferentes tipos de dado de maneira simples

Page 30: Curso iosx

Controller (22)

Intermedia o Model e a View

Atualiza a View quando há alteração no Model

Atualiza o Model quando o usuário manipula a View

Geralmente é onde está a lógica do app

MVC no Objective-C (23)

Vejamos agora como funciona na prática o padrão MVC na hora de programar seu app.

No esquema abaixo, vemos que o Model Object, substrato do programa, se comunica

diretamente ao Controller através do Outlet, que se comunica com a View diretamente

ao objeto alvo.

No caminho de volta, vemos que a View, se comunica com o Controller, pelas Actions,

que corresponde a algum método de interação com o usuário.

Outlet: é a representação do objeto. Em algumas linguagens de programação, seria o

parâmetro name. Em código, este é declarado como IBOutlet.

Action: declaração de um evento associado a um método, por exemplo, a chamada de

uma função ao clicar num botão. Em código, é declarado como IBAction.

Page 31: Curso iosx

Esquema MVC no Objective-C

2 - A linguagem de programação

2.1 - Padrão MVC

2.2 - Estrutura e padrões do código o 2.2.1 - Declaração de funções e métodos

o 2.2.2 - Declaração de métodos estáticos

o 2.2.3 - Declaração de métodos com um objeto de retorno

o 2.2.4 - Ciclo de vida de um objeto

2.3 - Orientação a objeto em poucas linhas

2.4 - Criando as classes em objC

2.5 - NSLog

2.6 - Variáveis e Objetos

2.7 - Condições

2.8 - Laços de repetição

2.9 - Getters, Setters e propriedades

2.10 - Protocolos

2.11 - Na prática

3 - Objetos de interface com o usuário

Page 32: Curso iosx

Estrutura e padrões do código (24)

No objC há algumas diferenças nas notações de sintaxe, algo que a princípio pode parecer

estranho, mas você verá que não há grandes mistérios, além do que em pouco tempo já estará

familiarizado.

Declaração de funções e métodos (25)

Toda função e/ou método do objeto é declarado seguindo a seguinte sintaxe:

- (tipo_de_retorno) funcao {

// ... instruções

}

Exemplos

-(id)init;

-(float)altura;

-(void)executar;

O sinal de menos “-” no início da declaração, indica ao compilador que este método é do

objeto, ou seja, é válido quando o objeto é instanciado.

Função com argumentos

Caso deseje declarar uma função com parâmetros, segue a sintaxe:

-(tipo_de_retorno) funcaoComParametro1: (tipo_do_param)varParam1

parametro2:(tipo_do_param)varParam2 {

// instrucoes

}

Exemplos

-(id)initWithName:(NSString *) nome;

-(float)calculaAreaQuadradoComLado1:(float) lado1 lado2:(float) lado2;

Page 33: Curso iosx

Alguns tipos de variáveis mais usados

void a função não exige retorno

id representa qualquer objeto

int a variável de retorno é inteiro

Métodos estáticos são aqueles que podem ser invocados pela classe, sem precisar instanciar o

objeto.

A estrutura para para declará-los é a mesma das citadas anteriormente. O que diferencia é o

sinal da declaração: no lugar do sinal de menos “-” usa-se o sinal de mais “+”.

+ (id)alloc

Para chamar um método estático, segue-se a seguinte estrutura:

[ClasseDoObjeto metodoEstatico];

Declaração de métodos estáticos (26)

Métodos estáticos são aqueles que podem ser invocados pela classe, sem precisar instanciar o

objeto.

A estrutura para para declará-los é a mesma das citadas anteriormente. O que diferencia é o

sinal da declaração: no lugar do sinal de menos “-” usa-se o sinal de mais “+”.

+ (id)alloc

Para chamar um método estático, segue-se a seguinte estrutura:

[ClasseDoObjeto metodoEstatico];

Declaração de métodos com um objeto de retorno (27)

Nos exemplos anteriores, você pode ter notado um * logo após o tipo do objeto. No objC, todo

objeto é declarado como ponteiro dentro de uma função.

-(NSObject *)estaFuncaoRetornaUmObjeto {

// Instrucoes

return objeto;

}

O NS (abreviação de Next Step) sinaliza que o objeto é original do objC. Os demais são

herdados do C.

Page 34: Curso iosx

Alguns tipos especiais do Interface Builder

IBAction indica a declaração de um método. Tem o mesmo valor do void, com a diferença de

que desta forma, o Interface Builder vai reconhecer que a função a seguir é um método a ser

acoplado a um objeto da interface gráfica (UIKit).

-(IBAction)clickNoBotao:(id)sender;

IBOutlet indica a declaração de um objeto da interface gráfica. Serve apenas para que o

Interface Builder reconheça no código. Não é necessariamente um tipo de objeto, apenas uma

flag.

IBOutlet UILabel *lblNome;

Ciclo de vida de um objeto (28)

A linguagem objC é totalmente orientada ao objeto. Logo, precisamos entender como funciona

o ciclo de vida do objeto, desde quando são instanciados.

Alocação e inicialização

Todo objeto, quando instanciado, deve estar alocado numa variável e em seguida inicializado.

A maneira mais simples de se inicializar segue-se na sintaxe:

NomeDaClasse *variavel = [[NomeDaClasse alloc] init];

Por padrão, todo objeto é declarado como ponteiro, incluindo o asterisco na frente da

variável. Esta notação do ponteiro é herança da linguagem C, que representa o endereço físico

da variável na memória.

Esta é a forma mais comum de se inicializar um objeto. Há objeto que pode-se passar

parâmetros na inicialização. O melhor exemplo é na variável NSString:

NSString *resultado = [[NSString alloc] initWithString:@?Texto da variável?];

Estas formas de inicialização são particulares de cada objeto.

Nota de atualização para o iOS5: a partir desta versão, um novo mecanismo denominado

ARC (Automatic Reference Counting) no qual faz o gerenciamento de memória é por conta do

compilador e não mais pelo usuário. Portanto, considere as informações a seguir apenas se for

desenvolver para versões anteriores do iOS (o que não é recomendado). Ao longo do curso, o

foco será dado ao iOS5, logo, informações como release/retain não serão usados.

Page 35: Curso iosx

Dealocação

Para limpar o objeto da memória, usa-se o método release no objeto.

[resultado release];

Você pode usar este comando quando não for mais necessário o objeto. Se o objeto for uma

variável de instância, este poderá ser dealocado num método especial dentro do objeto que

esteja trabalhando:

-(void) dealloc {

[resultado release];

[super dealloc];

}

Desta forma, quando o objeto pai for dealocado, todos os que estiverem contidos nesta função,

serão liberados em fila. Por padrão, toda clase tem o método dealloc a ser implementado.

[resultado autorelease];

Retenção

Uma vez que você instancia o objeto, pode ser que seja necessário garantir que o objeto persista

na memória. Neste caso, usa-se o método retain.

Seguindo o exemplo da string criada anteriormente, a sintaxe funcionaria da seguinte maneira:

[resultado retain];

Imaginemos um contador acoplado ao objeto. Toda vez que um objeto é instanciado, este

contador recebe o valor 1. A cada retain invocado no objeto, este contador soma 1 e a cada

release, este contador diminui 1. Quando este contador chega a zero, o objeto é liberado da

memória.

Ciclo de vida de um objeto

Page 36: Curso iosx

Orientação a objeto em poucas linhas (29)

Classe ( concentra as variáveis e códigos. É o código do objeto a ser instanciado propriamente

dito. O nome da classe determina o nome do tipo de objeto.

Objeto ( é a declaração de uma instância de uma classe.

Instância ( é a alocação de uma classe na memória. Uma classe pode ter várias instâncias de

um objeto.

Método (: é a função acoplada a um objeto. Toda mensagem e instrução enviada ao objeto, se

faz por intermédio de um método.

Variável de instância (: um pedaço específico de dados que pertence a um objeto.

Encapsulamento ( mantém a implementação privada e separada da interface.

Polimorfismo ( capacidade de uma mesma classe possuir diversas instâncias distintas de

objetos.

Herança ( possibilita que um novo objeto herde funcionalidades de um outro objeto.

Mensagem ( forma de troca de dados com um objeto.

Criando as classes em objC (30)

Chega de teoria! Vamos agora ao que interessa: como criar as classes no objC.

Esta parte introdutória é super importante para que vocês entendam todo o background da

linguagem de programação, facilitando o entendimento.

Arquivo .h

O arquivo .h (header) contêm todas as declarações de variáveis e métodos da classe. Utliza-se

nesta declaração os métodos que se tornarão públicos, ou seja, os métodos acessíveis na

instância do objeto.

Page 37: Curso iosx

Exemplo

#import <Foundation/Foundation.h>

@interface Objeto : NSObject {

NSObject *exObjeto;

}

@property (nonatomic, retain) NSObject * exObjeto;

-(void)exemploDeMetodo;

@end

Fique tranqüilo que a estrutura básica é gerada automaticamente pelo Xcode.

Page 38: Curso iosx

Arquivo .m

Contém a implementação da classe. No .h foram apenas declaradas as variáveis e funções, mas

não há nenhuma implementação.

Seguindo o exemplo anterior:

#import "Objeto.h"

@implementation Objeto

@synthesize exObjeto;

-(void) exemploDeMetodo

{

// implementação

}

@end

Não se preocupe se não entendeu o que está escrito. Tudo isso será explicado em breve.

Page 39: Curso iosx

Padrões de mensagens (31)

Já vimos anteriormente como se declaram métodos e, nos exemplos antes mostrados, já deve se

tem uma noção de como chamá-los de maneiras mais detalhadas.

[objeto mensagem];

A declaração mais simples de invocação de um método. A notação entre colchetes [ .. ] é a

forma padrão do envio de mensagens ao objeto.

Imagine que o método acima chamado, esteja contido numa classe chamada objeto e que tenha

a seguinte implementação:

-(void)mensagem;

Mensagens com mais de um argumento

[objeto mensagem1:argumento1 mensagem2:argumento2 ...];

Desta vez, argumentos são passados na chamada do método, podendo ser um ou mais valores,

dependendo de como foi construída a função. Imaginemos a implementação deste método:

-(void)mensagem1:(int)argumento1 mensagem2:(float)argumento2;

Notação por ponto

Desde a versão 2.0 do objC, foi introduzida a notação por ponto para invocar métodos de um

objeto, como acontece na maioria das linguagens de programação. Ambas as sintaxes estão

corretas, cabe a você escolher qual é a mais confortável.

Desta vez, vamos com um exemplo prático. Suponha que temos um objeto chamado pessoa,

que nele vamos definir e receber os valores da altura.

float alt = [pessoa altura];

float alt = pessoa.altura

Em ambos os exemplos, foi declarada a variável alt como float e na inicialização já recebera o

valor da variável de instância altura.

Para chamar os métodos de um objeto passando valores, segue-se os exemplos:

[pessoa setAltura:novaAltura];

pessoa.altura = novaAltura;

Neste caso, o objeto pessoa está recebendo o valor novaAltura. Nota-se uma pequena diferença

acima, na notação de colchetes, há um antes da variável. Esta é uma notação padrão do objC

para declaração de métodos getters e setters. Veremos com mais detalhes quando estudarmos as

declarações de propriedades.

Page 40: Curso iosx

NSLog (32)

Retomando o que vimos na introdução, usamos este comando que dá saída no console. Este

comando é de extrema utilidade, principalmente na hora do debug.

NSLog(@"mensagem de saída");

Esta é a forma mais simples de dar saída a uma mensagem. O "@" antes da mensagem significa

que a sequência é do tipo NSString.

NSLog(@"o valor inteiro é %d, o float é %f e o NSString é %@", varInt, varFloat,

varNSString);

Este exemplo ilustra como concatenarmos variáveis dentro de uma string. No lugar de %d

(para int), %f (para float) e %@ (para NSString), teremos estes curingas substituídos pelos

valores de varInt, varFloat e VarNSString.

Variáveis e Objetos (33)

Veremos agora os objetos e variáveis mais comuns e suas principais funções.

Strings (34)

Toda seqüência alfanumérica determina-se String. Originalmente, no C, a variável era definida

pelo tipo char. Entretanto, há algumas limitações, como por exemplo, a falta de suporte a

algumas codificações. Neste caso, surge o tipo NSString e sua subclasse, NSMutableString.

Veremos sobre elas agora.

Page 41: Curso iosx

NSString e NSMutableString (35)

Inicializa uma variável string com valor imutável, ou seja, uma vez que um valor é associado,

não poderá ser alterado. Caso deseje que a string possa ter o valor alterado, usa-se a subclasse

NSMutableString, que instancia uma variável ainda do tipo String, com as mesmas funções e

métodos, porém, com valor alterável. Vale lembrar que todos os métodos abaixo listados

servem para ambas as classes.

Para inicializar um NSString:

NSString *imutavel = [[NSString alloc] init];

E um NSMutableString:

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

Para atribuir um valor a um NSString:

imutavel = @"valor que uma vez adicionado não poderá ser alterado";

mutavel = @"valor que poderá ser alterado em qualquer momento";

Formas de inicialização (36)

-(id) initWithString:

Inicializa a string com um valor acoplado.

NSString *exemplo = [[NSString alloc] initWithString:@"valor inicial"];

-(id) initWithFormat:

Inicia a string com um valor com variáveis concatenadas.

int valorinteiro = 15;

NSString *exemplo = [[NSString alloc] initWithFormat:@"o valor inteiro = %d", valorinteiro];

Page 42: Curso iosx

Principais métodos (37)

UTF8String

Retorna o valor da string compatível com o tipo char do C.

char texto = [obj_nsstring UTF8String];

intValue

Retorna o valor do tipo int, se a string tiver conteúdo numérico.

int valor_inteiro = [obj_nsstring intValue];

isEqualToString

Retorna um valor bool (true ou false / YES ou NO) ao comparar duas strings

NSString *string1 = [[NSString alloc] initWithString:@"abcdef"];

NSString *string2 = [[NSString alloc] initWithString:@"ghij"];

BOOL result1 = [string1 isEqualToString:string2]; // result1 = NO

BOOL result2 = [string1 isEqualToString:@"abcdef"]; // result2 = YES

length

Retorna o número de caracteres unicode contidos na string.

NSString *variavel = [[NSString alloc] initWithString:@"ABCDEF"];

int quantidade = [variavel length]; // quantidade = 6

Números (38)

Os tipos numéricos mais usados no objC o int e o float, ambos herdados do C.

int admite valores inteiros.

float admite valores fracionários.

Formas de declaração:

int variavel_inteira;

float variavel_fracao;

int contador = 1;

float pi = 3.1415;

No objC existe também o objeto NSNumber, que seria uma versão objeto que engloba vários

tipos de valores numéricos.

Page 43: Curso iosx

Valores lógicos (39)

Os tipos lógicos (booleanos) admitem valores de verdadeiro ou falso. No objC, estes valores

podem ser denominados como true e false ou como YES e NO. Ambas as representações são

idênticas.

Para declarar uma variável lógica:

BOOL variavel;

O tipo BOOL é herdado do C, logo não tem valor de objeto, não sendo necessária a declaração

como ponteiro.

Arrays (40)

Assim como o NSString, O NSArray instancia um objeto array com valores já definidos, sem

poder ser alterado, ao contrário do NSMutableArray, que poderá ter o conteúdo alterado.

Para inicializar um array:

NSArray *arr = [[NSArray alloc] initWithObjects:@"obj1", @"obj2"

, @"obj3", nil];

NSMutableArray *mArr = [[NSMutableArray alloc] init];

Sempre que for inicializar um array com uma série de objetos, nunca se esqueça de colocar o

terminador nil.

Page 44: Curso iosx

Principais métodos (41)

count

Retorna o número de objetos que contém num array.

int qtd = [arr count]; // retornará 3

objectAtIndex:

Retorna um objeto do tipo id a partir de um índice. O primeiro item do array está no índice 0.

id linha2 = [arr objectAtIndex:1]; // Retorna ao objeto NSString com o valor obj2

Sobre o tipo id explicaremos a seguir.

Métodos exclusivos do NSMutableArray

addObject:

Insere um novo registro no array.

[arr addObject:@"obj4"]; // Adiciona a quarta linha com o objeto NSString com o valor "obj4"

insertObject:atIndex:

Insere um novo registro no array num índice determinado.

[arr insertObject:@"entre 2 e 3" atIndex:1];

Se o índice já estiver ocupado, os objetos, a partir do ponto indicado, moverão para um nível

acima, para dar espaço ao novo objeto inserido.

removeObjectAtIndex:

Remove o objeto do array localizado no índice.

[arr removeObjectAtIndex:2];

Dicionários (42)

Similar aos arrays, temos o NSDictionary e o NSMutableDictionary que são objetos que

também enumeram valores vetoriais, mas neste caso, você pode determinar valores nos índices,

ao invés destes serem numerados.

NSDictionary *dict = [[NSDictionary alloc] initWithObjects:(array) forKeys:(array)];

Neste caso, o número objetos em ambos arrays devem ser iguais.

NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:@"valor1", @"chave1",

@"valor2", "chave2",....,nil];

Este caso é bem similar ao primeiro método, com a diferença de que os valores estão

enumerados aos pares, seguindo respectivamente o valor e a chave, com o terminador nil.

Page 45: Curso iosx

Principais métodos (43)

count

Funcionamento idêntico ao NSArray, inclusive na sintaxe.

allKeys

Retorna um NSArray com todas as chaves contidas num NSDictionary.

NSArray *keys = [dict allKeys];

allValues

Retorna um NSArray com todos os valores contidos num NSDictionary.

NSArray *values = [dict allValues];

Métodos exclusivos do NSMutableDictionary

setObject:forKey:

Insere um novo objeto no NSDictionary.

[dict setObject:@"valor" forKey:@"nome da chave"];

removeObjectForKey:

Remove o objeto do NSDictionary.

[dict removeObjectForKey:@"nome da chave"];

Objeto id (44)

Este objeto é um caso especial, pois pode assumir todos os tipos de valores no escopo do

objeto. Apesar ser um objeto do objC, não se declara como ponteiro, a não ser que você

realmente precise de tal declaração, mas no uso comum, não é utilizado.

Page 46: Curso iosx

Condições (45)

Como em qualquer linguagem de programação usamos a estrutura if... else

if (condição) {

...

}

else if (condição) {

...

}

else {

...

}

Nas condições, usa-se a seguinte notação para comparação:

== -> igual

!= -> diferente

>, <, >=, <= maior, menor, maior ou igual, menor ou igual

Laços de repetição (46)

O objC usa basicamente três estruturas de repetição: for, while, e do..while.

Page 47: Curso iosx

O loop “for” (47)

Estrutura

for (valor inteiro inicial, condição, expressão do loop)

{

...

}

Exemplo:

for (int x=1; x<10; x++)

{

NSLog(@"O valor de x está em %d", x);

}

Neste caso, o laço se seguirá de 1 em 1 com a variável x, que se iniciará no valor 1 e terminará

no 9.

Loops infinitos

for (;;)

{

// ....

}

Interrompendo um loop for

for (int x=1; x<100; x++)

{

// ....

break;

}

Laços “while” e “do…while” (48)

Estrutura "while"

while (condição)

{

//..

}

Se a condição for verdadeira, executa o bloco repetidamente até se tornar falsa. Se a condição

desde o princípio já for falsa, o bloco não é executado.

Exemplo

int x = 1;

while (x<10)

{

//...

x++;

}

Page 48: Curso iosx

Estrutura "do... while"

do

{

//...

} while (condicao)

Segue a mesma lógica da estrutura anterior, com a diferença de que, antes de avaliar a

condição, o bloco é executado.

Getters, Setters e propriedades (49)

Como toda boa linguagem de programação OOP, uma das características dos objetos que deve

ser mantida e respeitada é a do encapsulamento, que implica a não-permissão de acesso às

variáveis de instância diretamente a elas, mas sim, por meio de métodos que são denominados

getters (que recupera o valor) e setters (que determina um valor).

Felizmente, o objC, neste caso, trabalha de uma forma muito simplificada, ao ponto de fazer

parte deste trabalho para você. Para isto, declaramos uma variável/objeto como propriedade.

Declaração de propriedades (50)

No arquivo .h, você já deve ter visto a instrução em outros exemplos:

@property (nonatomic, retain) NSString *exemploPropriedade;

E no arquivo .m

@synthesize exemploPropriedade;

Pois bem, estas instruções nada mais fazem do que declarar dois métodos para o objeto, que são

exemploPropriedade (getter) e o setExemploPropriedade (setter).

Por padrão, a primeira letra do nome do objeto passa a ser maiúscula na declaração do setter.

Logo, supondo que estejamos trabalhando na classe chamada Objeto, o código ficaria assim:

// Aloca e inicaliza o objeto

Objeto obj = [[Objeto alloc] init];

[obj setExemploPropriedade:@"valor"];

NSObject retorno = [obj exemploPropriedade];

Page 49: Curso iosx

Atributos das propriedades (51)

E quanto ao nonatomic e retain que estão entre parênteses? São chamados os atributos das

propriedades, o que determina como o compilador vai lidar com os objetos na hora de gerar o

getter e o setter. Os principais são:

readwrite: quando você quer que a propriedade seja modificável. O compilador irá gerar

um getter e um setter. É o padrão, caso não declare nada.

readonly: quando você não deseja que o valor seja alterável. O compilador não irá gerar

um setter, apenas um getter.

assign: usado quando você estiver lidando com tipos básicos do C (int, float, etc.). O

compilador irá gerar um setter para estes valores. É o padrão, mas não é o mais usual de

todas as opções.

retain: é usado quando se trabalha com objetos. Ao receber um novo valor, o objeto irá

se assegurar que o valor seja mantido até que um novo chegue.

copy: quando você quer uma cópia do valor passado ao invés do valor por si só.

nonatomic: assegura que o objeto terá um controle na hora de receber e enviar novos

valores, evitando crash no app no tempo de execução.

Em 99% dos casos, quando for trabalhar com objetos, acredite na combinação (nonatomic,

retain). É sem dúvida a mais usada e atende a todas as necessidades.

Protocolos (52)

Toda classe no objC é herdada de uma única classe que, por seguinte, esta é herdada de outra,

até chegarmos no NSObject. Mas e quando precisamos herdar métodos de outros objetos que

não estão nesta hierarquia? Neste caso, usamos os protocolos.

Os protocolos são declarações que fazemos dentro do cabeçalho, logo após a declaração da

interface, entre <>, como no exemplo abaixo:

@interface QualquerViewController : UIViewController <UITableViewDelegate,

UITableViewDataSource>

Esta declaração vai herdar os métodos das classes declaradas dentro dos <>. A melhor

aplicação disso poderemos ver nos próximos capítulos.

Page 50: Curso iosx

Na prática (53)

Vamos entender agora como funciona, na prática, a criação e a declaração de objetos.

Inicie um novo projeto (File > New project ou Cmd Shift N) no Xcode. Escolha o Single View

Application como nome de TesteClasses.

Na lista Groups & Files à esquerda, clique na aba Classes. Ali se encontram dois grupos de

arquivos: ~AppDelegate e ~ViewController. Como não trabalharemos a parte visual neste

projeto, mexeremos agora apenas no AppDelegate.

Neste exemplo criaremos uma classe simples que armazenará uma relação de nomes e idade,

apenas para ilustrar o funcionamento da classe. Demonstraremos também como se declara um

método e um construtor.

Crie um novo arquivo (File> New> File... ou Cmd N) e na guia iOS > Cocoa Touch, escolha

Objective-C Class e na subclass escolha NSObject. Clique em NEXT.

Em File Name, coloque Contatos.m e certifique-se que “Also Create Contatos.h” esteja

selecionado. Clique em FINISH.

Se já não estiver assim, arraste os dois arquivos criados para o grupo Classes, conforme a

imagem abaixo:

Configuração do XCode

Page 51: Curso iosx

Configurando as variáveis de instância (54)

Para este exemplo, vamos trabalhar com dois campos: nome e idade. No arquivo Contatos.h,

deverá ficar assim:

@interface Contatos : NSObject {

NSString *nome;

NSNumber *idade;

}

@property (nonatomic, retain) NSString *nome;

@property (nonatomic, retain) NSNumber *idade;

-(id)initWithName:(NSString *)n age:(NSNumber *)i;

-(BOOL)isMaiorDeIdade;

Explicação do código

O código começa com a declaração do cabeçalho do objeto, definindo o nome da classe e qual é

a classe-pai.

@interface Contatos : NSObject

Dentro das chaves, estão declaradas as variáveis de instância do objeto. No caso do nome,

colocamos do tipo NSString, e a idade do tipo NSNumber. Não declaramos aqui do tipo int pois

é mais fácil e direto trabalharmos com classes ao invés dos tipos do C.

NSString *nome;

NSNumber *idade;

Logo abaixo, criamos as propriedades para tornar as variáveis de instância acessíveis a outros

objetos. Como já vimos anteriormente, a chamada @property declara automaticamente um

getter e um setter para um objeto.

@property (nonatomic, retain) NSString *nome;

@property (nonatomic, retain) NSNumber *idade;

Em seguida determinamos os métodos acessíveis ao objeto. O initWithName determina que o

objeto deve ser inicializado com os parâmetros Nome e Idade. Apesar da nomenclatura em

inglês nesta declaração, não precisa ser necessariamente esta e com as mesmas variáveis. E

logo depois o método de exemplo que determina se a pessoa é maior de idade ou não.

-(id)initWithName:(NSString *)n age:(NSNumber *)i;

-(BOOL)isMaiorDeIdade;

Page 52: Curso iosx

Implementando a classe (55)

Agora no arquivo Contatos.m, primeiro vamos colocar pra funcionar as propriedades

declaradas. Abaixo do @implementation Contatos, insira o código a seguir:

@synthesize nome, idade;

Esta declaração implementa os métodos de entrada e saída dos objetos. Ou seja, um método

chamado nome (getter) e um chamado setNome (setter) acaba de ser criado sem ter de

propriamente criá-los. O mesmo acontece com o idade.

Em seguida, vamos declarar o construtor, conforme declaramos no .h:

-(id)initWithName:(NSString *)n age:(NSNumber *)i {

// certifica-se que você esteja trabalhando na superclasse

if (self = [super init]) {

// Define as variáveis de instância de acordo com os parâmetros

self.nome = n;

self.idade = i;

}

return self;

}

Neste caso, o self corresponde a própria instância da classe. É o equivalente ao this na maioria

das linguagens de programação.

E em seguida, o método usado como exemplo:

-(BOOL)isMaiorDeIdade {

if ([[self idade] intValue]>=18) {

return YES;

}

else {

return NO;

}

}

Neste método, na própria declaração já avisa que ele vá retornar um tipo BOOL (YES/true ou

NO/false).

-(BOOL)isMaiorDeIdade

Dentro da condição, chamamos a ivar idade, que é do tipo NSNumber, e através do método

intValue, foi retornado o valor com o tipo int.

[[self idade] intValue]

Na condição, se a idade for maior ou igual a 18, retorna YES, senão, retorna NO.

Page 53: Curso iosx

Usando a classe (56)

Utilizaremos a classe AppDelegate, que contem todos os métodos de inicialização do

aplicativo.

No arquivo AppDelegate.h, abaixo do #import <UIKit/UIKit.h>, digite:

#import "Contatos.h"

Essa linha agregará o objeto Contatos anteriormente criado à classe atual sendo usada. Toda

vez que desejar utilizar uma classe que criara, este é o procedimento.

Agora no arquivo AppDelegate.m, veja que há uma série de métodos que designam um estado

da aplicação. No nosso caso, precisamos quando o app estiver iniciado, logo, usaremos o

primeiro método, o didFinishLaunchingWithOptions. Este método já está implementado e não é

aconselhado que se modifque o que já está escrito.

O código a seguir poderá ser escrito em qualquer parte do método antes do return. Se colocar

no começo, antes do código padrão, tudo será executado antes da aplicação se tornar visível. Se

colocar depois, apenas quando o app mostrar sua janela. No nosso exemplo, fica a seu critério.

Primeiro vamos instanciar a classe. Lembrando que toda classe no objC deverá ser alocada e

inicializada. A seguir veremos como inicializar de ambas as formas.

Contatos *contato = [[Contatos alloc] init];

No exemplo acima, foi atribuido à variável contato o objeto Contatos, mas sem parâmetros de

inicialização, ou seja, se for fazer um get em alguma das variáveis de instância, o retorno será

null. Confira:

NSLog(@"%@",[contato nome]);

Exemplos de uso (57)

Vamos supor que você queira atribuir este objeto ao nome “Maria” com a idade “20”, que são

os valores que este objeto comporta:

[contato setNome:@"Maria"];

contato.idade=[NSNumber numberWithInt:20];

Acima eu representei as duas notações usadas no objC. Ambas são idênticas, só quis

demonstrar na prática como funciona. Vale reforçar que na notação por ponto, não se usa set ao

atribuir um valor. E como idade é do tipo NSNumber, o tipo é incompatível com o tipo int,

sendo necessário convertê-lo.

[NSNumber numberWithInt:20]

Confira agora a saída pelo console

NSLog(@"Nome: %@, idade: %@",[contato nome], [contato idade]);

Algo assim será listado

TesteClasses[2727:207] Nome: Maria, idade: 20

Page 54: Curso iosx

Deixemos este objeto de stand by e vamos agora declarar um segundo, mas usando os métodos

de inicialização que criamos antes. Vamos dar o nome de João e ele tem 16 anos:

Contatos *contato2 = [[Contatos alloc] initWithName:@"João" age:[NSNumber

numberWithInt:16]];

Ao fazermos a saída:

NSLog(@"Nome: %@, idade: %@",[contato2 nome], [contato2 idade]);

Teremos:

TesteClasses[2929:207] Nome: João, idade: 16

Agora vamos testar o método que criamos. No bloco abaixo:

if ([contato isMaiorDeIdade]) {

NSLog(@"%@ pode votar", [contato nome]);

}

else {

NSLog(@"%@ ainda é menor de idade", [contato nome]);

}

Usamos dentro de um IF, caso o método retornar YES, exibirá o primeiro bloco, senão o

segundo. Tente fazer o mesmo com o outro objeto.

O código na íntegra

Contatos *contato = [[Contatos alloc] init];

[contato setNome:@"Maria"];

contato.idade=[NSNumber numberWithInt:20];

NSLog(@"Nome: %@, idade: %@",[contato nome], [contato idade]);

Contatos *contato2 = [[Contatos alloc] initWithName:@"João" age:[NSNumber

numberWithInt:16]];

NSLog(@"Nome: %@, idade: %@",[contato2 nome], [contato2 idade]);

if ([contato isMaiorDeIdade]) {

NSLog(@"%@ pode votar", [contato nome]);

}

else {

NSLog(@"%@ ainda é menor de idade", [contato nome]);

Page 55: Curso iosx

Objetos de interface com o usuário (58)

Chega de teoria, vamos a parte que nos interessa! Afinal de contas, não é só de código que é

feito o seu app, ele precisa de um visual, de uma interface intuitiva e agradável ao usuário para

garantir o sucesso do seu programa (e da aprovação pela equipe da Apple também).

Neste capítulo vamos abordar com detalhes os principais componentes visuais da biblioteca

UIKit, que incluem botões, caixas de texto, imagem, etc. Para esta parte do curso, usaremos

muito tanto o Xcode, como o Interface Builder, logo, esteja preparado para uma constante

mudança de janelas.

Sintaxe padrão para declarar um objeto no Xcode (59)

Para todos os objetos da biblioteca UIKit, utiliza-se o mesmo padrão de declaração no Xcode,

para interligar a interface ao código.

No arquivo .h, dentro do bloco @interface...

IBOutlet UIObjeto *nome_do_objeto;

e caso queira torná-la acessível publicamente:

@property (nonatomic, retain) IBOutlet UIObjeto *nome_do_objeto;

No arquivo .m, logo após o @implementation, se o @property foi declarado:

@symphesize nome_do_objeto;

Feito isso, você já pode no Interface Builder associar os objetos com o controller, clicando

sobre o File’s owner segurando o botão control e arrastando sobre o objeto na view. Em

seguida faça a associação. Estes caminhos foram descritos no tutorial do capítulo 1, no Hello

World.

Page 56: Curso iosx

Sintaxe padrão para declarar uma ação a um evento (60)

Ao tocar num botão, escrever um texto, selecionar o item numa lista, espera-se que o programa

reaja de alguma forma. Para isso, precisamos de criar uma ação a um evento. A forma mais

usual de se declarar uma ação é:

No arquivo .h, abaixo do bloco @interface...

-(IBAction) nomeDaAcao:(id)sender;

E para implementar o código, no arquivo .m...

-(IBAction) nomeDaAcao:(id)sender {

// implementação

}

O parâmetro (id)sender representa o objeto UIKit que enviou a ação.

Para associar o método do componente a uma ação, selecione o objeto; na janela de atributos,

escolha a aba de eventos (uma seta dentro de um círculo) e dentro do círculo associado ao

evento na lista (sent events), clique segurando o botão control e arraste sobre o File’s Owner.

Em seguida, selecione o evento no qual deseja associar. Este passo já foi descrito no capítulo 1.

Label, textfield, textview e botão (61)

Nesta unidade trabalharemos com estes quatro componentes em conjunto, num único exemplo,

para já ilustrarmos a ligação entre os componentes.

Label (UILabel)

Representa uma etiqueta simples, geralmente com uma linha, usado principalmente para

denominar outros objetos ao usuário. Não há eventos associados a este componente

Principais propriedades

text / setText:

Recupera / altera o texto contido no label.

NSString *texto = [objLabel text];

[objLabel setText:@"outro texto"];

Textfield (UITextField)

Campo de inserção de dados por texto em uma única linha. Entre as propriedades do inspector

para este objeto incluem, além da aparência do componente, a configuração do teclado exibido.

Principais propriedades

text / setText:

Recupera / altera o texto contido no textfield.

NSString *texto = [objTextField text];

[objTextField setText:@?outro texto?];

Page 57: Curso iosx

editing

Propriedade somente-leitura que retorna YES ou NO se o campo está sendo editado.

Principais métodos

resignFirstResponder

Por padrão, o teclado uma vez aberto, não se fecha, sendo necessário invocar este método para

fechá-lo.

[objTextField resignFirstResponder];

Principais eventos

Did End On Exit

Quando o botão RETURN for pressionado.

Value Changed

Quando o valor do campo for alterado.

Textview (UITextView)

Similar ao textfield, entretanto, com a possibilidade de exibir textos com mais de uma linha.

Sua aparência é plana e já possui um scroll automático para quando o texto ultrapassar os

limites do box.

As propriedades e métodos são similares ao do texfield. A exceção ocorre nos eventos, pois não

há nenhum vinculado a este objeto.

Botão (UIButton)

Responde às ações de toque na interface. Pode assumir diversas formas. Há diversas formas de

personalização de layout, podendo conter texto, imagem e há também outros desenhos pré-

definidos.

Principais propriedades

currentImage

Propriedade somente-leitura que recupera a imagem (UIImage) que está contida no botão.

currentTitle

Somente-leitura. Recupera o texto contido no botão num NSString.

titleLabel

Somente-leitura. Recupera o objeto UILabel que contem o texto do botão.

setImage:forState:

Define uma imagem (UIImage) para um estado específico (UIControlState). Este estado

corresponde ao ponto de interação com o botão (estado normal, ao tocar, desabilitado, etc.). Os

valores deste estado podem ser:

Page 58: Curso iosx

UIControlStateNormal

Estado padrão: habilitado, sem estar em selecionado e nem acionado.

UIControlStateHighlighted

Quando o botão está em destaque.

UIControlStateDisabled

Botão desabilitado.

setTitle:forState:

Similar ao setImage, porém, no lugar da imagem, se define o texto do label do botão.

Na prática (62)

Crie um novo projeto e escolha o Single View Application. Dê o nome do projeto de UIKit1.

Abra o UIKitViewController.xib no Interface Builder.

Insira na view um label, um textfield, um botão e um textview. Para isso, selecione da library e

arraste para a view. Deixe-a configurada mais ou menos assim:

Dê dois cliques sobre o label e altere o título para “Digite alguma coisa”. Faça o mesmo no

botão com o texto “Entrar”. Dê dois cliques no textview e delete o texto padrão contido no

box. No final, ela ficará assim:

Page 59: Curso iosx

Cabeçalhos (63)

Volte ao XCode, e abra o arquivo UIKit1ViewController.h, que é o cabeçalho da classe que

controla a view. Abaixo da @interface, vamos declarar os IBOutlets com textview e com o

textfield. Com isso, temos agora a possibilidade de recuperar e alterar as propriedades destes

objetos.

IBOutlet UITextView *textos;

IBOutlet UITextField *entrada;

Mas por que não o botão e o label? Os outlets são declarados para os componentes que vão ter

suas propriedades alteradas ou acessadas. No caso do label está apenas para informar ao usuário

da ação que tem de fazer no textfield, e no botão só há necessidade de declararmos sua action.

Logo após as {} e antes do @end, vamos declarar a action que vai ser passada ao acionarmos o

botão.

-(IBAction)onEnter:(id)sender;

Voltemos agora ao Interface Builder e vamos fazer as conexões dos objetos com a classe (File’s

owner). Segure o botão control, clique sobre o File’s owner e solte sobre o textfield e selecione

entrada. Faça o mesmo no text view, selecionando a opção textos.

Para o botão, segure control e clique no botão. Arraste para o File’s owner e selecione a opção

onEnter.

Em caso de dúvidas como fazer isso, o tutorial mostrado no capítulo introdutório, no exemplo

Hello World.

Page 60: Curso iosx

Implementações (64)

Agora no arquivo UIkit1ViewController.m, vamos implementar o método onEnter.

-(IBAction)onEnter:(id)sender

{

}

Neste método vamos seguir o seguinte roteiro:

Fechar o teclado

[entrada resignFirstResponder];

Montar uma string contendo o texto atual do textview e com o texto novo a ser inserido,

contido no textfield

NSString *texto = [[NSString alloc] initWithFormat:@"%@ %@",[entrada text], [textos text]];

Sendo:

[entrada text]: texto contido no textfield

[textos text]: texto contido no textview

Passar o valor da string para o textview

[textos setText:texto];

Limpar o textfield

[entrada setText:@""];

No final, o método está assim:

-(IBAction)onEnter:(id)sender {

[entrada resignFirstResponder];

NSString *texto = [[NSString alloc] initWithFormat:@"%@ %@",[entrada text],

[textos text]];

[textos setText:texto];

[entrada setText:@""];

}

Pronto! Execute o app e veja como fica.

Page 61: Curso iosx

Switch e Activity Indicator (65)

Switch (UISwitch)

Componente que trabalha em dois estados: ON e OFF, similar ao interruptor elétrico.

Principais propriedades

isOn

Retorna um valor YES ou NO dependendo do estado do componente.

BOOL estado = [objSwitch isOn];

setOn:animated:

Atribui o valor YES ou NO ao switch e com a opção de ser animado ou não.

[objSwitch setOn:YES animated:YES];

[objSwitch setOn:YES animated:NO];

Principais eventos

Value changed

Evento invocado quando o estado do switch é alterado.

Activity Indicator (UIActivityIndicatorView)

Componente que fornece ao usuário um feedback visual de atividade de processamento.

Principais propriedades

hidesWhenStopped / setHidesWhenStopped

Recupera / atribui a propriedade com valores YES ou NO indicando se o indicador deve ou não

ser mostrado enquanto a animação está parada.

isAnimating

Retorna YES ou NO, dependendo do estado do indicador.

Principais métodos

startAnimating

Faz com que o indicador inicie a animação.

stopAnimating

Faz com que o indicador interrompa a animação. Neste caso, se a propriedade

hidesWhenStopped estiver marcada como YES, o componente será ocultado automaticamente.

Page 62: Curso iosx

Na Prática (66)

Crie um novo projeto Single View Application. Dê ao projeto o nome de UIKit2. Abra o

arquivo UIKit2ViewController.xib no Interface Builder.

Coloque na view o Switch e Activity Indicator. No inspector, coloque a propriedade State do

switch para Off. Para o indicador, maque a propriedade “Hide when stopped” e desmarque a

propriedade “Animating”.

No arquivo UIKit2ViewController.h, declare o objeto do indicador:

IBOutlet UIActivityIndicatorView *spinner;

E declare também o método que vai capturar a mudança de estado do switch:

-(IBAction)setOnOff:(id)sender;

Vá no interface builder e faça as conexões com os componentes:

Page 63: Curso iosx

File’s owner -> Activity Indicator

Switch -> File’s owner

Salve a view.

Agora no arquivo UIKit2ViewController.m, vamos implementar o método setOnOff. Na

execução deste método, quando o switch ficar ON, o indicador aparece, caso contrário, a

animação para e ele desaparece.

-(IBAction)setOnOff:(id)sender {

if ([sender isOn])

{

[spinner startAnimating];

}

else {

[spinner stopAnimating];

}

}

Simples! Agora é só testar!

Segmented Control e Image View(67)

Segmented Control (UISegmentedControl)

Objeto que exibe um set de botões segmentados para exibir opções de escolha.

Principais propriedades

numberOfSegments

Somente-leitura. Recupera o número de opções (segmentos) contidos no objeto.

int segs = [objSeg numberOfSegments];

selectedSegmentIndex / setSelectedSegmentIndex

Recupera/atribui o valor do segmento selecionado. O primeiro item sempre tem o índice 0

(zero) e crescente a cada item.

Principais eventos

Value changed

Acionado quando uma outra opção do segmento for alterada.

Image View (UIImageView)

Container para exibir imagens.

Page 64: Curso iosx

Principais propriedades

image / setImage

Recupera / atribui um objeto UIImage associado a view. Esta imagem pode tanto ser definida

pelo inspector ou em runtime, podendo ser local ou carregada remotamente.

Na Prática (68)

Crie um novo projeto Single View Application, com o nome de UIKit3. Abra o

UIKit3ViewController.xib no Interface builder.

Adicione um segmented control e um image view na tela. No inspector, defina Segments para

2, e coloque os títulos dos botões respectivamente Brasil e Japão.

Baixe aqui as imagens usadas no projeto, que são as bandeiras dos dois países. Descompacte o

arquivo e arraste a pasta para a o grupo Supporting Files.

Clique no image view, na propriedade image, escolha brasil.png. Na seção SIZE (com o ícone

de uma régua), determine os seguintes valores para os tamanhos: W = 320 e H = 206. No final,

vc terá algo assim:

Salve a view e voltemos agora ao Xcode.

Page 65: Curso iosx

Criando o código (69)

No arquivo UIKit3ViewController.h, vamos declarar o outlet do image view, que vai ter a

imagem alterada na medida que o segmented control tem seu estado alterado, e o método de

mudança do estado do segmented control.

IBOutlet UIImageView *imagem;

-(IBAction)toggle:(id)sender;

Faça as devidas conexões no Interface Builder, e vamos à implementação.

A ideia é simples. De acordo com a opção do outlet, o image view irá exibir a bandeira

correspondente ao país. Na implementação:

-(IBAction)toggle:(id)sender {

}

Criaremos um array com as imagens, na ordem que está disposto no segmented control

NSArray *imgs = [NSArray arrayWithObjects:

[UIImage imageNamed:@"brasil.png"],

[UIImage imageNamed:@"japao.png"],

nil];

Definir a imagem do image view de acordo com o índice selecionado

[imagem setImage:[imgs objectAtIndex:[sender selectedSegmentIndex]]];

Sendo:

[sender selectedSegmentIndex]: O valor do índice do segmented control.

No final, o código está assim:

-(IBAction)toggle:(id)sender {

NSArray *imgs = [NSArray arrayWithObjects:

[UIImage imageNamed:@"brasil.png"],

[UIImage imageNamed:@"japao.png"],

nil];

[imagem setImage:[imgs objectAtIndex:[sender selectedSegmentIndex]]];

}

Page 66: Curso iosx

Slider e Progress View (70)

Slider (UISlider)

Este componente é similar a uma barra de rolagem, na qual o valor ser altera na medida que o

cursor muda de posição.

Uma particularidade deste componente é que ele não responde muito bem ao método com o

objeto sender, logo, excepcionalmente neste caso, recomenda que declare o IBOutlet deste

componente, mesmo associando um método a ele.

Principais propriedades

value

Retorna um valor do tipo float com o valor correspondente à posição do cursor.

setValue:animated:

Define um valor float para o slider. O argumento animated determina se a mudança de valor vai

ser animada ou não (efeito de slide do cursor).

[objSlider setValue:2.7 animated:YES];

minimumValue / setMinimumValue

Determina o valor mínimo comportado pelo slider. Este valor é do tipo float.

maximumValue / setMaximumValue

Determina o valor máximo comportado pelo slider. Este valor é do tipo float.

Principais eventos

Value Changed

Invocado quando o cursor muda de posição.

Progress View (UIProgressView)

Componente que ilustra o progresso de 0 a 100%, admitindo valores float de 0 a 1. Sua única

propriedade disponível é a progress.

progress / setProgress

Determina um valor de 0 a 1 do tipo float para marcar o progresso na view.

Page 67: Curso iosx

Na prática (71)

Crie um novo projeto View-based application, dê o nome de UIKit4. Abra o arquivo

UIKit4ViewController.xib e coloque um label, um slider e um progress view.

No label, edite o texto colocando um 0 (zero). No inspector, configure o slider, definindo o

minimum value para 0 e maximum 100, e initial 0. No progress view, coloque a propriedade

progress para 0.

No final, sua view deverá estar similar a imagem abaixo:

Page 68: Curso iosx

Criando o código (72)

No arquivo UIKit4ViewController.h, declare os três componentes inseridos, mais o método que

vai responder à mudança do slider:

IBOutlet UISlider *slider;

IBOutlet UIProgressView *progress;

IBOutlet UILabel *display;

e

-(IBAction)mudanca:(id)sender;

Faça as conexões no Interface builder dos componentes e voltemos ao arquivo

UIKit4ViewController.m.

Page 69: Curso iosx

Na implementação do método, vamos seguir os seguintes passos:

Pegar o valor atual do slider

float valorAtual = [slider value];

Atribuir ao título do label

[display setText:[NSString stringWithFormat:@"%.1f",valorAtual]];

Calcular o progresso para que seja compatível ao progress

float progresso = valorAtual / 100;

Definir o valor ao progress view

[progress setProgress:progresso];

No final, o código será assim:

-(IBAction)mudanca:(id)sender

{

float valorAtual = [slider value];

[display setText:[NSString stringWithFormat:@"%.1f",valorAtual]];

float progresso = valorAtual / 100;

[progress setProgress:progresso];

}

Classes relacionadas (73)

Para manipularmos os objetos, precisamos trabalhar com algumas classes que lidam com a

interface. São várias, todas bem documentadas pela Apple, entretanto, chamo a atenção em

duas: a UIFont e a UIColor.

UIColor(74)

As cores dos objetos e o valor de transparência (alpha) são definidos pelo objeto UIColor. Há

algumas cores padrão já definidas, mas você pode livremente criar outras cores, baseadas no

padrão RGB (vermelho, verde, azul) ou RGBA (com a camada Alpha).

Modos de inicialização

Cores em preto e branco (grayscale)

[UIColor colorWithWhite:0.0a1.0 alpha:0.0a1.0];

Cores no sistema RGBA

[UIColor colorWithRed:0.0a1.0 green:0.0a1.0 blue:0.0a1.0 alpha:0.0a1.0];

Imagem de fundo no lugar da cor

[UIColor colorWithPatternImage:UIImageObjeto];

Page 70: Curso iosx

Cores pré-definidas (75)

Basta invocar o método estático do objeto:

[UIColor cor];

O valor cor pode ser:

blackColor

darkGrayColor

lightGrayColor

whiteColor

grayColor

redColor

greenColor

blueColor

cyanColor

yellowColor

magentaColor

orangeColor

purpleColor

brownColor

clearColor

Sendo o clearColor para transparente.

UIFont (76)

Gerencia as fontes dos objetos. Alguns métodos importantes a saber.

Retorna um array com os nomes das fontes:

[UIFont familyNames];

Pra declarar uma fonte e com um tamanho:

[UIFont fontWithName:@"Nome da fonte" size:tamanho];

UIImage (77)

Classe responsável por gerenciar arquivos de imagem. No geral, os componentes do UIKit

framework que trabalham com imagens, possui esta classe envolvida.

Esta classe suporta os arquivos do tipo tif, jpg, gif, png, bmp, ico, cur e xbm.

Modos de inicialização

imageWithContentsOfFile:

Inicia o objeto com o conteúdo de uma string indicado pelo caminho da imagem.

imageNamed:

Inicia o objeto com uma imagem contida no resource.

Page 71: Curso iosx

Windows e views (78)

No iOS se usa windows e views para mostrar as informações visuais contidas na aplicação.

Uma janela (window) não contem elementos visíveis em si mas serve de suporte à diversas

views e subviews, que pode ser um container, um botão, texto, imagem, etc e é usada para

gerenciar seus subgrupos.

Toda aplicação tem pelo menos uma janela e uma view para apresentar o conteúdo. Caso

contrário, nada seria exibido ao iniciar e provavelmente a aplicação se terminaria. Há vários

tipos de views a serem explorados, que vão desde uma simples tela branca a outros tipos mais

complexos, como os de rolagem, paginação, tabela, etc.

Métodos das views (79)

Todo objeto do tipo ViewController possui métodos de execução já pré-definidos, de acordo

com os eventos que ela recebe.

initWithNibName

Método inicializador no qual se define um arquivo NIB para ser lido associado ao controller ao

ser invocado. Ao ser implementado, tudo que for descrito neste método será executado quando

a view for inicializada com este método.

viewDidLoad

Este método é invocado quando a view se torna visível, independente do meio que ela

aparecerá.

shouldAutorotateToInterfaceOrientation

Ao rotacionar o iPhone, este evento é invocado. Ao retornar YES, os componentes responderão

a auto-rotação.

didReceiveMemoryWarning

Método chamado quando o app recebe um aviso de memória baixa, geralmente neste método é

descarregado tudo que estiver ocupando espaço na memória atoa.

viewDidUnload

Chamado quando a view é descarregada.

Page 72: Curso iosx

Métodos do App Delegate (80)

No App Delegate, todas as ações relacionadas ao app de uma maneira geral, numa instância

maior, são designadas nesta classe. Alguns métodos são importantes conhecer para se ter um

controle maior do funcionamento da aplicação.

didFinishLaunchingWithOptions

Método chamado quando a aplicação é iniciada. Geralmente neste método são iniciados as

views quando o app é Window based.

applicationWillResignActive

Invocado quando a aplicação entrar em modo inativo (quando recebe um sms ou uma chamada

é recebida, botão home acionado, etc.). Geralmente se pausa as atividades com maior consumo

de memória e em caso de jogos, automaticamente entra em PAUSE.

applicationDidEnterBackground

Méotodo chamado quando a aplicação entra no modo de segundo plano, quando o botão home

for pressionado ou quando uma outra aplicação entra em primeiro plano.

applicationWillEnterForeground

Chamado quando a aplicação estiver prestes a entrar em atividade.

applicationDidBecomeActive

Invocado quando a aplicação volta ao primeiro plano. No geral, os processos parados no

método applicationDidEnterBackground são retornados à atividade.

applicationWillTerminate

Método chamado quando a aplicação for finalizado.

applicationDidReceiveMemoryWarning

Similar ao evento da view didReceiveMemoryWarning, mas num contexto geral da aplicação.

Page 73: Curso iosx

Navigation Bar (81)

Iniciando o tópico sobre navegação pelas views, eis o tipo mais comum, que é pela barra de

navegação.

Esta sem dúvida é uma das formas mais convenientes quando se trata de uma navegação linear

e o iOS facilita muito neste ponto, pois muitas das coisas mais básicas, como o meio de voltar à

view anterior, já são implementadas por default.

TabBar Controller (82)

Compõe uma lista de opções justapostas na parte mais baixa do aplicativo. Um bom exemplo

para ilustrar o funcionamento desta view é no player de música do iPhone. Logo abaixo você vê

“Albums, artistas, playlists...”, pois então, este é o TabBar Controller.

Este componente é útil quando precisamos de ramificar as opções de funções do app, sendo que

cada aba inicia uma nova ramificação de views, independente das demais.

Page 74: Curso iosx

Propriedades (83)

Para formatação desta view, deve-se seguir o padrão: ícone e texto. Há algumas opções pré-

definidas dentro da propriedade Tab bar item > Identifier. Para encontrar esta propriedade, dê

dois cliques sobre o item no Interface Builder. Caso queira criar outros nomes e definir outras

imagens, use a aba logo abaixo “Bar Item”. Lembrando que a imagem deverá ser na cor branca,

com fundo transparente. Para variação de tonalidade, use os valores de opacidade na hora de

criá-la. A imagem deve seguir o tamanho de 30x30 px.

Este tamanho servirá bem para os iPhones e iPods sem o retina display. Para que suas imagens

funcione bem nas novas gerações de tela, deve-se criar um arquivo com o dobro das dimensões

(no caso do tab bar, 60x60 px) e no nome do arquivo com o final @2x antes da extensão. Ex:

mapa.png / [email protected]

TableView Controller (84)

Este tipo de view é uma das mais importantes e merece uma atenção especial. O seu uso mais

básico é na listagem de dados tabulares, que consqüentemente serve como meio de navegação

de dados. Além disso, há diversas formas de se trabalhar o TableView no quesito formatação,

como também inserir componentes, etc.

Tipos de tabela

Veremos agora alguns exemplos de como suas tabelas podem ser.

Page 75: Curso iosx

Tabela padrão

Modelo mais usado, mais simples e prático de exibir dados. Caracteriza-se por ter apenas o

título na célula.

Tabela com índice

Page 76: Curso iosx

Neste caso, há uma ordenação por ordem alfanumérica. Muito útil para quando se trabalhar

com listas de contatos. Possui uma separação nas células, além de uma rolagem de pesquisa

rápida na direita.

Tabela de seleção

Uma pequena variação do primeiro exemplo, mas aqui os itens podem ser checados como

selecionados (checklist).

Page 77: Curso iosx

Tabelas agrupadas

Ideal para quando queira fazer uma melhor distribuição da informação na view. Você pode

agrupar as informações em comum no mesmo grupo.

Page 78: Curso iosx

Propriedades especiais nas células (85)

Esta propriedade é definda dentro do código da TableViewController, ao invocar o método

cellForRowAtIndexPath, logo após o código.

cell = [[[UITableViewCell alloc] initWithStyle:...

UITableViewCellStyleDefault

Este é o tipo padrão de célula. Corresponde à lista com o titulo somente.

Page 79: Curso iosx

UITableViewCellStyleValue1

Nesta lista, o título fica alinhado à esquerda, e à direita, num corpo menor, as informações de

detalhe. Neste caso, recomenda-se caso este detalhe seja pequeno.

Page 80: Curso iosx

UITableViewCellStyleValue2

Neste caso, ambos os títulos ficam no mesmo corpo de fonte, entretanto, a valorização maior do

espaço é com o valor dos detalhes.

UITableViewCellStyleSubtitle

Page 81: Curso iosx

As informações de detalhe ficam logo abaixo do título.

Títulos da célula (86)

Dentro do método cellForRowAtIndexPath, para definirmos o título, logo abaixo do comentário

“// Configure the cell...”

cell.textLabel.text = @"texto";

Para definirmos o subtítulo:

cell.detailTextLabel.text = @"texto";

Para definirmos uma imagem ilustrativa na célula:

UIImage *objImg = [UIImage imageNamed:@"nomeImagem.png"];

cell.imageView.image = objImg;

Sendo esta imagem tem de estar contida no projeto. Para isso, basta arrastar os arquivos para a

pasta Resources (no XCode 4 esta pasta se chama Supporting files) e marque a opção que "se

deseja copiar os arquivos".

Pode-se usar os formatos JPG, GIF se desejar, mas o recomendado é o PNG.

Ícones de navegação (87)

Page 82: Curso iosx

Às vezes, para deixar claro que, ao selecionarmos uma célula, ela nos levará a outra view, usa-

se uns ícones de forma de seta, localizados à direita da célula. Estes ícones são chamados de

AcessoryType, definidos ainda dentro do método cellForRowAtIndexPath.

cell.accessoryType = escolha_de_acordo_com_a_lista_abaixo;

UITableViewCellAccessoryDisclosureIndicator

UITableViewCellAccessoryDetailDisclosureButton

UITableViewCellAccessoryCheckmark

Modal views (88)

As views modais (modal view) são aquelas que abrem sobrepostas a todas a janelas presentes.

Para exibir uma view modal:

View *objView = [[View alloc] init];

[self presentModalViewController:objView animated:YES];

Sendo View o nome da classe que contém a view na qual deseja exibir.

Para fechá-la:

[self dismissModalViewControllerAnimated:YES];

Transições (89)

Page 83: Curso iosx

Algumas transições definem o comportamento da animação ao exibir o modal view. Para

configurarmos, usa-se o método:

[objView setModalTransitionStyle:AQUI_ENTRA_O_MODO_DE_TRANSICAO];

UIModalTransitionStyleCoverVertical

Este é a transição padrão, com a animação de baixo para cima ao exibir, e de cima para baixo

ao sair. E para esta, não precisa do código acima. Se nenhuma transição for definida, esta é a

executada.

UIModalTransitionStyleFlipHorizontal

Desta forma, a view aparecerá com o efeito de flip, revelando como se a view estivesse contida

no verso.

UIModalTransitionStyleCrossDissolve

Mostra a view com um efeito de transição de fade in e fade out.

UIModalTransitionStylePartialCurl

Mostra a view abaixo, revelando apenas uma parte dela, com o efeito de uma folha de papel

sendo dobrada.

Mensagens de alerta (90)

Para invocar as mensagens de alerta, usa-se uma classe chamada UIAlertView. Para invocá-

los, usa-se a estrutura:

UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:@"Aqui entra o título"

message:@"Mensagem do box" delegate:self cancelButtonTitle:@"Título do botão cancelar"

otherButtonTitles:nil] autorelease];

[alert show];

Para adicionar mais um outro botão, coloque a linha antes do [alert show]

[alert addButtonWithTitle:@"titulo do botão"];

Pra receber a ação do botão, antes, no arquivo .h do objeto que estiver trabalhando, coloque o

protocolo UIAlertViewDelegate

Em seguida, siga o evento abaixo:

Page 84: Curso iosx

- (void)alertView:(UIAlertView *)alertView

didDismissWithButtonIndex:(NSInteger)buttonIndex {

// executa

}

Nesta função, reconhece-se qual botão foi clicado pela variável buttonIndex, sendo o 0 o botão

Cancelar, e os demais botões, seguindo a ordem numérica crescente.

Exemplo: se acrescentarmos um botão SIM, além do que já tem como padrão (que se chamaria

NÃO), o NÃO seria 0 e o SIM seria 1.

Na prática(91)

Neste exemplo prático, vamos demonstrar como incorporar todas as views estudadas

anteriormente para vermos melhor na prática como elas se comportam, e claro, como programá-

las:

Configurando o projeto baseado em Window

Crie um novo projeto, escolha Empty Application e dê o nome de TutorialView. A partir daí

você verá que não há nada no projeto senão o AppDelegate. Vamos agora adicionar a Window

que vai receber o tab bar controller.

Vá em File -> New -> File... e em User Interface, escolha Window. Escolha o Target Device:

iPhone e dê o nome de MainWindow

Page 85: Curso iosx

Inclua um Object no Window.

Page 86: Curso iosx

Atribua o Object ao AppDelegate, selecionando na lista de Objects e no Inspector, fazer esta

alteração

Selecione o File's Owner e mude a Class para UIApplication. A partir dela, vamos designar os

links entre as classes. Comece associando o outlet delegate para o AppDelegate.

Page 87: Curso iosx

Abra o arquivo AppDelegate.h e altera a linha de

@property (strong, nonatomic) UIWindow *window;

para

@property (strong, nonatomic) IBOutlet UIWindow *window;

Volte para o MainWindow.xib e clique no App Delegate, escolha o outlet Window e arraste

para a Window criada.

Page 88: Curso iosx

Em seguida, vamos associar esta Window para que seja a window principal. No menu a

esquerda, clique primeiro item (no caso TutorialView). Marque como Main Interface o

MainWindow

Page 89: Curso iosx

E por fim, modifique o método do didFinishLaunchingWithOptions no AppDelegate.m de

- (BOOL)application:(UIApplication *)application

didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{

self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

// Override point for customization after application launch.

self.window.backgroundColor = [UIColor whiteColor];

[self.window makeKeyAndVisible];

return YES;

}

para

- (BOOL)application:(UIApplication *)application

didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{

return YES;

}

Page 90: Curso iosx

Adicionando o TabBarController

Abra o MainWindow.xib e inclua um Tab Bar Controller. Para isso, selecione-o na Library e

arraste-o para a janela de projeto.

Você verá algo similar a isso:

Page 91: Curso iosx

Configurando a Tab Bar(92)

Como você pode ver, há duas view controllers já inseridas por padrão. Quando for trabalhar

com este componente, não significa que você terá de trabalhar com elas necessariamente, mas

no nosso exemplo, vamos mantê-las e adicionaremos mais dois controllers, só que do tipo

Navigation Controller.

Arraste-os para dentro do Tab Bar Controller, mantendo-os abaixo dos dois primeiros

controllers. Tenha certeza de que eles estão contidos dentro do Tab Bar. No final você verá algo

assim:

Page 92: Curso iosx

Em cada aba, dê dois cliques sobre o título e Renomeie-os para respectivamente: Modal Views,

Alerts, View Padrão, Table View. O resultado deve ser algo similar a figura abaixo:

Page 93: Curso iosx

Incluindo a Tab Bar ao Window (93)

Mas se executarmos o nosso programa, você verá apenas uma tela branca. Isso é porque você

precisa adicionar este Tab Bar Controller a Window.

Vá no Interface Builder com o arquivo MainWindow.xib e segure o control e clique em

Window e arraste sobre o Tab Controller, marque a opção rootViewController.

Execute e verá algo assim:

Page 94: Curso iosx

Ícones (94)

Caso queira colocar alguns ícones para ilustrar os tabs, crie as imagens dentro do padrão

30x30px (60 para o retina display). A imagem dever ser em branco com fundo transparente,

podendo no desenho ter valores de transparência (alfa). Deixarei para download aqui os ícones

usados neste tutorial.

Download dos ícones

Para usá-los, arraste-os ao projeto para a pasta Resources (ou Supporting Files caso esteja no

XCode 4) e marque a opção “Copy if needed”.

Daí é só escolher no inspector na opção Image as imagens que desejar.

Page 95: Curso iosx

Modal Views (95)

Vamos criar a view para a primeira aba, que vai demonstrar o funcionamento das animações

para exibir as modal views.

Crie um novo arquivo do tipo UIViewController subclass, marque como subclass a opção

UIViewController e a opção de criar o XIB. Dê o nome de ModalViews.

Abra o ModalViews.xib no Interface Builder e crie 4 botões. No final, você terá algo parecido

com a imagem abaixo:

Page 96: Curso iosx

Subview a ser aberta (96)

Antes de declaramos as actions aos botões, vamos criar uma nova view com seus controllers,

mas desta vez chamada de AbreModalView, seguindo os mesmos procedimentos para criar o

ModalViews. Esta view será exibida na ação dos botões.

Abra o arquivo AbreModalView.xib e mude a cor do fundo para ficar visível a transição.

Coloque um botão no meio, com o título de Fechar. No final, você terá algo parecido com isso:

Vá no arquivo AbreModalView.h e declare o método:

-(IBAction)fechar:(id)sender;

No arquivo AbreModalView.m, implemente este método da seguinte forma:

-(IBAction)fechar:(id)sender {

[self dismissModalViewControllerAnimated:YES];

}

Page 97: Curso iosx

E não esqueça de fazer a conexão do botão com o File’s Owner no Interface Builder,

vinculando o evento fechar.

Declarando os métodos do ModalViews.h (97)

Voltemos agora ao ModalViews.h. Antes de declararmos os métodos dos botões, vamos

importar a view que acabamos de criar:

#import "AbreModalView.h"

Declare em seguida no @interface a view. Faremos desta maneira para não ter que ficarmos

instanciando toda vez que implementamos os eventos dos botões.

AbreModalView *abreModal;

E agora, os métodos dos botões:

-(IBAction)abrePadrao:(id)sender;

-(IBAction)abreFlip:(id)sender;

-(IBAction)abreDissolve:(id)sender;

-(IBAction)abrePartialCurl:(id)sender;

Implementando os métodos no ModalViews.m (98)

Vamos agora ao arquivo ModalViews.m. Antes de implementarmos os métodos dos botões,

precisamos inicializar o objeto que contem a view abreModal. Vá no método viewDidLoad e

inicialize-a:

abreModal = [[AbreModalView alloc] init];

Agora sim, implementemos os métodos. Todos os quatro métodos têm códigos similares,

mudando apenas o parâmetro de transição. Começaremos com o abrePadrao.

-(IBAction)abrePadrao:(id)sender

{

[abreModal setModalTransitionStyle:UIModalTransitionStyleCoverVertical];

[self presentModalViewController:abreModal animated:YES];

}

Apesar de por padrão a transição já ser a vertical, deixaremos reforçada esta propriedade, pois,

como esta view é instanciada no objeto para ser usada nos demais métodos, se não reforçamos o

tipo de transição, ele vai usar a última declarada.

Não entendeu? Bom, faz de conta que não colocamos nada. Ao executar o programa e clicar no

primeiro botão, você verá que a subview irá aparecer num movimento de baixo para cima. Mas

se em seguida você clicar no botão Dissolve e voltar, ao clicar no primeiro botão, ao invés do

movimento ser o de subida, será o último usado, ou seja, dissolve.

Os demais botões, sem grandes mistérios:

-(IBAction)abreFlip:(id)sender

Page 98: Curso iosx

{

[abreModal setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];

[self presentModalViewController:abreModal animated:YES];

}

-(IBAction)abreDissolve:(id)sender

{

[abreModal setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];

[self presentModalViewController:abreModal animated:YES];

}

-(IBAction)abrePartialCurl:(id)sender

{

[abreModal setModalTransitionStyle:UIModalTransitionStylePartialCurl];

[self presentModalViewController:abreModal animated:YES];

}

E não se esqueçam de fazer as devidas conexões dos métodos no Interface Builder.

Mas agora você precisa vincular esta View na primeira aba do Tab Bar. Na janela do projeto no

Interface Builder, selecione o ViewController da primeira aba, no Inspector, na aba Identity, no

campo Class, escolha ModalViews.

Execute o app e veja como fica :)

Page 99: Curso iosx

Alerts (99)

Para esta aba, crie uma nova view com o nome de Alerts. O procedimento para criar este

arquivo é o mesmo seguido nos anteriores. Abra o arquivo Alerts.xib no Interface Builder.

Coloque um label, um textfield e um botão. Configure-os da seguinte maneira:

No arquivo Alerts.h, declare o textfield para que receba seu valor.

IBOutlet UITextField *mensagem;

E o método do botão que será executado.

-(IBAction)mostrarMensagem:(id)sender;

No arquivo Alerts.m, faremos a implementação do método do botão. Quando o botão for

acionado, ele exibirá um alerta com a mensagem escrita no textfield. A implementação segue

abaixo:

-(IBAction)mostrarMensagem:(id)sender

{

Page 100: Curso iosx

UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:@"Sua mensagem aqui"

message:[mensagem text] delegate:self cancelButtonTitle:@"Fechar" otherButtonTitles:nil]

autorelease];

[alert show];

[mensagem resignFirstResponder];

}

Sendo:

initWithTitle:@"Sua mensagem aqui": O título do alerta

message:[mensagem text]: a mensagem do alerta, que seria o que está escrito no textfield.

cancelButtonTitle:@"Fechar": Título do botão para fechar.

E claro, no final, fechamos o teclado:

[mensagem resignFirstResponder];

Faça as devidas conexões com o textfield e o botão no Interface Builder. E no Tab Bar, no

segundo ViewController, associe a Custom Class para Alerts.

Simples, não é? Execute e veja como ficou.

View Padrão – SubView (100)

Nesta aba, começaremos a trabalhar com o navigation controller, sendo neste exemplo uma

navegação por views simples. Antes de começarmos a trabalhar nesta view, vamos criar a

subview que será aberta nos exemplos seguintes.

Crie uma nova view, seguindo os mesmos passos anteriores chamado SubView. Abra o

SubView.xib, mude a cor do fundo e coloque um label.

Page 101: Curso iosx

No SubView.h declare o label e uma string, que vai ser passada pelas views principais. Vamos

nos exemplos a seguir demonstrar como se passa um valor a uma outra view.

IBOutlet UILabel *saida;

NSString *titulo;

Tornaremos a string titulo pública, logo, vamos declará-la como propriedade:

@property (nonatomic, retain) NSString *titulo;

Agora no arquivo SubView.m, vamos em primeiro lugar tratar da propriedade titulo. Como já

se sabe:

@synthesize titulo;

Quando a view for carregada, queremos que o título do label seja alterado. No método

viewDidLoad:

[saida setText:titulo];

E para definirmos o título que vai ser exibido no Navigation Controller:

[self setTitle:@"Subview"];

Sendo Subview o texto que vai aparecer na barra azul. Pode ser qualquer coisa.

ViewPadrao(101)

Agora vamos ao View Padrão. Crie uma nova view chamada ViewPadrao, abra o

ViewPadrao.xib no Interface Builder e coloque um botão.

Page 102: Curso iosx

Abra agora o ViewPadrao.h e declare o método do botão:

-(IBAction)abreSubView:(id)sender;

E vamos implementá-lo no ViewPadrao.m. Antes disso, vamos importar a subview a esta

classe:

#import "SubView.h"

Em seguida, implementar o método do botão. O código deste método segue três passos

fundamentais:

Instância da classe SubView

Passagem do valor a propriedade titulo

Exibir o subview

-(IBAction)abreSubView:(id)sender

{

SubView *sub = [[[SubView alloc] init] autorelease];

[sub setTitulo:@"Alo!"];

[self.navigationController pushViewController:sub animated:YES];

}

Não se esqueça de fazer a conexão do botão no Interface Builder e de vincular ao terceiro

controller a Class ViewPadrao.

Table View (102)

Vamos agora ao último tab, para isso, crie uma nova view, mas desta vez, cuidado pois você

deverá marcar a opção Subclass of UITableViewController. Dê o nome de TableView.

No arquivo TableView.h, vamos declarar o array que conterá a lista exibida na tabela.

NSArray *lista;

Em numberOfSectionsInTableView, coloque:

return 1;

Pois neste caso, só teremos uma única seção na lista.

Em numberOfRowsInSection, coloque:

return [lista count];

Neste caso, ele pede para informar o número de linhas que a tabela possui. Demos o valor que

corresponde a quantidade de objetos no array lista.

Nas versões mais atuais do Xcode (4.3) tem havido algumas modificações na implementação

neste método, o que leva a necessidade de adicionar o seguinte bloco antes da personalização

da célula, para que nenhum erro ocorra:

if (cell == nil) {

Page 103: Curso iosx

cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault

reuseIdentifier:CellIdentifier] autorelease];

}

Agora no método cellForRowAtIndexPath, vamos declarar os títulos das linhas da tabela.

Logo abaixo da linha comentada, insira:

cell.textLabel.text = [lista objectAtIndex:indexPath.row];

Sendo:

cell.textLabel.text: a propriedade de título da linha da tabela.

indexPath.row: o índice da linha que está no momento sendo trabalhada.

Mas para termos o que lista na tabela, precisamos de popular o array. Para isso, no método

viewDidLoad, inicializaremos o array e colocaremos alguns itens para ser listados:

lista = [[NSArray alloc] initWithObjects:@"Mensagem 1", @"Mensagem 2", nil];

Você pode colocar quantos itens que desejar, contanto que o último item do array seja o

terminador nil.

Agora só falta fazermos com que ao selecionarmos o item na tabela, seja aberto o subview.

Vamos no método didSelectRowAtIndexPath, que se encontra no final do arquivo.

Há um exemplo de declaração comentado para servir de exemplo. Não usaremos exatamente

aquele modelo, mas um que siga os seguintes passos:

Instanciaremos a classe que controla o subview

Passaremos o valor selecionado da tabela para a subview

Abriremos a view

O código de implementação será algo similar ao abaixo:

SubView *sub = [[SubView alloc] init];

[sub setTitulo:[lista objectAtIndex:indexPath.row]];

[self.navigationController pushViewController:sub animated:YES];

Sendo:

indexPath.row: o indice da linha da tabela que foi selecionada.

Não se esqueça agora de associar na quarta tab o TableView e execute o app, veja como ficou.

Acesso a dados e sandbox (103)

Neste capítulo vamos trabalhar com formas de tratamento de dados e armazenamento, algo

essencial para o desenvolvimento de aplicativos. Vamos listar aqui os principais e mais usados

meios de acesso e armazenamento de dados usados pelo iOS.

Page 104: Curso iosx

NSUserDefaults (104)

O NSUserDefaults é uma classe do objC que fica responsável por guardar dados pequenos de

forma persistente. Muito conveniente para armazenar configurações, sem ter a necessidade de

criar bancos de dados ou gerar arquivos de configuração.

Seu uso é muito simples, para gravar dados:

NSUserDefaults *objeto = [NSUserDefaults standardUserDefaults];

[objeto setObject:@"valor desejado" forKey:@"valorChave"];

[objeto setObject:@"outro valor desejado" forKey:@"outroValorChave"];

[objeto synchronize];

E para abrí-los:

NSUserDefaults *objPrefs = [NSUserDefaults standardUserDefaults];

NSString *objString = [objPrefs stringForKey:@"valorChave"];

NSString *objOutraString = [objPrefs stringForKey:@"outroValorChave"];

Page 105: Curso iosx

Na prática (105)

Crie um novo projeto View-based Application, dê o nome de TesteDefaults. Abra o arquivo

TesteDefaultsViewController.xib e no interface builder, crie um TextField e um botão. Dê ao

botão o título Salvar. Algo parecido com isso:

Voltando ao Xcode, abra o arquivo TesteDefaultsViewController.h e declararemos os objetos

e métodos.

Dentro do @interface, declare o TextField:

IBOutlet UITextField *texto;

E logo após:

-(IBAction)salvar:(id)sender;

Volte ao Interface builder e associe o texto ao TextField e o método salvar ao botão Salvar.

Agora no arquivo TesteDefaultsViewController.m vamos declarar o método salvar:

-(IBAction)salvar:(id)sender

{

Page 106: Curso iosx

NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];

[prefs setObject:[texto text] forKey:@"textoPadrao"];

[prefs synchronize];

}

E para abrir os dados no TextField:

- (void)viewDidLoad {

NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];

[texto setText:[prefs stringForKey:@"textoPadrao"]];

[super viewDidLoad];

}

Explicando rapidamente o que acontece no programa acima, ao salvar, será salvo a propriedade

“textoPadrao” com o valor contido no TextField. Quando o usuário abrir o app, será consultado

se há algum valor para a chave textoPadrao e seu valor inserido no TextField.

Rode a aplicação e veja como funciona. Para ter certeza do funcionamento, salve alguma coisa

e feche o app. Abra-o novamente e veja.

Acesso aos arquivos do sandbox (106)

O sandbox é um diretório no qual você pode ter acesso dentro do seu app para armazenar

dados. É o único local onde você terá total liberdade de escrita e leitura, ao contrário das demais

pastas.

Para acessar o diretório do sandbox:

NSArray *objArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,

NSUserDomainMask, YES);

NSString *caminho = [objArray objectAtIndex:0];

Para verificar a existência de um arquivo:

NSString *arquivo = [path stringByAppendingPathComponent:@"nomedoarquivo"];

if ([[NSFileManager defaultManager] fileExistsAtPath:arquivo])

{

// Algo a ser feito

}

Para listar os arquivos contidos no Documents:

NSArray *arrayConteudo = [[NSFileManager defaultManager]

contentsOfDirectoryAtPath:caminho error:NULL];

for (int Count = 0; Count < (int)[arrayConteudo count]; Count++)

{

NSLog(@"Arquivo %d: %@", (Count + 1), [arrayConteudo objectAtIndex:Count]);

}

Neste tópico não vamos nos aprofundar muito, pois a aplicação deste recurso é muito mais

visível dentro de um exemplo prático e será muito usado no projeto final.

Page 107: Curso iosx

PLists (107)

Uma PList (property list) é um meio de armazenamento de dados simples e estruturados.

Possui um funcionamento um pouco mais complexo do que o User Defaults, pois sua estrutura

é mais ramificada.

Uma PList pode tanto receber o tipo NSArray como NSDictionary e sendo seu carregamento

feito via arquivo. A diferença entre os dois tipos está no fato de que o NSArray só permite uma

de correspondência simples, bidimensional enquanto no Dictionary permite uma ramificação

maior.

Como usá-las

Para criar uma plist

Vá em New File, na aba Mac OS X > Resources > Property List. E dê o nome que desejar.

Na Property List, veja em Root, escolha na coluna do meio o tipo que desejar: NSArray ou

NSDictionary. Clique no botão que aparece ao fim da linha e insira um novo item.

Nas versões mais recentes do XCode (4.2), só tem permitido criar PLists do tipo NSDictionary,

logo, se estiver usando esta versão, desconsidere o tipo NSArray.

Para carregá-la

NSString *caminho = [[NSBundle mainBundle] pathForResource:@"NomeDoArquivo"

ofType:@"plist"];

NSMutableDictionary *objDictionary = [[NSMutableDictionary alloc]

initWithContentsOfFile:caminho];

Page 108: Curso iosx

Na prática (108)

Neste projeto não exploraremos a parte visual, apenas ilustraremos como funciona a listagem

de dados.

Crie um novo projeto View-based Application e dê o nome de TestePLists. Em seguida crie um

arquivo PList e dê o nome de cardapio.plist.

Abra o cardapio.plist e insira três linhas de registro: Drinks, Comidas e Sobremesas, todas as

três como o tipo Array. Repare que ao transformá-lo deste tipo, uma nova lista surgirá dentro

dos campos.

Dentro dos arrays, insira os dados ao seu gosto. O resultado deve ser algo similar à figura

abaixo:

Implementação (109)

Agora no arquivo TestePListsViewController.m, procure o método viewDidLoad e

implemente:

NSString *path = [[NSBundle mainBundle] pathForResource:@"cardapio" ofType:@"plist"];

NSMutableDictionary *tmpDict = [[NSMutableDictionary alloc] initWithContentsOfFile:path];

A primeira linha retornará o caminho com a localização do arquivo no sistema de arquivos do

seu aparelho. E a segunda, criará um dicionário com os dados contidos na lista.

Em seguida faremos uma varredura nesta lista:

Page 109: Curso iosx

for(NSString *titulo in tmpDict)

{

NSLog(@"%@", titulo);

}

Ao executar do jeito que está, você verá apenas os nomes dos títulos dos dicionários, sem os

itens contidos neles. Agora vamos fazer uma varredura dentro dos arrays. Logo abaixo do

NSLog, insira o código:

for(NSString *item in [tmpDict objectForKey:titulo])

{

NSLog(@">> %@",item);

}

Explicando o que ele faz: os títulos do plist são arrays, logo, ao chamar por eles no dicionário,

teremos os ítens do array. Daí é só listá-los. O código na íntegra:

- (void)viewDidLoad {

[super viewDidLoad];

NSString *path = [[NSBundle mainBundle] pathForResource:@"cardapio"

ofType:@"plist"];

NSMutableDictionary *tmpDict = [[NSMutableDictionary alloc]

initWithContentsOfFile:path];

for(NSString *titulo in tmpDict)

{

NSLog(@"%@",titulo);

for(NSString *item in [tmpDict objectForKey:titulo])

{

NSLog(@">> %@",item);

}

}

}

Desafio

Usando seus conhecimentos de UITableViewController e de navegação, implemente este

código de forma que ao invés da saída ser no console, ela ser na tabela, de forma que ao

clicarmos no ítem, ele listar os sub-itens.

Page 110: Curso iosx

Core data(110)

O Core Data é um framework de gerenciamento de dados do SQLite3 que permite a

manipulação de registros num nível de abstração maior, sem a necessidade do uso de consultas

SQL. Seu uso é altamente recomendado pois o risco de haver alguma alteração na sintaxe na

programação em caso de atualização do SQLite é quase nulo.

Vamos demonstrar o funcionamento deste framework na melhor maneira: praticando!

Na prática (111)

Para ilustrar como funciona o Core Data, nada melhor do que fazermos na prática. O

funcionamento é simples e a forma de se trabalhar aqui ilustrada, representa a grande maioria

dos projetos que usam banco de dados.

Baseando-se na classe que criamos no primeiro projeto (classe Contatos), vamos criar um novo

projeto, só que agora com recurso de entrada e saída de dados, e com uso de um modo visual.

Começando

Crie um novo projeto, escolha o Empty Project. Dê o nome de TesteCoreData e certifique-se

que a opção Use Core Data esteja selecionada. Quando você escolhe esta opção, toda a

estrutura de uso do framework já fica automaticamente preparada no projeto.

É necessário seguir alguns passos para configurar a MainWindow do projeto, como já feito

anteriormente, caso haja dúvidas, reveja o tópico Configurando o projeto baseado em

Window localizado na referência (91) do curso.

.

No grupo Frameworks, veja que o CoreData está incluído.

Veja no arquivo AppDelegate.h algumas linhas automaticamente inseridas

@property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;

@property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;

@property (nonatomic, retain, readonly) NSPersistentStoreCoordinator

*persistentStoreCoordinator;

- (void)saveContext;

- (NSURL *)applicationDocumentsDirectory;

Cada uma das propriedades declaradas representam uma camada do framework como descrito

anteriormente. Há também métodos criados automaticamente. O primeiro (saveContext) salva

toda alteração que você fez no modelo em arquivo e o segundo

(applicationDocumentsDirectory) retorna o objeto NSURL contendo o caminho do diretório

Documents do app.

Page 111: Curso iosx

Criando a tabela (112)

No grupo Supporting Files, veja um arquivo chamado TesteCoreData.xcdatamodeld. Este

arquivo irá conter o modelo de dados padrão do app. Abra-o.

Crie uma entity e dê o nome de Contatos. Uma entity equivale a uma tabela, e cada atributo

equivale a um campo.

Crie dois atributos:

nome, com o tipo String;

idade, com o tipo Integer 16.

Em seguida, salve. Selecione o arquivo TesteCoreData.xcdatamodeld e vá em File > New

File e escolha Managed Object Class (se você usar o Xcode4, esta opção se encontra na guia

CoreData > NSManagedObject subclass). Selecione a entidade Contatos e next, finish. Neste

passo, serão criados dois arquivos, Contatos.h e Contatos.m, que são muito similares àquela

classe que criamos nos primeiros capítulos.

Page 112: Curso iosx

TableListView Controller(113)

Vá em File > New File e na aba iOS > Cocoa Touch escolha UIViewController subclass e

escolha a subclass UITableViewController e desmarque a opção de criar os arquivos XIB. Dê o

nome de ContatoListController.

Abra o arquivo ContatoListController.h e vamos configurar os cabeçalhos do controller.

Primeiro vamos importar a classe que representa o objeto NSObjectContext da entidade

Contatos, que acabamos de criar. Logo após o #import <UIKit/UIKit.h>, digite:

#import "Contatos.h"

Em seguida, vamos declarar duas variáveis de instância. Uma que representará a camada

ManagedObjectContext e a outra, um NSMutableArray que conterá os dados listados na

tabela.

NSManagedObjectContext *managedObjectContext;

NSMutableArray *arrayLista;

E precisamos também torná-las acessíveis, logo, determinarmos um getter e um setter.

@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;

@property (nonatomic, retain) NSMutableArray *arrayLista;

Determinaremos agora dois métodos a princípio: um para adicionar um novo registro e um para

listar todos os registros na tabela.

-(void)listaRegistros;

-(void)addNovoRegistro:(id)sender;

Implementação da classe (114)

Agora no arquivo ContatoListController.m, faremos a implementação dos métodos declarados

no header, começando com as propriedades declaradas:

@synthesize managedObjectContext, arrayLista;

Antes de implementarmos os métodos, vamos configurar a nossa view. Faremos a

implementação no métodos viewDidLoad. Abaixo do [super viewDidLoad]:

Primeiro daremos um título para ser exibido na barra de navegação:

self.title = @"Contatos";

Colocaremos agora um botão de + na barra de título. A linha a seguir equivale a adicionarmos

um botão na barra de título e associarmos os métodos no IB:

UIBarButtonItem *addBotao = [[UIBarButtonItem alloc]

initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self

action:@selector(addNovoRegistro:)];

Dissecando a linha:

UIBarButtonItem *addBotao: Declara a variável addBotao como objeto do tipo

UIBarButtonItem, e em seguida o objeto foi alocado.

Page 113: Curso iosx

initWithBarButtonSystemItem:UIBarButtonSystemItemAdd: Inicializa o objeto como um

botão pré-definido no sistema, do tipo ItemAdd.

target:self: Define o alvo do objeto criado como ele mesmo.

action:@selector(addNovoRegistro:): Determina que o método padrão do objeto ao ser

executado para addNovoRegistro:.

Agora incluímos o botão na barra de navegação:

self.navigationItem.rightBarButtonItem = addBotao;

Configurando a TableListView(115)

Precisamos agora implementar alguns métodos obrigatórios da class UITableViewController,

que são numberOfSectionsInTableView e numberOfRowsInSection.

No primeiro (numberOfSectionsInTableView), temos apenas uma seção no nosso table view,

logo, o código deverá ficar assim:

return 1;

No caso do numberOfRowsInSection, o número de linhas, equivale ao número de linhas no

arrayLista, logo:

return [arrayLista count];

Além disso, precisamos também popular a tabela com os registros contidos no array. Procure o

método cellForRowAtIndexPath. Este método é responsável pela construção de cada célula da

tabela, como já vimos anteriormente. Configure o estilo da célula para “StyleValue1”, dentro de

if (cell == nil) altere o parâmetro de initWithStyle para UITableViewCellStyleValue1.

Agora, na área após o comentário “Configure the cell...”, primeiro instanciaremos o objeto

Contatos com o valor atual da célula listada. Lembrando que todas as instâncias do objeto

Contatos estão alocados no arrayLista.

Contatos *contato = [[self arrayLista] objectAtIndex:[indexPath row]];

Em seguida vamos colocar o campo nome como título da célula, e a idade como um detalhe a

ser exibido.

cell.textLabel setText:[contato nome]];

[cell.detailTextLabel setText:[NSString stringWithFormat:@"%@ anos",[contato idade]]];

Por enquanto é só. Voltaremos mais tarde para definirmos o método acionado ao clicarmos na

célula.

Page 114: Curso iosx

Listando os registros (116)

Agora vamos implementar o método listaRegistros

-(void)listaRegistros

{

}

A primeira coisa que temos que fazer é selecionar qual a entidade que vamos listar. Para isso,

declararemos um objeto do tipo NSEntityDescription.

NSEntityDescription *entContatos = [NSEntityDescription entityForName:@"Contatos"

inManagedObjectContext:managedObjectContext];

Dentro da declaração, em entityForName, passamos o valor Contatos que corresponde ao

nome da entidade criada, e em inManagedObjectContext, passamos o objeto declarado na

propriedade, logo no começo.

Em posse da entidade declarada, temos agora que chamar o método que vai listar estes

registros. Para isso, declaramos um objeto do tipo NSFetchRequest, que receberá os registros da

entidade.

// Declara o objeto "request"

NSFetchRequest *request = [[NSFetchRequest alloc] init];

// Define a entidade para o objeto "request"

[request setEntity:entContatos];

Para uma boa listagem, temos de definir um critério de ordenação. No caso, no código a seguir,

vamos ordenar por nome, em ordem alfabética. Primeiro declaramos um objeto do tipo

NSSortDescriptor, que vai definir qual é o campo a ser ordenado e qual o critério de

ordenação.

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"nome"

ascending:YES];

Em seguida, declararemos um NSArray que irá conter a ordenação do objeto.

NSArray *arraySD = [NSArray arrayWithObject:sortDescriptor];

Passemos agora para o objeto request o critério de ordenação.

[request setSortDescriptors:arraySD];

Com tudo já definido, vamos finalmente fazer a listagem dos registros. Para isso, temos de nos

resguardar que alguma coisa errada poderá acontecer no processo, pelas mais diversas razões.

Pensando nisso, toda e qualquer ação de acesso a dados no Core Data está vinculada a um

objeto NSError, mais especificamente, ao ponteiro deste objeto. Ou seja, em caso de qualquer

pane, este objeto terá sido acionado.

NSError *error;

NSMutableArray *fetchResults = [[managedObjectContext executeFetchRequest:request

error:&error] mutableCopy];

Os resultados sempre vêm no objeto do tipo NSMutableArray. Em executeFetchRequest

passamos o objeto request, no qual estivemos trabalhando e no final, passamos o ponteiro do

objeto error.

Page 115: Curso iosx

Herdado do C, um ponteiro é o endereço da memória no qual uma variável está alocada. Toda

vez que declaramos um objeto com um asterisco antes do nome, deixamos claro por compilador

que o endereço desta variável poderá ser acessível. Para termos acesso a este endereço, usa-se o

& antes do nome da variáve

Se tudo deu certo, ótimo, senão, o código a seguir irá informar em algo que houve de errado.

if (!fetchResults)

{

NSLog(@"Algo de errado aconteceu!");

}

Geralmente este erro é muito grave o que pode levar ao fim forçado da execução do app.

Pesquisa feita. Agora vamos passar os resultados para o array que declaramos no cabeçalho

como propriedade.

[self setArrayLista:fetchResults];

Enfim, o código completo do método.

-(void)listaRegistros

{

NSEntityDescription *entContatos = [NSEntityDescription entityForName:@"Contatos"

inManagedObjectContext:managedObjectContext];

// Declara o objeto "request"

NSFetchRequest *request = [[NSFetchRequest alloc] init];

// Define a entidade para o objeto "request"

[request setEntity:entContatos];

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"nome"

ascending:YES];

NSArray *arraySD = [NSArray arrayWithObject:sortDescriptor];

[request setSortDescriptors:arraySD];

NSError *error;

NSMutableArray *fetchResults = [[managedObjectContext executeFetchRequest:request

error:&error] mutableCopy];

if (!fetchResults) {

NSLog(@"Algo de errado aconteceu!");

}

[self setArrayLista:fetchResults];

}

Chame esta função dentro do método viewDidLoad: do ContatoListController.m

-(void)viewDidLoad

{

[super viewDidLoad];

/*

Page 116: Curso iosx

Implementação anterior

*/

[self listaRegistros];

}

Implementando a navegação (117)

Vamos agora incluir o TableView na window principal, além de implementarmos a navegação.

Mas desta vez, não faremos no Interface Builder, criaremos em linhas de código e veremos

como é simples.

Primeiro vamos adicionar algumas propriedades ao delegate. Vá no arquivo AppDelegate.h e

adicione a seguinte linha nas variáveis de instância:

UINavigationController *navControl;

E logo abaixo:

@property (nonatomic, retain) UINavigationController *navControl;

Abra o arquivo AppDelegate.m e importe a classe ContatoListController

#import "ContatoListController.h"

E implementemos a propriedade do navControl

@synthesize navControl;

Procure o método didFinishLaunchingWithOptions para declarmos o ViewController para ser

inserido na window:

ContatoListController *tabCtrl = [[ContatoListController alloc]

initWithStyle:UITableViewStylePlain];

A linha acima cria um objeto com o estilo mais simples de lista. Precisamos agora informar a

esta view qual é o Managed Object Context do Core Data em vigência no app. Quem

“gerencia” este objeto é a classe delegate, entretanto, já criamos uma propriedade com este tipo

no ViewController, justamente para recebê-la quando for instanciada. Faremos isso!

tabCtrl.managedObjectContext = [self managedObjectContext];

Instancie agora o TableViewController, associado ao navControl

self.navControl = [[UINavigationController alloc] initWithRootViewController:tabCtrl];

Por fim, adicione a view na window.

[self.window addSubview:[self.navControl view]];

Se por curiosidade for dar um Run no programa para vê-lo no simulador, você verá uma lista

vazia com um botão + na barra azul. Se não tiver nada disso, confira os passos anteriores.

Page 117: Curso iosx

Formulário (118)

Vá em File > New File..., na guia iOS > Cocoa Touch > UIViewController subclass. Certifique-

se que a opção de criar um arquivo XIB esteja marcada e que a opção de herdar o

UITableViewController esteja desmarcada. Dê o nome de Formulario.

Hora de diagramar. Abra o arquivo Formulario.xib no IB, e crie 2 labels, 2 textfields e 3

botões. Esta etapa já podes fazer a seu gosto, o importante é conter estes elementos. No final

ficará algo parecido com isso:

Para o textfield de idade, no inspector, dentro do grupo Text Input Traits, localize a opção

Keyboard e selecione Number Pad.

O botão Excluir este registro deve estar ocultado por padrão, pois ao inserir um novo registro,

não faz sentido ele ser exibido. Para isso, selecione o botão, vá no Inspector e na área View,

marque a opção Hidden.

Salve e voltemos aos controllers deste form. No arquivo Formulario.h, declare os componentes:

Page 118: Curso iosx

#import "Contatos.h"

#import "ContatoListController.h"

@interface Formulario : UIViewController {

Contatos *contatoAtual;

ContatoListController *viewParent;

NSManagedObjectContext *managedObjectContext;

IBOutlet UITextField *txtNome;

IBOutlet UITextField *txtIdade;

IBOutlet UIButton *btnSave;

IBOutlet UIButton *btnCancelar;

IBOutlet UIButton *btnExcluir;

}

@property (nonatomic, retain) Contatos *contatoAtual;

@property (nonatomic, retain) ContatoListController *viewParent;

@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;

@property (nonatomic, retain) IBOutlet UITextField *txtNome;

@property (nonatomic, retain) IBOutlet UITextField *txtIdade;

@property (nonatomic, retain) IBOutlet UIButton *btnSave;

@property (nonatomic, retain) IBOutlet UIButton *btnExcluir;

-(IBAction)doSave:(id)sender;

-(IBAction)doCancel:(id)sender;

-(IBAction)doDelete:(id)sender;

@end

Antes de mais nada, precisamos lembrar que devemos passar a instância do

ManagedObjectContext para o formulário para que nele possa ser feita ações no Core Data.

Veja também que foi importado e declarada a propriedade da classe ContatoListController.

Esta declaração é de extrema importância para que se estabeleça uma comunicação entre a view

original e a que está em uso.

Criamos uma propriedade para armazenar qual é o contato atual que está em vigência no

formulário. Significa que, quando o objeto estiver instanciado com algum valor, estamos

editando, senão, inserindo um novo (caso o contatoAtual seja null). Repare que desta vez

declaramos os componentes como propriedades, isso significa que queremos acessá-los pela

classe. E os eventos abaixo correspondem a ação dos botões. Faça as devidas correspondências

no IB (control + arrasta).

Faremos agora torná-la visível. Neste caso, chamaremos ela como uma view modal. As views

modais são aquelas que se sobrepõem a todas outras e com exclusividade na ação, sendo que as

demais views só se tornam disponíveis quando esta se fecha.

Page 119: Curso iosx

Implementando o formulário (119)

Votando agora ao Formulario.m, implementaremos primeiro as propriedades declaradas no

header:

@synthesize managedObjectContext, contatoAtual, txtNome, txtIdade, btnSave, btnExcluir,

viewParent;

Vamos antes implementar o método doCancel que é o mais simples de todos. Precisamos

apenas que o formulário se torne invisível.

-(IBAction)doCancel:(id)sender

{

[self dismissModalViewControllerAnimated:YES];

}

Dados padrão nos campos (120)

A view Formulario serve para tanto inserir um novo registro como alterar. Logo, para

realizarmos alterações, precisamos que os dados ao serem lidos, estejam presentes nos campos.

Esta condição é definida pela instância da propriedade contatoAtual.

Se a instância da propriedade contatoAtual for nula (nil), então se trata de um novo registro.

Caso contrário, trata-se de uma alteração. Lembrando que a propriedade contatoAtual possui a

instância contato no qual foi selecionado na célula.

No arquivo Fomulario.m, procure pelo método viewDidLoad e caso esteja comentado, retire as

marcações (/* e */). O código ficará asism:

- (void)viewDidLoad {

[super viewDidLoad];

self.txtNome.text = [self.contatoAtual nome];

self.txtIdade.text = [NSString stringWithFormat:@"%d",[[self.contatoAtual idade]

intValue]];

if (self.contatoAtual !=nil)

{

[btnSave setTitle:@"Alterar" forState:UIControlStateNormal];

btnExcluir.hidden = NO;

}

}

Neste caso, as linhas que implementamos preenchem por padrão os valores dos campos do

formulário. O código para ler a idade está mais extenso, pois o valor da idade é do tipo

NSNumber, mas o TextField recebe valores NSString e necessita conversão de NSString para

NSNumber.

Page 120: Curso iosx

Dicas importantes

Há várias formas para convertemos os tipos de NSNumber para NSString e vice-versa, aqui

deixo uma que envolve menos código possível.

NSNumber -> NSString

[NSString stringWithFormat:@"%d",[NSNumberObj intValue]];

NSString -> NSNumber

[NSNumber numberWithInt:[NSStringObj intValue]];

E dentro da condição, verifica se tiver algum registro vinculado ao formulário, o botão Inserir

se chamará Alterar e o botão Excluir se tornará visível.

Salvando o registro (121)

Vamos agora implementar o método doSave, que vai executar a inserção do novo registro. Já

vimos que a condição de alterar ou inserir um novo é definido pela propriedade contatoAtual.

-(IBAction)doSave:(id)sender

{

Contatos *contato;

if (contatoAtual != nil) {

contato = contatoAtual;

}

else {

contato = (Contatos *)[NSEntityDescription

insertNewObjectForEntityForName:@"Contatos"

inManagedObjectContext:managedObjectContext];

}

//.....

}

Criamos um objeto chamado contato e verificamos a condição da propriedade contatoAtual. Se

não estiver definida, será declarado um novo objeto NSEntityDescription chamando o método

que insere um novo registro em branco na entidade. Para evitar conflitos no compilador, foi

reforçado que este NSEntityDescription é uma classe similar a Contatos.

Em seguida vamos definir os valores aos atributos (campos):

[contato setNome:[txtNome text]];

[contato setIdade:[NSNumber numberWithInt:[[txtIdade text] intValue]]];

E comitamos as modificações:

NSError *error;

if(![managedObjectContext save:&error]){

NSLog(@"houve um erro muito grave");

}

Feitas as alterações, precisamos atualizar a lista e claro, fechar a view. Primeiro vamos dar um

refresh na lista de registro, chamando o evento listaRegistros.

Page 121: Curso iosx

[viewParent listaRegistros];

Em seguida, atualizar o conteúdo da tabela

[viewParent.tableView reloadData];

E por fim, fechar a view modal.

[self dismissModalViewControllerAnimated:YES];

Veja o código na íntegra:

-(IBAction)doSave:(id)sender

{

Contatos *contato;

if (contatoAtual != nil) {

contato = contatoAtual;

}

else {

contato = (Contatos *)[NSEntityDescription

insertNewObjectForEntityForName:@"Contatos"

inManagedObjectContext:managedObjectContext];

}

[contato setNome:[txtNome text]];

[contato setIdade:[NSNumber numberWithInt:[[txtIdade text] intValue]]];

NSError *error;

if(![managedObjectContext save:&error]){

NSLog(@"houve um erro muito grave");

}

[viewParent listaRegistros];

[viewParent.tableView reloadData];

[self dismissModalViewControllerAnimated:YES];

}

Excluindo o registro (122)

A lógica para excluirmos um registro é bem simples. Lembrando que o botão Excluir só estará

habilitado se houver um registro aberto, logo, não é necessário fazer a verificação.

Primeiramente declaramos o objeto NSManagedObject com o valor do contatoAtual.

Em seguida, solicitamos a exclusão do objeto:

[managedObjectContext deleteObject:contato];

E por fim, comitamos as mudanças, reload na tabela e por fim, fechar o formulário, igual no

método doSave:

Page 122: Curso iosx

NSError *error;

if(![managedObjectContext save:&error]){

NSLog(@"houve um erro muito grave");

}

[viewParent listaRegistros];

[viewParent.tableView reloadData];

[self dismissModalViewControllerAnimated:YES];

O código na íntegra:

-(IBAction)doDelete:(id)sender

{

NSManagedObject *contato = contatoAtual;

[managedObjectContext deleteObject:contato];

NSError *error;

if(![managedObjectContext save:&error]){

NSLog(@"houve um erro muito grave");

}

[viewParent listaRegistros];

[viewParent.tableView reloadData];

[self dismissModalViewControllerAnimated:YES];

}

Tornando o formulário visível (123)

Voltemos ao ContatoListController.m e vamos implementar agora o addNovoRegistro.

Primeiro vamos importar o Formulario.h para termos acesso a classe.

#import "Formulario.h"

Em seguida, implementaremos o método

-(void)addNovoRegistro:(id)sender

{

Formulario *form = [[Formulario alloc] init];

[form setManagedObjectContext:[self managedObjectContext]];

[form setViewParent:self];

[self presentModalViewController:form animated:YES];

}

No código acima, primeiro declaramos o objeto form como do tipo Formulario, que é o view

controller da view que criamos agora pouco.

Formulario *form = [[Formulario alloc] init];

Em seguida passamos ao form o managedObjectContext e a quem é o view controller pai.

[form setManagedObjectContext:[self managedObjectContext]];

[form setViewParent:self];

Page 123: Curso iosx

E por fim, torná-lo visível de forma modal:

[self presentModalViewController:form animated:YES];

Hora de abrir o registro pela tabela (124)

Procure o método no ContatoListController.m chamado didSelectRowAtIndexPath. Este evento

é executado quando uma célula é selecionada.

A implementação do evento é muito similar ao do addNovoRegistro, a única diferença é que

temos de passar ao Formulario o objeto Contato que está atualmente selecionado, claro, antes

de invocar o método para tornar a view visível:

form.contatoAtual=[arrayLista objectAtIndex:[indexPath row]];

Veja o código na íntegra:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath

*)indexPath {

// Navigation logic may go here. Create and push another view controller.

Formulario *form = [[Formulario alloc] init];

form.managedObjectContext = self.managedObjectContext;

form.viewParent = self;

form.contatoAtual=[arrayLista objectAtIndex:[indexPath row]];

[self presentModalViewController:form animated:YES];

}

Pronto! Execute o programa e tente manipular os dados. Se algo deu errado, verifique o código

novamente.

Resumindo (125)

Classes do core data

NSError

Classe que é acionada caso algum erro de execução no app ocorra. Não é uma classe exclusiva

do Core Data, mas toda e qualquer ação a ser executada deverá conter o ponteiro para uma

variável desta classe.

NSManagedObjectContext

Representa a área de dados da sua aplicação, contendo todas as entidades declaradas em um

único arquivo de modelo de dados (aquele no qual fizemos a entidade e os atributos).

Page 124: Curso iosx

Quando o projeto é criado com o Core Data embutido, este objeto já vem instanciado e não há

necessidade de redeclará-lo, apenas passar a instância deste objeto para os demais classes na

qual deseja usá-lo (fizemos isso com o uso das propriedades).

NSEntityDescription

Este objeto representa a entidade a ser usada. Toda vez que alguma ação for feita no banco,

precisa-se antes especificar qual é a entidade (tabela) que será trabalhada.

A declaração deste objeto segue o seguinte padrão:

NSEntityDescription *objeto = [NSEntityDescription entityForName:@"entidade"

inManagedObjectContext:managedObjectContext];

Ou seja, sempre que for usar o core data, antes de mais nada, temos de declarar o Entity

Description.

NSFetchRequest

Equivale a um SELECT do SQL, ou seja, este objeto quando instanciado, retornará uma lista

com os registros contidos numa entidade. Para instanciá-lo:

NSFetchRequest *objeto = [[NSFetchRequest alloc] init];

[objeto setEntity:objetoNSEntity];

Os critérios de busca e ordenação estão definidos pelos objetos NSPredicate e

NSSortDescriptor.

NSPredicate

Não foi usada no exemplo, mas esta classe é de grande importância. É usada para estabelecer

critérios de filtragem na pesquisa. Para usá-la:

NSPredicate *objeto = [NSPredicate predicateWithFormat:@"criterio"];

[objetoNSFetchRequest setPredicate:objeto];

Algumas formas de critério de pesquisa:

Pesquisa simples:

campo == "valor"

campo like "valor"

campo > valor

Operações lógicas:

(campo like "valor") OR (campo like "valor")

(campo like "valor") AND (campo like "valor")

NSSortDescriptor

Usado para ordenar uma pesquisa, de acordo com os critérios de campo e formas de ordenação

(ascendente ou descendente).

Para usá-lo:

NSSortDescriptor *objeto = [[NSSortDescriptor alloc] initWithKey:@"campo"

ascending:YESouNO];

Page 125: Curso iosx

NSArray *objetoArray = [NSArray arrayWithObject:objeto];

[objetoNSFetchRequest setSortDescriptors:objetoArray];

No parâmetro ascending, caso queira ordenar de forma ascendente, use YES senão, use NO

(para descendente).

NSManagedObject

Classe genérica que implementa todos os atributos básicos do modelo do Core Data. Em outras

palavras, é a representação da classe que criamos automaticamente quando criamos o modelo

de dados (no nosso exemplo, o Contatos.h/.m)

Para listar objetos

Cria-se um NSEntityDescription com a entidade na qual se trabalhará

NSEntityDescription *objEntidade = [NSEntityDescription entityForName:@"Entidade"

inManagedObjectContext:managedObjectContext];

Cria-se um objeto NSFetchRequest, que receberá as filtragens

NSFetchRequest *objRequest = [[NSFetchRequest alloc] init];

[objRequest setEntity: objEntidade];

Caso seja necessário, cria-se o NSPredicate e o NSSortDescriptor

NSPredicate *objPredicate = [NSPredicate predicateWithFormat:@"criterio"];

[objRequest setPredicate:objPredicate];

Executa a consulta atribuindo os resultados ao array

NSSortDescriptor *objSortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"campo"

ascending:YESouNO];

NSArray *array = [NSArray arrayWithObject: objSortDescriptor];

[objSortDescriptor setSortDescriptors: array];

NSError *error;

NSMutableArray *arrayResultados = [[managedObjectContext executeFetchRequest:

objRequest error:&error] mutableCopy];

Para inserir um novo registro

Declara um NSEntityDescription com o método de inserção de um novo registro

ObjetoEntidade *objEntidade = (ObjetoEntidade *)[NSEntityDescription

insertNewObjectForEntityForName:@"entidade"

inManagedObjectContext:managedObjectContext];

Define os valores dos campos

[objEntidade setCampo1:@"valor1"];

[objEntidade setCampo2:@"valor2"];

Page 126: Curso iosx

Comita as alterações

NSError *error;

if(![managedObjectContext save:&error]){

// O que fazer quando deu um erro...

}

Pra editar um registro existente

O processo é similar ao anterior, só que ao invés de instarmos o objeto requerendo uma nova

linha, usaremos a instância do NSManagedObject com os dados abertos.

ObjetoEntidade *objEntidade = objNSManagedObjectInstanciado;

[objEntidade setCampo1:@"valor1"];

[objEntidade setCampo2:@"valor2"];

...

NSError *error;

if(![managedObjectContext save:&error]){

// O que fazer quando deu um erro...

}

Para excluir um registro

Instancie um NSManagedObject, igual feito no passo anterior

NSManagedObject *objeto = objNSManagedObjectInstanciado;

Solicite ao objeto managedObejectContext para que seja deletado aquela instância

[managedObjectContext deleteObject: objeto];

Comite as alterações

NSError *error;

if(![managedObjectContext save:&error]){

// O que fazer quando deu um erro...

}

XML (126)

Para encerrar a seqüencia deste capítulo, vamos tratar de dados em formato XML. Há vários

métodos diferentes para as mais diversas situações, mas vamos trabalhar com a principal delas,

que é a classe NSXMLParser.

Ao ser instanciado, o objeto varre linha a linha o código, identificando seus parâmetros,

atributos e até mesmo erros. E a cada linha descrita, um evento é acionado para fazer a leitura.

Para utilizar esta classe:

Page 127: Curso iosx

À classe que for trabalhar com o parser, declarar o protocolo

<NSXMLParserDelegate>, que vai importar os métodos relacionados.

Na própria classe, instancia-se o objeto NSXMLParser e define o delegate para ela

própria. Isto significa que todo o gerenciamento do xml será dado pela própria classe.

xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];

[xmlParser setDelegate:self];

Implementemos os métodos importados do protocolo.

Veremos o funcionamento com maiores detalhes no projeto final.

Métodos do NSXMLParserDelegate (127)

parserDidStartDocument:

Chamado quando o xml começa a ser lido.

-(void)parserDidStartDocument:(NSXMLParser *)parser

parserDidEndDocument:

Chamado quando o parser termina de ler o documento xml.

-(void)parserDidEndDocument:(NSXMLParser *)parser

parser:foundCharacters:

Chamado quando o parser encontra uma sequência de strings determinada.

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

Webview (128)

Webview (da classe UIWebView), é uma view na qual serve de suporte para conteúdo html.

Este conteúdo pode ser tanto carregado online, via url, quanto criado localmente. Possui suporte

para HTML5, CSS3 e Javascript, só não roda Flash, como já é de conhecimento geral o não

suporte pelos dispositivos móveis da Apple. É o mesmo objeto no qual funciona o Safari do

iOS (navegador padrão).

Para demonstrarmos o uso, crie um novo projeto e instancie uma UIWebView (nesta altura

você já deve saber como fazer, né? Caso ainda tenha dúvidas, vide o capítulo sobre Objetos de

interface com o usuário). Os testes abaixo serão realizados dentro do método viewDidLoad do

ViewController.

Operações com a webview (129)

Page 128: Curso iosx

Para abrir uma url de um site

NSString *url_endereco = @"http://suaurlaqui.com";

NSURL *url = [NSURL URLWithString:url_endereco];

NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];

[obj_web_view loadRequest:requestObj];

A sequência acima funciona da seguinte maneira:

Declaramos os o objeto NSURL, que servem para manipular URLs absolutas e relativas,

explicaremos melhor a seguir

Fazemos a requisição online desta URL. Esta requisição será armazenada no objeto

NSURLRequest.

Passamos a requisição para o webview.

Para passar valores html para o webview

NSString *html = @"conteudo";

[obj_web_view loadHTMLString:html baseURL:[NSURL fileURLWithPath:[[NSBundle

mainBundle] bundlePath]]];

O primeiro argumento é a string em si com o contúdo html. A segunda mostra qual é o diretório

raiz do documento, no qual os caminhos relativos irão tomar por base. Para entender melhor:

Importe uma imagem para a pasta resources do seu projeto

Na string do seu HTML, coloque <img src=”nome_do_arquivo_da_imagem”>

Use a estrutura acima para abrir o html

Significa que, sem o diretório base definido, a imagem não seria exibida, pois a view não usaria

a raiz do documento como referência.

Para abrir um arquivo html local

[obj_web_view loadRequest:[NSURLRequest requestWithURL:[NSURL

fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"nome_do_arquivo"

ofType:@"html"]isDirectory:NO]]];

Neste caso ele faz uma requisição local do arquivo que seja inserido na pasta Supporting Files

do seu aplicativo.

Classes relacionadas (130)

NSURL

Classe que cuida do gerenciamento de urls, seja elas locais (sistema de arquivos) como online.

Toda requisição de arquivos, seja online ou não, deve passar pela validação deste objeto. A

maneira mais usual de usá-la:

NSURL *url = [NSURL URLWithString:@"string da url"];

Page 129: Curso iosx

Desta forma, você transforma uma string em um objeto NSURL.

NSURLRequest

Representa a requisição de uma URL independente do seu protocolo. Os dados recebidos da url

ficam armazenados neste objeto, podendo ser passado para outros componentes que suportam

este objeto.

Desafio

Usando os seus conhecimentos de objetos de interface, experimente criar um app similar a um

navegador web, usando o campo TextField para indicar o endereço.

Projeto final (131)

Enfim, estamos na reta final do nosso curso. Chegou a hora de juntarmos tudo o que

aprendemos numa aplicação mais completa. Com certeza não usaremos 100% do que foi visto,

mas nada que impede que depois de concluído, você possa usá-los com o fim de enriquecer seu

aplicativo.

Como projeto final, iremos fazer um leitor de feeds RSS, de forma que você possa agregar seus

conteúdos preferidos num aplicativo simples.

Planejando o app (132)

Antes de colocarmos as mãos no código, vamos pensar um pouco no funcionamento do que

teremos no app e como melhor otimizar as telas para facilitar a navegação do usuário. E claro,

para que na hora de programar, termos um direcionamento mais preciso.

Neste app trabalharemos com duas divisões distintas: uma com as últimas postagens e uma com

o gerenciamento dos feeds. Pensando um pouco mais a frente, todas as abas cairão numa view

em comum, a qual que contem o conteúdo da postagem.

A estrutura pensada neste app segue o esquema abaixo:

Page 130: Curso iosx

Pense também que seria bom que o usuário pudesse ler offline os posts. Logo, a partir da leitura

do xml do RSS, tudo seria armazenado no banco de dados local. E, a partir disso, poder

manipular as preferências, como marcar como lido, marcar como favorito, enfim, as ideias são

infinitas.

O programa que iremos fazer neste projeto é apenas a base, o essencial para que você já tenha

uma noção do ciclo de criação de um aplicativo. Se você já tem experiência em outras áreas de

desenvolvimento, verá que não é muito diferente ou até mais simples do que já está

acostumado.

Mãos a obra! (133)

Crie um novo projeto Empty Application e dê o nome de LeitorRSS. Tenha certeza de que

deixou marcado que deseja usar o Core Data Framework.

Siga os passos para criar a MainWindow conforme descritas na referência (91).

Exemplo: Na prática (91)

No grupo Resources, você vai encontrar um arquivo chamado LeitorRSS.xcdatamodeld. Abra-o

e vamos criar nosso modelo de dados.

Modelo de dados (134)

Vamos pensar que temos dois tipos de entidades a serem criadas: uma contendo as urls dos

feeds cadastradas e uma outra com os posts em si, relacionados diretamente à url de onde foi

puxada.

Para as urls, vamos considerar dois campos: um contendo a url e outra contendo o nome do

site que virá ao puxarmos os dados do RSS. Já para os posts, precisaremos essencialmente dos

dados do título, conteúdo, data de publicação, além do guid e da identificação de origem do

feed, que no nosso exemplo usaremos a url de onde saiu.

No arquivo xcdatamodeld, crie uma entidade chamada Urls, com os seguintes atributos:

nome - String

url - String

Crie uma outra identidade com o nome de Posts, com os seguintes atributos:

feed_url - String

guid - String

titulo - String

conteudo - String

data_publicacao - Date

Page 131: Curso iosx

Caso tenha dúvida de como isso é feito, reveja este tópico no arquivo de Core Data.

No final, você terá uma estrutura similar a essa:

Temos agora de criar as classes para gerenciar essas entidades. Caso não se lembre, reveja aqui.

Faça estes passos para ambas as entidades. No final você terá dois pares de arquivos: Posts e

Urls.

Leitura dos feeds (135)

Trataremos a leitura de feeds num objeto a parte, para que esta funcionalidade se estenda a

outras partes do app. Este objeto irá ler o conteúdo XML da URL inserida e fará o rastreio no

arquivo inserindo no banco de dados.

Estrutura do RSS (136)

Antes de criarmos nosso objeto, veremos como funciona a estrutura do XML. O RSS (Really

Simple Syndication) é um formato de publicação em XML que é muito usada para compartilhar

conteúdo num formato aberto e comum.

O arquivo segue a seguinte estrutura:

<?xml version="1.0" encoding="UTF-8" ?>

<rss version="2.0">

<channel>

<title>titulo do site</title>

<description>Descrição do canal RSS</description>

Page 132: Curso iosx

<link>http://enderecoprosite.com.br</link>

<lastBuildDate>Mon, 01 Aug 2011 00:01:00 +0000 </lastBuildDate>

<pubDate>Mon, 01 Aug 2011 00:01:00 +0000 </pubDate>

<item>

<title>Titulo do post</title>

<description>Conteudo do feed</description>

<link>http://url.para.o.post</link>

<guid>string única identificadora</guid>

<pubDate>Mon, 06 Sep 2009 16:45:00 +0000 </pubDate>

</item>

</channel>

</rss>

No começo as declarações do XML e do RSS. Em seguida temos a tag CHANNEL, que inicia

as identificações do canal RSS, como título, endereço do site, descrição, data de publicação,

etc.

Abaixo, começam as séries das tags ITEM. Cada post publicado no feed estará dentro de um

grupo individual da tag ITEM. Basicamente seu conteúdo contem o TITLE (título),

DESCRIPTION (conteúdo do feed), LINK (endereço para o post diretamente), GUID

(identificador único do post no feed) e PUBDATE, com a data de publicação. Podem haver

outras tags dependendo do gerenciador de conteúdo for usado, mas basicamente são essas

informações.

Objetos relacionados (137)

Uma boa prática, para quando fizer armazenamento de dados bidimensionais, é criar uma classe

auxiliar para guardar estes valores. Desta forma, além de facilitar o acesso invocando de uma

única fonte, você pode incluir n outras funções para o tratamento dos dados.

Como o nosso parser vai ler uma série de grupos da tag item, logo, precisamos de um meio para

armazenar estes valores para que depois possamos processá-los no banco de dados.

Crie num novo arquivo do tipo NSObject e dê o nome de FeedPosts. Vamos declarar agora nos

cabeçalhos os campos nos quais precisamos armazenar no objeto:

NSString *titulo;

NSString *conteudo;

NSString *pubData;

NSString *guid;

Apesar do campo pubData ser armazenada no banco de dados como tipo Date, vamos a

princípio tratá-la como uma string, para depois cuidarmos das burocracias de conversão quando

precisarmos.

Esses valores têm de estar acessíveis a outras classes. Logo, vamos declará-los como

propriedades:

@property (nonatomic, retain) NSString *titulo;

Page 133: Curso iosx

@property (nonatomic, retain) NSString *conteudo;

@property (nonatomic, retain) NSString *pubData;

@property (nonatomic, retain) NSString *guid;

E por fim, precisamos criar um método inicializador, no qual vai receber todos estes valores na

hora instanciarmos o objeto. No nosso exemplo, ficaria algo como:

-(id)initWithTitulo:(NSString *)tit conteudo:(NSString *)cont pubData:(NSString *)pubd

guid:(NSString *)g;

Sendo que todos os valores dos campos estão contidos na mesma função.

Implementações (138)

Agora precisamos fazer a implementação da classe. No arquivo FeedPosts.m, implemente as

propriedades declaradas:

@synthesize titulo, conteudo, pubData, guid;

Vamos também declarar o nosso método inicializador, atribuindo para as variáveis de instância,

os valores passados:

-(id)initWithTitulo:(NSString *)tit conteudo:(NSString *)cont pubData:(NSString *)pubd

guid:(NSString *)g

{

if (self == [super init])

{

self.titulo = tit;

self.conteudo = cont;

self.pubData = pubd;

self.guid = g;

}

return self;

}

Parser (139)

Vamos agora à classe que vai fazer o tratamento do XML. Crie uma nova classe NSObject

chamada XMLParser, e vamos editar os cabeçalhos.

Primeiramente, precisamos de declarar que esta classe terá que responder a algumas funções do

NSXMLParser nativamente em sua estrutura. Para isso, teremos de declarar o protocolo

NSXMLParserDelegate.

@interface XMLParser : NSObject <NSXMLParserDelegate>

Em seguida vamos declarar as variáveis no qual vamos usar na leitura do feed. Em primeiro

lugar, precisamos de uma String que vá armazenar a URL atual que está sendo processada:

NSString *urlFeed;

Também a lista de itens listados no feed:

NSMutableArray *items;

Como o parser lê arquivo linha a linha e processa em lote, precisamos demarcar checkpoints

durante a leitura, para determinarmos quando começamos ou terminarmos ler uma seção do

Page 134: Curso iosx

feed. Para isso, vamos delimitar duas áreas em especial: o Channel e o Item. O Channel será

lido no começo e vai se encerrar quando iniciarmos a leitura do primeiro item. E a cada item,

terá o seu controle de início e fim. Veremos mais adiante o funcionamento mais claramente,

mas agora, vamos declarar estas variáveis:

BOOL channelElementInProgress;

BOOL itemElementInProgress;

Precisamos também de uma string global que dará acesso ao conteúdo presente dentro de uma

tag. Precisaremos que esta seja do tipo MutableString pois este valor irá se alterar

constantemente.

NSMutableString *dadoAtual;

E pro fim, algumas variáveis auxiliares que armazenarão os dados durante a leitura.

NSString *nomeFeed;

NSString *tempTitulo;

NSString *tempConteudo;

NSString *tempPubData;

NSString *tempGuid;

E não podemos esquecer do acessor ao Managed Object Context do Core data, que irá fazer as

devidas conexões ao banco de dados.

Sendo que o nomeFeed irá armazenar o valor do title dentro de channel e o bloco a seguir os

valores contidos no item em questão.

NSManagedObjectContext *moc;

Implementação e init (140)

Precismos declarar alguns deste itens como propriedades:

@property BOOL channelElementInProgress;

@property BOOL itemElementInProgress;

@property (nonatomic, retain) NSString *urlFeed;

E por fim, os métodos da classe:

-(BOOL)parse;

-(id)initWithUrlFeed:(NSString *)url;

Sendo que o primeiro será o que irá de fato fazer com que o processamento comece e o seguinte

o inicializador, passando na instância do objeto o valor da url.

Vamos agora à implementação da classe. Abra o arquivo XMLParser.m e vamos implementar

as propriedades:

@synthesize urlFeed, itemElementInProgress, channelElementInProgress;

Em seguida, vamos declarar o inicializador. Um detalhe diferente é que desta vez vamos

declarar puxando diretamente do AppDelegate, algo que não fizemos ainda durante o curso.

Para tal, primeiro vamos importar a classe:

#import "AppDelegate.h"

Page 135: Curso iosx

Para declararmos os AppDelegate, seguiremos a instrução abaixo:

AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

Desta forma, o objeto appDelegate passará a conter as propriedades e métodos públicos do

delegate. Vamos agora pegar o valor do Managed Object Context:

moc = appDelegate.managedObjectContext;

E por fim, atribuir ao urlFeed o valor do método incializador e alocar o array items.

urlFeed = url;

items = [[NSMutableArray alloc] init];

No final, o código estará assim:

-(id)initWithUrlFeed:(NSString *)url

{

if (self == [super init])

{

AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication]

delegate];

moc = appDelegate.managedObjectContext;

urlFeed = url;

items = [[NSMutableArray alloc] init];

}

return self;

}

didStartElement: (141)

Agora vamos aos métodos herdados do protocolo NSXMLParserDelegate. O primeiro que

veremos será o didStartElement: que faz o tratamento da tag inicial.

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

namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName

attributes:(NSDictionary *)attributeDict

{

}

Neste método, a lógica funcionará da seguinte forma:

Quando a tag <channel> for identificada, inicia-se o tratamento dos dados como channel.

if ([elementName isEqualToString:@"channel"])

{

[self setChannelElementInProgress:YES];

}

Quando a primeira tag <item> for identificada, significa que o tratamento do channel se encerra

e passa a tratar o conteúdo dos posts.

if ([elementName isEqualToString:@"item"])

{

[self setChannelElementInProgress:NO];

[self setItemElementInProgress:YES];

Page 136: Curso iosx

}

Sendo que setChannelElementInProgress e setItemElementInProgress são os setters das

propriedades do tipo BOOL antes declaradas e já comentadas.

No fim, o código do método completo.

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

namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName

attributes:(NSDictionary *)attributeDict

{

if ([elementName isEqualToString:@"channel"])

{

[self setChannelElementInProgress:YES];

}

if ([elementName isEqualToString:@"item"])

{

[self setChannelElementInProgress:NO];

[self setItemElementInProgress:YES];

}

}

foundCharacters: (142)

O método a seguir é o foundCharacters:. Este método pega os valores dos caracteres contidos

dentro da tag ativa, passando linha a linha.

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

{

}

A lógica envolvida neste método é simples. Declaramos nos cabeçalhos a mutable string

dadoAtual. Ela é quem vai receber o valor. Primeiro verificamos se ela já está alocada na

memória:

if(!dadoAtual)

{

dadoAtual = [[NSMutableString alloc] init];

}

E em seguida, passamos os valores registrados no evento a esta variável.

[dadoAtual appendString:string];

Simples! Os dados desta variável serão usadas no método a seguir, mas antes disso, o código do

método:

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

{

if(!dadoAtual)

{

dadoAtual = [[NSMutableString alloc] init];

}

Page 137: Curso iosx

[dadoAtual appendString:string];

}

didEndElement: (143)

E agora vamos trabalhar com o método didEndElement:. Este é invocado toda vez que detecta

um encerramento de uma tag: </item>, </channel>, etc.

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

namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName

{

}

Esta implementação será um pouco mais longa, pois é nela que vai conter as demais instruções

de gravação no banco de dados, etc.

Título do feed (144)

Vamos começar com o tratamento do channel, detectando se a tag </title> foi invocada

enquanto o channelElementInProgress era YES. O que será feito é simplesmente atribuir o

valor de dadoAtual ao nomeFeed, que corresponde ao nome do site.

if (self.channelElementInProgress)

{

if ([elementName isEqualToString:@"title"])

{

nomeFeed = [dadoAtual stringByTrimmingCharactersInSet:[NSCharacterSet

whitespaceAndNewlineCharacterSet]];

}

}

Sendo que o método stringByTrimmingCharactersInSet:[NSCharacterSet

whitespaceAndNewlineCharacterSet] retira os espaços excedentes. Equivale ao trim de

outras linguagens de programação.

Page 138: Curso iosx

Fechamento da tag item (145)

Agora vamos com o tratamento do fechamento da tag ITEM (</item>). Esta simboliza o fim do

carregamento das informações no post. O que temos de fazer neste bloco:

if ([elementName isEqualToString:@"item"])

{

}

Marcar que o item não está mais em progresso

[self setItemElementInProgress:NO];

Atribuir os valores das tags ao objeto

FeedPosts *feedP = [[FeedPosts alloc]initWithTitulo:tempTitulo conteudo:tempConteudo

pubData:tempPubData guid:tempGuid];

Os valores envolvidos serão declarados a seguir.

Inserir o objeto no array items.

[items addObject:feedP];

Este bloco ficará assim:

if ([elementName isEqualToString:@"item"])

{

[self setItemElementInProgress:NO];

FeedPosts *feedP = [[FeedPosts alloc]initWithTitulo:tempTitulo conteudo:tempConteudo

pubData:tempPubData guid:tempGuid];

[items addObject:feedP];

}

Dados dos posts (146)

Agora vamos tratar as tags do post individualmente, caso o itemElementInProgress esteja

YES. Em cada tag seguirá a mesma estrutura da que adotamos quando atribuimos os valores à

variável nomeFeed.

Verifique se o itemElementInProgress está como YES.

if (self.itemElementInProgress)

{

}

Dentro da condição, verificaremos se a tag foi fechada, e caso sim, atribuiremos o valor do

dadoAtual à sua variável temporária declarada no cabeçalho.

if ([elementName isEqualToString:@"title"])

{

Page 139: Curso iosx

tempTitulo = [dadoAtual stringByTrimmingCharactersInSet:[NSCharacterSet

whitespaceAndNewlineCharacterSet]];

}

Repita esses passos às demais tags. No final, este bloco ficará assim:

if (self.itemElementInProgress)

{

if ([elementName isEqualToString:@"title"])

{

tempTitulo = [dadoAtual stringByTrimmingCharactersInSet:[NSCharacterSet

whitespaceAndNewlineCharacterSet]];

}

if ([elementName isEqualToString:@"pubDate"])

{

tempPubData = [dadoAtual stringByTrimmingCharactersInSet:[NSCharacterSet

whitespaceAndNewlineCharacterSet]];

}

if ([elementName isEqualToString:@"description"])

{

tempConteudo = [dadoAtual stringByTrimmingCharactersInSet:[NSCharacterSet

whitespaceAndNewlineCharacterSet]];

}

if ([elementName isEqualToString:@"guid"])

{

tempGuid = [dadoAtual stringByTrimmingCharactersInSet:[NSCharacterSet

whitespaceAndNewlineCharacterSet]];

}

}

Page 140: Curso iosx

Fechamento da tag RSS (147)

E por fim, o tratamento do fechamento da tag RSS, que é a última tag do xml. Ela simboliza o

fim do arquivo, ou seja, depois dela, todos os dados colhidos poderão ser processados. No

nosso exemplo, vamos inserir no banco de dados o que colhemos e guardamos nas variáveis

antes declaradas.

Antes de começarmos a condição, vamos declarar o objeto NSError que é requerido pelas

funções do core data. Em seguida, inciaremos as condições:

NSError *error;

if ([elementName isEqualToString:@"rss"])

{

}

Verificação do cadastro do feed (148)

O primeiro passo é verificar se o feed já está cadastrado no banco, para evitarmos dados

duplicados.

Declarar o objeto NSEntityDescription, chamando a entidade Urls.

NSEntityDescription *entCheckUrl = [NSEntityDescription entityForName:@"Urls"

inManagedObjectContext:moc];

Declarar o objeto NSFetchRequest, que buscará os dados contidos na entidade

NSFetchRequest *reqCheckUrl = [[NSFetchRequest alloc] init];

[reqCheckUrl setEntity:entCheckUrl];

Adicionar a condição na consulta, caso a url já esteja cadastrada no banco de dados.

NSPredicate *predCheckUrl = [NSPredicate predicateWithFormat:@"url == %@",urlFeed];

[reqCheckUrl setPredicate:predCheckUrl];

Criar um array contendo os dados da busca

NSMutableArray *arrayCheckUrl = [[moc executeFetchRequest:reqCheckUrl error:&error]

mutableCopy];

Page 141: Curso iosx

Cadastro do feed (149)

Agora, a lógica é a seguinte: caso o número de itens presentes arrayCheckUrl seja 0, significa

que o registro não existe, logo, podemos prosseguir com a adição dos dados.

if ([arrayCheckUrl count] == 0)

{

}

Declara a classe Urls, associada a classe NSEntityDescription.

Urls *entUrls = (Urls *)[NSEntityDescription insertNewObjectForEntityForName:@"Urls"

inManagedObjectContext:moc];

Atribui os valores do feed ao objeto

[entUrls setNome:nomeFeed];

[entUrls setUrl:urlFeed];

Comita as informações

if(![moc save:&error]){

}

Este bloco na íntegra:

NSEntityDescription *entCheckUrl = [NSEntityDescription entityForName:@"Urls"

inManagedObjectContext:moc];

NSFetchRequest *reqCheckUrl = [[NSFetchRequest alloc] init];

[reqCheckUrl setEntity:entCheckUrl];

NSPredicate *predCheckUrl = [NSPredicate predicateWithFormat:@"url == %@",urlFeed];

[reqCheckUrl setPredicate:predCheckUrl];

NSMutableArray *arrayCheckUrl = [[moc executeFetchRequest:reqCheckUrl error:&error]

mutableCopy];

if ([arrayCheckUrl count] == 0)

{

Urls *entUrls = (Urls *)[NSEntityDescription insertNewObjectForEntityForName:@"Urls"

inManagedObjectContext:moc];

[entUrls setNome:nomeFeed];

[entUrls setUrl:urlFeed];

if(![moc save:&error]){

}

}

Page 142: Curso iosx

Verificação dos posts do feed (150)

E faremos agora a varredura pelos posts do feed, seguindo o mesmo esquema anterior,

passando item por item contido no array.

for (FeedPosts *fp in items)

{

}

Dentro do loop, vamos verificar se o registro já está cadastrado, verificando pelo guid e pelo

feed_url.

NSEntityDescription *entChecPost = [NSEntityDescription entityForName:@"Posts"

inManagedObjectContext:moc];

NSFetchRequest *reqCheckPost = [[NSFetchRequest alloc] init];

[reqCheckPost setEntity:entChecPost];

NSPredicate *predCheckPost = [NSPredicate predicateWithFormat:@"guid == %@ AND

feed_url == %@",[fp guid], nomeFeed];

[reqCheckPost setPredicate:predCheckPost];

NSError *error;

NSMutableArray *arrayCheckPost = [[moc executeFetchRequest:reqCheckPost error:&error]

mutableCopy];

Page 143: Curso iosx

Cadastro dos posts (151)

Em seguida, caso o arrayCheckPost seja 0, prossiga. Mas antes, vamos falar de um tópico

especial que é a conversão da data do formato NSString para o formato NSDate.

Vejamos um exemplo de como é o valor da data de publicação no RSS:

Sun, 31 Jul 2011 14:36:38 +0000

Para que este valor seja aceito no objeto NSDate, precisamos antes determinar o parâmetro de

formatação da data no objeto NSDateFormater que, ao receber este valor, irá sem problemas

fazer esta conversão.

Primeiro declaramos o objeto do tipo NSDateFormater

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];

Estabelecer o local no qual a data será calculada. Esta função é apenas uma formalidade

do objeto, pois o timezone já está definido na data (+0000).

NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];

[dateFormatter setLocale: usLocale];

Estabelecer o formato da data

[dateFormatter setDateFormat:@"EEE, dd MMM yyyy HH:mm:ss Z"];

Realiza a conversão

NSDate *pubdate = [dateFormatter dateFromString:[fp pubData]];

O código do bloco na íntegra (152)

for (FeedPosts *fp in items)

{

NSEntityDescription *entChecPost = [NSEntityDescription entityForName:@"Posts"

inManagedObjectContext:moc];

NSFetchRequest *reqCheckPost = [[NSFetchRequest alloc] init];

[reqCheckPost setEntity:entChecPost];

NSPredicate *predCheckPost = [NSPredicate predicateWithFormat:@"guid == %@

AND feed_url == %@",[fp guid], nomeFeed];

[reqCheckPost setPredicate:predCheckPost];

NSMutableArray *arrayCheckPost = [[moc executeFetchRequest:reqCheckPost

error:&error] mutableCopy];

if ([arrayCheckPost count] == 0)

Page 144: Curso iosx

{

Posts *entPosts = (Posts *)[NSEntityDescription

insertNewObjectForEntityForName:@"Posts" inManagedObjectContext:moc];

[entPosts setFeed_url:urlFeed];

[entPosts setGuid:[fp guid]];

[entPosts setTitulo:[fp titulo]];

[entPosts setConteudo:[fp conteudo]];

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];

NSLocale *usLocale = [[NSLocale alloc]

initWithLocaleIdentifier:@"en_US"];

[dateFormatter setLocale: usLocale];

[dateFormatter setDateFormat:@"EEE, dd MMM yyyy HH:mm:ss Z"];

NSDate *pubdate = [dateFormatter dateFromString:[fp pubData]];

[entPosts setData_publicacao:pubdate];

if(![moc save:&error]){

}

}

}

E finalmente, zerar o objeto dataAtual que deve constar na última linha do método,antes de

fechar as chaves }

dadoAtual = nil;

Page 145: Curso iosx

parse: (153)

Agora finalmente o método parse:, que fará com que toda a seqüência acima ser executada.

-(BOOL)parse

{

}

Converter a url de string para NSURL

NSURL *url = [[NSURL alloc] initWithString:[self urlFeed]];

Instanciar o objeto NSXMLParser

NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];

[parser setDelegate:self];

Enviar o comando para executar a varredura

[parser parse];

Fazer o retorno do método

return YES;

A view principal (154)

Abra o arquivo MainWindow.xib e adicione um Tab Bar controller. Exclua os dois view

controllers que veio como padrão e no lugar coloque dois Navigation View Controller. Em

seguida conecte o Window ao rootViewController.

Aos tabs criados, dê respectivamente os títulos Novidades e Feeds.

Substitua o View Controller dos itens por TableViewController.

Page 146: Curso iosx

Em seguida, dê os mesmo títulos ao NavigationTitleBar dos respectivos views.

Page 147: Curso iosx

Na segunda view, adicione um Bar Button Item. No inspector, coloque a propriedade Identifier

para Add.

Adicione imagens ao seu gosto para ilustrar os tabs. As que eu usei neste exemplo, você pode

baixar aqui.

Page 148: Curso iosx

View EditFeeds (155)

Vamos criar um novo view para que possamos cadastrar os feeds. Crie um novo

ViewController com o nome de EditFeeds. Abra o EditFeeds.xib e coloque deixe-o assim:

A disposição acima é uma sugestão. Apenas ilustrando uma forma de dispor os elementos.

Page 149: Curso iosx

Controller EditFeeds (156)

Abra agora o EditFeeds.h, e vamos declarar os outlets e os métodos.

Primeiro, precisamos determinar qual vai ser a janela-pai desta view, para que possamos manter

a conexão entre as classes. Primeiro importe a classe FeedsController.

#import "FeedsController.h"

Em seguida, declarar os outlets e métodos

IBOutlet UITextField *txtFeed;

FeedsController *parent;

@property (nonatomic, retain) FeedsController *parent;

-(IBAction)doSave:(id)sender;

-(IBAction)fechar:(id)sender;

E agora no arquivo EditFeeds.m, iremos implementar a classe, primeiramente implementando a

propriedade parent

@synthesize parent;

E agora, vamos ao evento fechar:. Vale frisar que esta view será exibida como Modal

-(IBAction)fechar:(id)sender

{

[self dismissModalViewControllerAnimated:YES];

}

E agora o evento de salvar o feed. Lembre-se que o responsável por isso é o objeto XMLParser.

Tratar a url inserida

NSString *feedURL = [[NSString alloc] initWithFormat:@"http://%@",[txtFeed text]];

Chamar o objeto XMLParser

XMLParser *xmlp = [[XMLParser alloc] initWithUrlFeed:feedURL];

Executar a verificação no xml

[xmlp parse];

E por fim, fechar a view

[self dismissModalViewControllerAnimated:YES];

O código completo

-(IBAction)doSave:(id)sender

{

NSString *feedURL = [[NSString alloc] initWithFormat:@"http://%@",[txtFeed text]]

XMLParser *xmlp = [[XMLParser alloc] initWithUrlFeed:feedURL];

[xmlp parse];

Page 150: Curso iosx

[self dismissModalViewControllerAnimated:YES];

}

Controller da lista de feeds (157)

Agora vamos trabalhar na lista de feeds. Crie uma nova classe TableViewController, mas sem o

arquivo da view chamada FeedsController. Associe esta class na TableView que colocamos no

Tab Bar.

Nos cabeçalhos, vamos declarar os objetos necessários para a nossa classe, começando pelo

nosso array que fará a listagem dos itens da tabela, além do objeto Managed Object Context.

NSMutableArray *listaFeed;

NSManagedObjectContext *moc;

Declare agora o array como propriedade para que ela se torne acessível a outras classes:

@property (nonatomic, retain) NSMutableArray *listaFeed;

E por fim, os eventos associados a classe. Primeiro o evento que vai responder ao botão + que

colocamos na view e também o evento que fará a leitura dos dados.

-(IBAction)novoFeed:(id)sender;

-(void)abrirDados;

Faça a conexão do botão + ao controller FeedsController.

Page 151: Curso iosx

Implementação do controller (158)

Agora na implementação, veremos as classes que estão associadas a este controller. Começando

pelo formulário de novo feeds, que será aberto ao clicarmos no botão +, além do AppDelegate,

das Urls que serão listadas:

#import "EditFeeds.h"

#import "AppDelegate.h"

#import "Urls.h"

Agora o método para chamar o formulário modal, passando a instância do view controller para

ele.

-(IBAction)novoFeed:(id)sender

{

EditFeeds *editFeeds = [[[EditFeeds alloc] init] autorelease];

[editFeeds setParent:self];

[self presentModalViewController:editFeeds animated:YES];

}

Até então passei rápido nestas declarações pois elas já não são novidade, são coisas já muito

exploradas nos capítulos anteriores.

abreDados: (159)

Iremos agora implementar o método abreDados: que fará a listagem do banco de dados no table

view.

-(void)abrirDados

{

}

No método, primeiro vamos declarar o objeto Managed Object Context para fazermos a

conexão com o banco e inicializarmos o array listaFeed.

AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

moc = appDelegate.managedObjectContext;

listaFeed = [[NSMutableArray alloc] init];

Em seguida, objeto com a entidade Urls, invocando a listagem e a ordenação por ordem

alfabética:

NSEntityDescription *objUrls = [NSEntityDescription entityForName:@"Urls"

inManagedObjectContext:moc];

NSFetchRequest *urlReq = [[NSFetchRequest alloc] init];

[urlReq setEntity: objUrls];

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"nome"

ascending:YES];

NSArray *arraySD = [NSArray arrayWithObject:sortDescriptor];

[urlReq setSortDescriptors:arraySD];

Page 152: Curso iosx

NSError *error;

NSMutableArray *arrayResultados = [[moc executeFetchRequest:urlReq error:&error]

mutableCopy];

Enfim, atribuir os resultados no array listaFeed, limpar o objeto NSFetchRequest da memória e

por fim, atualizar a lista.

listaFeed = arrayResultados;

[self.tableView reloadData];

Precisamos listar os dados já contidos no banco de dados assim que abrimos a view, logo, no

viewWillAppear:

[self abrirDados];

Configurações da tabela (160)

Agora para configurar os dados do table view, em numberOfSectionsInTableView:

return 1;

No evento numberOfRowsInSection:

return [listaFeed count];

E no evento cellForRowAtIndexPath, configuraremos a exibição dos dados. Logo abaixo da

linha comentada, primeiramente vamos colocar o indicador que ao clicarmos, há algo a mais a

ser visto:

cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

E o título da célula, que será puxado diretamente da propriedade nome do objeto Urls contido

no array listaFeed.

cell.textLabel.text = [[listaFeed objectAtIndex:[indexPath row]] nome];

Por enquanto paramos por aqui neste arquivo. Voltaremos nele logo mais quando criamos as

demais views.

View para lista de posts (161)

Nesta view vamos listar os posts de um feed cadastrado. Assim como no FeedsController, crie

um TableViewController com o nome de PostsController, desmarcando a opção de criar o

arquivo XIB. Abra o arquivo PostsController.h e vamos editar os cabeçalhos.

Page 153: Curso iosx

Cabeçalhos (162)

Esta view vai receber um objeto do tipo Urls para que seja feita a filtragem. Logo, precisamos

importar o objeto Urls e o App Delegate, para termos acesso aos dados.

#import "Urls.h"

#import "AppDelegate.h"

Em seguida, declararemos três objetos: o array com as listas, o objeto Urls que vai ser recebido

pelo FeedsController e o Managed Object Context.

NSMutableArray *items;

Urls *urlAtual;

NSManagedObjectContext *moc;

Por fim, precisamos que tanto a lista quanto o objeto urlAtual sejam acessíveis. Logo vamos

declarar como propriedade:

@property (nonatomic, retain) NSMutableArray *items;

@property (nonatomic, retain) Urls *urlAtual;

Implementação (163)

Nesta view vamos precisar passar para a view de visualização, o objeto posts. Logo, vamos

importá-lo para a classe:

#import "Posts.h"

E implementaremos as propriedades.

@synthesize items, urlAtual;

Em seguida, assim como fizemos no FeedsController, vamos inicializar o objeto declarando o

Managed Object Context e o array items.

-(id)init

{

if (self == [super init])

{

AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication]

delegate];

moc = appDelegate.managedObjectContext;

items = [[NSMutableArray alloc] init];

}

return self;

}

Page 154: Curso iosx

Lista de posts (164)

Ao exibirmos a view, vamos fazer a listagem dos posts contidos. Logo, vamos proceder

diretamente no método viewDidLoad:. O processo vai ser similar ao que fizemos no método

abreDados: no FeedsController. A grande diferença é que faremos a filtragem da entidade

Posts, usando como critério o atributo feed_url, ordenado pela data de publicação do mais

novo para o mais antigo.

NSEntityDescription *objPosts = [NSEntityDescription entityForName:@"Posts"

inManagedObjectContext:moc];

NSFetchRequest *reqPosts = [[NSFetchRequest alloc] init];

[reqPosts setEntity:objPosts];

NSPredicate *predPosts = [NSPredicate predicateWithFormat:@"feed_url == %@",[urlAtual

url]];

[reqPosts setPredicate:predPosts];

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]

initWithKey:@"data_publicacao" ascending:NO];

NSArray *arraySD = [NSArray arrayWithObject:sortDescriptor];

[reqPosts setSortDescriptors:arraySD];

NSError *error;

NSMutableArray *arrayResultados = [[moc executeFetchRequest:reqPosts error:&error]

mutableCopy];

if (!reqPosts) {

}

items = arrayResultados;

[reqPosts release];

E vamos colocar o título da view para o nome do feed url:

[self setTitle:[urlAtual nome]];

Page 155: Curso iosx

Configuração da tabela (165)

Configurando a tabela agora, vamos aos métodos:

numberOfSectionsInTableView:

return 1;

numberOfRowsInSection:

return [items count];

cellForRowAtIndexPath:

cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

cell.textLabel.text = [[items objectAtIndex:[indexPath row]] titulo];

Logo mais vamos implementar o método didSelectRowAtIndexPath. Mas antes disso, vamos

fazer esta view se tornar visível.

Abrindo esta view (166)

Voltaremos ao arquivo FeedsController.m e vamos implementar o método

didSelectRowAtIndexPath desta classe. Mas antes disso, importaremos a classe

PostsController.

#import "PostsController.h"

No método didSelectRowAtIndexPath vamos chamar esta view, passando a instância do

objeto Urls da linha selecionada ao PostsController.

PostsController *pcontrol = [[PostsController alloc] init];

[pcontrol setUrlAtual:[listaFeed objectAtIndex:indexPath.row]];

[self.navigationController pushViewController:pcontrol animated:YES];

View de exibição do post (167)

Esta view será focada em exibir o post. Para isso, vamos usar o webview, que nos proporciona

maior mobilidade no tamanho do conteúdo. Crie uma nova classe ViewController, marcando a

opção de criar o arquivo XIB e dê o nome de Postagem.

Abra o arquivo Postagem.xib e inclua um Web View, cobrindo toda a área da view. Em

seguida vamos implementar a classe.

Page 156: Curso iosx

Cabeçalhos (168)

Primeiro os cabeçalhos. Precisamos declarar dois objetos: O outlet com o webview e o objeto

Posts, que vai receber a instância desta classe com os dados a serem exibidos. Logo, precisamos

importar o objeto Posts:

#import "Posts.h"

Em seguida os objetos e as propriedades:

IBOutlet UIWebView *webConteudo;

Posts *post;

@property (nonatomic, retain) Posts *post;

Implementação (169)

Na implementação do método, vamos instanciar a propriedade:

@synthesize post;

Faça as conexões dos objetos da classe com a interface. Em seguida, faremos que ao exibirmos

a view, os dados sejam carregados em formato html, no método viewDidLoad:

Declarar uma string com o html para o título:

NSString *html_titulo = [[NSString alloc] initWithFormat:@"<h1>%@</h1>",[post titulo]];

Declarar outra string com o conteúdo, que ficará dentro de uma DIV com a class

conteudo.

NSString *html_conteudo = [[NSString alloc] initWithFormat:@"<div

class=\"conteudo\">%@</div>", [post conteudo]];

Inserir ambas as strings para o objeto WebView.

[webConteudo loadHTMLString:[NSString stringWithFormat:@"%@%@", html_titulo,

html_conteudo] baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];

Colocar o título da view com o título do post.

[self setTitle:[post titulo]];

Page 157: Curso iosx

Formatação CSS (170)

A exibição do html está sem formatação, com o estilo padrão. Uma das vantagens de

trabalharmos com o webview é a possibilidade de usarmos todos os recursos de formatação

web, entre eles javascript e CSS.

Crie um arquivo chamado postagem.css. Deixe-o no grupo Supporting Files para fins de

organização. O código do CSS usado no exemplo foi:

h1, div {

font-family:Helvetica;

}

div.conteudo {

color:#666;

}

Para importar o css para o webview, usaremos recursos html, com o artifício do código do

objective c.

Antes da string html_titulo, crie uma string chamada html_css, que conterá a tag <link> que

fará a importação do css ao html

NSString *html_css = @"<link href=\"postagem.css\" rel=\"stylesheet\" type=\"text/css\" />";

Na linha onde tem a configuração do webConteudo, adicione esta variável para ser exibida no

conteúdo, modificando para:

[webConteudo loadHTMLString:[NSString stringWithFormat:@"%@%@%@", html_css,

html_titulo, html_conteudo] baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle]

bundlePath]]];

Exibindo a view pela lista de posts (171)

Voltemos ao PostsControler.m. Antes, precisamos importar a classe Postagem para ser

exibida.

#import "Postagem.h"

Em seguida, passar o objeto Posts ao selecionarmos uma célula e exibir a view com a

postagem. No método didSelectRowAtIndexPath:

Postagem *viewpost = [[Postagem alloc] init];

[viewpost setPost:[items objectAtIndex:indexPath.row]];

[self.navigationController pushViewController:viewpost animated:YES];

Page 158: Curso iosx

A view da aba Novidades (172)

Para esta view, usaremos um Table View. Mas, iremos fazer uso de uma tabela com várias

seções. Cada seção corresponderá a um feed cadastrado e mostrará o último post cadastrado em

cada uma.

Crie uma classe TableViewController chamada Novidades. Desmarque a opção de criar um

arquivo XIB, pois usaremos a view anexada no MainWindow. Atribua esta classe ao

ViewController do primeiro item do tab bar do Main Window.

Nos cabeçalhos do Novidades.h, vamos declarar dois objetos: um array para a lista, um para os

cabeçalhos, que conterá o título da seção, e um objeto Managed Object Context, para o banco

de dados.

NSMutableArray *itens;

NSMutableArray *cabecalhos;

NSManagedObjectContext *moc;

Implementação do arquivo Novidades.m(173)

Nesta view, teremos de listar o último post de cada feed cadastrado e por seguinte exibir na

view de postagem. Logo, vamos ter de importar estas classes.

#import "Posts.h"

#import "Urls.h"

#import "Postagem.h"

#import "AppDelegate.h"

Implementaremos o método viewDidLoad: que fará a listagem tanto dos cabeçalhos quanto

dos posts dentro dos respectivos arrays.

Declarar o Managed Object Context

AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

moc = appDelegate.managedObjectContext;

Fazer a busca na entidade Urls procurando por todos os endereços de feeds cadastrados e

inserí-los no array cabecalhos.

NSEntityDescription *objUrls = [NSEntityDescription entityForName:@"Urls"

inManagedObjectContext:moc];

NSFetchRequest *urlReq = [[NSFetchRequest alloc] init];

[urlReq setEntity: objUrls];

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"nome"

ascending:YES];

NSArray *arraySD = [NSArray arrayWithObject:sortDescriptor];

[urlReq setSortDescriptors:arraySD];

NSError *error;

Page 159: Curso iosx

NSMutableArray *arrayFeeds = [[moc executeFetchRequest:urlReq error:&error]

mutableCopy];

cabecalhos = [[NSMutableArray alloc] initWithArray:arrayFeeds];

Varrer dentro do array gerado pela pesquisa arrayFeeds, e inserir o primeiro registro de cada

resultado no arrayPosts. Para que possamos pegar o mais novo no primeiro registro do array,

vamos ordernar a busca como ordem decrescente pela data. No final, atribuir o resultado da

consulta ao array itens.

NSMutableArray *arrayPosts = [[NSMutableArray alloc] init];

for (Urls *u in arrayFeeds)

{

NSEntityDescription *objPosts = [NSEntityDescription entityForName:@"Posts"

inManagedObjectContext:moc];

NSFetchRequest *reqPosts = [[NSFetchRequest alloc] init];

[reqPosts setEntity:objPosts];

NSPredicate *predPosts = [NSPredicate predicateWithFormat:@"feed_url == %@",[u url]];

[reqPosts setPredicate:predPosts];

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]

initWithKey:@"data_publicacao" ascending:NO];

NSArray *arraySD = [NSArray arrayWithObject:sortDescriptor];

[reqPosts setSortDescriptors:arraySD];

NSError *error;

NSMutableArray *arrayTempPosts = [[moc executeFetchRequest:reqPosts error:&error]

mutableCopy];

[arrayPosts addObject:[arrayTempPosts objectAtIndex:0]];

}

itens = [[NSMutableArray alloc] initWithArray:arrayPosts];

Page 160: Curso iosx

Configurações da tabela (174)

Vamos às configurações das células. Em primeiro lugar, é bom lembrar que desta vez

trabalharemos com uma tabela multi-secionada. Logo, no método

numberOfSectionsInTableView, colocaremos o número de itens do array cabecalhos.

return [cabecalhos count];

E no numberOfRowsInSection, cada seção terá 1 item, então:

return 1;

E um novo método há de ser implementado, que determina o título das seções. Por padrão ele

não está inserido no código, tendo de inserir:

- (NSString *)tableView:(UITableView *)tableView

titleForHeaderInSection:(NSInteger)section

{

return [[cabecalhos objectAtIndex:section] nome];

}

Em cada linha, o título do post, no método cellForRowAtIndexPath:

cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

cell.textLabel.text = [[itens objectAtIndex:indexPath.section] titulo];

E por fim, vamos chamar a view que abrirá o post quando escolhermos a linha, no método

didSelectRowAtIndexPath:

Postagem *viewpost = [[Postagem alloc] init];

[viewpost setPost:[itens objectAtIndex:indexPath.section]];

[self.navigationController pushViewController:viewpost animated:YES];

De código, isso é tudo que temos a fazer. Agora vamos cuidar de alguns aspectos de

apresentação do nosso app.

Refinamentos (175)

Ícones

Para identificar-mos o app no dispositivo, precisamos de um ícone que o remeta bem. Crie uma

imagem 57x57 pixels (114x 114 para o retina display). Todo o efeito de sombra, luz e

arredondamento é feito automaticamente pelo iPhone. Salve-os com o nome de Icon.png

([email protected] para o retina display). Importe-as para o projeto (grupo Resources).

Ícones usados neste app.

Tela de Splash

Agora vamos criar uma tela de apresentação do nosso app; aquela imagem que apresenta o

programa, empresa ou afins. Para isso, crie uma imagem nas dimensões 320x480 px

(640x960px para a versão retina display) e salve-as com o nome de Default.png e

[email protected] respectivamente. Importe-as para o projeto no grupo resources.

Imagens usadas neste app.

Page 161: Curso iosx

Desafios propostos para melhorias (176)

Como pode ver, há muitas possibilidades para expandir as funcionalidades, nas quais, com o

decorrer do curso, você com certeza deve ter aprendido. O objetivo agora é deixar em suas

mãos a implementação de alguns recursos, tais como:

Possibilidade do usuário favoritar um post

Excluir um feed

Excluir um post

Atualizar as postagens de feeds, forçando a leitura do xml parser

Marcar como lido ou não lido

E muitas outras que poderão vir de acordo com a sua criatividade. Tente implementá-las usando

seus conhecimentos. Estarei aqui para tirar as dúvidas. Mas, o mais importante é ter a segurança

de que aprendeu, seguindo seus passos de forma independente. Mãos a obra!

Considerações finais (177)

Enfim, chegamos ao fim deste curso do iMasters PRO! O objetivo foi apresentar a você parte

dos infinitos recursos que o iPhone pode oferecer. Infelizmente não conseguimos tratar de todas

as funcionalidades, até porque, muitas delas são muito extensas e nos mais diversos focos, mas

por agora, você está gabaritado para atender boa parte da demanda de apps para iPhone.