Vous êtes sur la page 1sur 41

Guia Definitivo

para dominar o principal


componente em aplicativos iOS
UITableView: O Principal 
Componente em Aplicativos iOS 
UITableView​ ​é a View mais usada em aplicativos iOS, competindo apenas com o seu 
"primo"​ ​UICollectionView​. 
 
Aplicativos como Facebook, Instagram e Spotify são exemplos empíricos de que a 
UITableView​ ​está presente em boa parte dos aplicativos mais comuns. 
 

 
 
Seja você iniciante ou Expert, dominar esse componente irá te ajudar a criar aplicativos de 
mercado além de aumentar a sua capacidade de criação de novos projetos. Isso porque a 
UITableView​ ​está presente em​ ​mais de 80% dos aplicativos já criados​. 
 
A​ ​UITableView​ ​permite que o usuário final do aplicativo faça duas coisas que são, na minha 
opinião, essenciais na era da informação: 
 
1. Listar dados (de uma forma elegante, customizada e eficiente) 
2. Permitir a interação dos dados com outras Views (ver detalhes, reordenar, excluir, etc) 
 
Ao final desse eBook você já estará dominando esse componente e estará na frente de muitas 
pessoas. Acredito que esse componente é apenas 20% de todos os componentes fornecidos 
pela Apple, mas é capaz de estar presente em 80% do seu projeto. 
COMO CRIEI UM ​APLICATIVO PROFISSIONAL DO ZERO 
EM ​88 DIAS​ SEM NUNCA TER ESCRITO ​UMA LINHA DE 
CÓDIGO SWIFT​ OU ​USADO O XCODE​! 
Meu nome é Tiago Aguiar, sou Desenvolvedor de Software Sênior (tanto 
Web quanto Mobile) e uso meu tempo para compartilhar experiências que 
transformam "pessoas comuns" em Desenvolvedores & Designers 
Extraordinários. Tudo através de videos, insights, artigos e produtos na web. 
 
Desde 2012, onde comecei minha jornada mobile, crio aplicativos Android pessoais e para 
empresas. Porém, eu queria sair da minha zona de conforto, queria me aventurar no mundo 
Apple​ por sempre admirar os produtos extraordinários criado pela empresa. De fato, eles são 
referências em tudo que faço. Inclusive esta fonte de texto que você está lendo agora foi 
pensado com calma em busca da fonte perfeita para a sua leitura ​;-) 
 
Como falei, eu queria sair da minha zona de conforto e criei a oportunidade (um dia eu te conto 
como você cria oportunidades) para desenvolver aplicativos iOS dentro da startup que estou 
onde comecei a coordenar um time de desenvolvedores.  
 
Em Janeiro de 2016 eu decidi fazer isso do absoluto ZERO, sem mesmo nunca ter encostado 
em um Mac, literalmente. Não conhecia Xcode, nem Swift, nem Objective-C. Nada!  
 
Eu acreditava ser simples, mas nunca fácil. Logo, eu consumi todo o tipo de material que você 
possa imaginar, isso porque eu tinha dois obstáculos nada pequenos...  
 
… meu tempo era limitado porque eu não tinha um Mac e tinha que ser 
feito no trabalho, dentro de 8h (isso contando que eu não ficava 8h 
nisso). E também tinha que ser perfeito porque era um aplicativo 
profissional. Usado por mais de 50.000 pessoas. 
 
Pra você entender melhor, minha missão era reescrever do absoluto 
zero um aplicativo iOS escrito em Objective-C para a nova linguagem 
Swift (na época). Detalhe: não sabia Objective-C e nem mesmo Swift. 
 
No fim da história eu consegui fazer isso em 88 dias. O aplicativo estava 
pronto totalmente em Swift (em um outro momento conto com mais detalhes)! 
 
O que eu quero mostrar aqui com a minha história é que desenvolver qualquer aplicativo ou 
mudar de linguagem de programação é uma tarefa ardua porém simples e que todos podemos 
fazer. Você só precisa de 2 coisas:   
 
1. O desejo irrazoável pra fazer seu projeto acontecer! 
2. O método certo. Conhecer os atalhos que te colocam um passo a frente cada dia. 
 
Simples assim! 
 
E você já tem o atalho principal em suas mãos agora. Dominar a ​UITableView. ​Agora 
você precisa pegar esse atalho e colocar um desejo irrazoável pra fazer seu projeto acontecer 
 
Agora que você já sabe que o seu primeiro passo é dominar a​  ​UITableView​, ​vamos 
começar! 
 

PASSO #0: DEFINIR A IDEIA 
Além de compartilhar com você meu conhecimento sobre ​UITableView​ mostrando 
exemplos práticos do básico à maestria, quero mostrar com ideias de projetos que são de fato, 
aplicadas no "campo de batalha". Isto é, ideias de ​projetos reais​ que você pode aplicar em 
qualquer lugar, seja no seu trabalho ou projeto pessoal. 
 
Logo, o primeiro passo antes de escrever uma linha sequer de código é definir o que vamos 
criar. 
 
Criaremos um aplicativo que listará os produtos de uma loja virtual de jogos digitais. 

         
Nosso aplicativo passará por vários estágios. Desde uma listagem básica até a arte final. Isso 
porque quero te ensinar os princípios por traz de uma ​UITableView​ e como você pode ir 
"lapidando" o seu projeto tornando-o cada vez melhor. 

PASSO #1: CRIANDO O PROJETO 
Abra seu Xcode​ ​[ ​cmd + space​ ]​ e  clique em criar novo projeto [ ​Create a new Xcode project 
]. 

 
 
Selecione a opção [ ​Single View Application​ ] para criar um aplicativo comum do início. 
 
 
Adicione as seguintes informações para construir o aplicativo: 
 
● Product Name: ​<Nome do Seu Aplicativo> 
● Organization Name: ​<Nome da Organização> 
● Team: ​<Sua Equipe>​ (Você pode criar com seu Apple ID) 
● Organization Identifier: ​<usado como um identificador único do seu aplicativo> 
● Language: Swift 
● Devices: Universal 
 
 
 
Escolha seu [ workspace ] para salvar o projeto. ​Use Core​,​ Data Unit Tests​,
Include UI Tests​, não  serão necessários.  
 
Caso tenha problemas com o parâmetro [ ​team​ ], selecione [ ​Add an Account…​ ] e crie uma 
identifação com seu Apple ID. 

 
 
 
Pronto! Agora você já tem um projeto iOS inicial para começar a brincar. 

 
 

PASSO #2: CRIANDO A View UITableView 
A primeira dica aqui é começar a modelar a camada de ​view​ do seu aplicativo. Logo, vamos 
selecionar o arquivo ​main.storyboard​ e começar a construir nossa ​UITableView 
(bem simples para começar). 
 
A esquerda da tela é possível selecionar a ​View Controller​ no qual você está 
trabalhando… 
 
 
… e logo abaixo, o tamanho do dispositivo para visualizar como está ficando a View … 
 

 
 
Como boas práticas, vamos incorporar nossa ​View Controller​ padrão à uma 
Navigation View Controller​ que será responsável pela navegação superior, bem 
como título da nossa view. 
 
É bem simples! Basta selecionar a ​View Controller​, clicar em ​Editor​ > ​EmbedIn ​> 
Navigation Controller​. 
 
 
Agora a sua ​View Controller​ possui uma ​Navigation Controller​ que poderá 
abrir menus, ir e vir de views futuramente. 
 
Adicione um título ao seu aplicativo clicando ​Navigation Item​ que apareceu no menu da 
storyboard. 

 
No menu inferior a direita você encontra uma variedade rica de componentes nativos que o 
`SDK` do iOS (kit de desenvolvimento de software) fornece. Hoje vamos usar a 
UITableView.
Selecione sua ​View Controller​ e desative a opção [ Adjust Scroll View Insets ] caso sua 
UITableView​ tenha uma margem superior desnecessária.  
 
Vamos adicionar uma ​UITableView​ à nossa view. 
 
Você pode está se perguntando sobre o por quê não usar a ​Table View Controller
ao invés de adicionar uma ​UITableView ​a  ​View Controller.

Existe apenas uma pequena desvantagem em usar uma ​Table View Controller 


diretamente. Nós não podemos adicionar outros componentes (leia-se views) ao redor de uma 
UITableView ​neste caso. 
 
Não é uma regra, só uma preferência aqui. 
 
Arraste a ​UITableView​ para dentro da ​ViewController​. 
 
Vamos adicionar o ​AutoLayout​ nessa view para que ela se adpate a qualquer tamanho de 
dispositivo (iPhone 5, iPhone 7 Plus, etc). 
 
Para adicionar o ​AutoLayout​ que preencha todo o espaço da view pai, basta clicar nesse 
pequeno ícone que fica abaixo da tela a direita e colocar os valores 0 ao redor (lembre-se de 
desmarcar a opção ​Constraint to margins​ para evitar margins e selecionar Update 
frames: Items of new constraints). 
 

 
 
A ​UITableView​ foi criada, porém, ela ainda não possui nenhuma célula para que possamos 
inserir dados nela. Células conhecidas como ​UITableViewCell​. 
 
Selecione a ​UITableView​ e clique no botão ​Inspector​ no canto superior direito do 
Xcode e adicione um protótipo de célula para um conteúdo dinâmico. 
 

 
 
Aqui indicamos a ​ViewController​ que sua ​UITableView​ terá células sendo criadas 
dinamicamente de acordo com este protótipo de célula ​UITableViewCell​. Mais a frente, 
iremos criar células customizadas com imagens, textos e etc. 
 
Quando você selecionar a ​UITableViewCell​ e clicar no ​Inspector​ você poderá 
mudar o estilo da célula. O Xcode nos fornece 5 opções de estilo para a ​UITableViewCell​. 
 
● Custom 
● Basic 
● Right Detail 
● Left Detail 
● Subtitle 
 
Pra começar, vamos escolher o estilo subtitle da ​UITableViewCell.
PASSO #3: CRIANDO O MODEL VIEW CONTROLLER 
(M-V-C) 
Nossa tabela precisa de dados para serem listados. Mas antes de criar os dados, vamos 
adicionar algumas imagens do nosso aplicativo (game store). Para adicionar, vamos selecionar a 
pasta ​Assets.xcassets.​ Clique no sinal de "mais" [ + ] e clique em ​New Image
Set.

Selecione no seu ​Finder ​as imagens dos produtos (jogos digitais) e adicione ao pacote de 
imagens no xcode. 
 
Imagens 2x são utilizadas para dispositivos de alta resolução (retina). 
 
Para criar a ​View Controller ​que será responsável por "gerenciar" nossa view e os 
dados (model), basta usar as teclas [ cmd + N ], escolher uma nova classe ​Cocoa Touch
Class.

Vamos dar o nome da nossa ​View Controller ​de  ​GameViewController.


Na ​Main.storyboard,​devemos indicar que a controladora dessa view que possui a 
tableView é a nossa nova classe ​GameViewController.
Pra fazer isso, selecione a controller e escolha no ícone ao lado esquerdo do Inspector o nome 
da classe. 

 
Agora que a view sabe que é sua controladora, vamos construir uma referência da nossa 
UITableView ​no código swift para que possamos manipular esse componente via código. 
Quando selecionar a (no ícone amarelo em cima da controller) ​ViewController
podemos abrir a classe em uma nova perspectiva de janela e conectar os pontos (view e 
controller). 

 
Aqui acontece a "mágica" do Xcode. ​Muita atenção aqui! ​Você deve selecionar a 
UITableView,​segurar a tecla ​Ctrl,​ ​clicar​ ​e arrastar o mouse para dentro do código 
swift e BOOM! Agora é possível criar um ​IBOutlet ​(uma referência) da ​UITableView.

Dê um nome a nova variável. Neste ponto a ViewController sabe qual é o componente (leia-se 
view) que deve ser manipulada.  
 
@IBOutlet weak var​ ​tableView​: ​UITableView​! 
 
Sempre que um ​IBOutlet ​é criado e conectado com a View, sua referência com a View é 
garantida quando uma pequena "bolinha" é exibida. 
 
Vamos retomar a ​UITableViewCell ​e adicionar um identificador para ela. Logo, quando 
estivermos trabalhando dentro do Swift, podemos pegar essa view dentro do código através de 
seu ​Identifier​. Chamaremos nosso identificador de ​GameCell.

 
 
Chegou a hora de criar os dados! 
 
Para manter o foco desse material que é a ​UITableView,​vou mostrar um arquivo Model 
Fake pronto com os dados necessários para exibir na tabela. Lembre-se que os dados podem 
vir de vários ambientes, seja um arquivo, um JSON via HTTP, um XML do webservice, 
whatever… 
 
Esse arquivo possui uma Struct de Game e uma Struct que lista esses Games com um método 
estático. Essa é a forma mais rápida de se construir dados fakes para podermos utilizar em 
nossos controllers. 
//
// Games.swift
// gamestore
//
// Created by Tiago Aguiar on 3/29/17.
// Copyright © 2017 Code Spartan. All rights reserved.
//

import Foundation

struct Game {
var name: String
var desc: String
var imageName: String
}

struct Games {
static func getAllGames() -> [Game] {
return [
Game(name: "Resident Evil 7", desc: "horror game",
imageName: "resident_evil_7"),
Game(name: "The Legend of Zelda Skyward", desc: "adventure
game", imageName: "legend_of_zelda_sky"),
Game(name: "God of War 3", desc: "adventure game",
imageName: "god_of_war_3"),
]
}
}
Ok! Agora que temos nossa camada Model definida, vamos a Controller e fazer a 
UITableView ​ler esses dados. 
 
Primeiro, vamos recordar como está a classe neste momento. 
 
class​ GameViewController: ​UIViewController​ { 
 
    ​@IBOutlet weak var​ tableView: ​UITableView​! 
 
    ​override func​ viewDidLoad() { 
        ​super​.​viewDidLoad​() 
    } 
 
    ​override func​ didReceiveMemoryWarning() { 
        ​super​.​didReceiveMemoryWarning​() 
    } 

 
Temos apenas nossa view com uma referência weak nomeada tableView. 
 
Os métodos viewDidLoad e didReceiveMemoryWarning são executadas no ciclo de vida da View 
Controller. Não iremos entrar em detalhes neste momento. 
 
Para que o aplicativo liste os jogos que, em tese, cadastramos, vamos fazer os seguintes passos: 
 
1. Declarar a variável de ​games​. 
2. Criar uma ​extension​ da ​GameViewController 
3. Implementar o ​protocol​ ​UITableViewDataSource​ que será responsável por observar 
os eventos que acontece na ​tableView​ como construir novas células. 
4. Definir o número de seções que a tabela terá 
5. Definir o número de linhas por seção 
6. Adquirir o objeto ​TableViewCell​ e atribuir os dados da model. 
7. Dizer a ​tableView​ qual será a classe responsável por observar o ​protocol 
UITableViewDataSource 
 
Lembra do identificador que colocamos na ​UITableViewCell?
Agora iremos utilizar no método:  
 
let​ cell = tableView.​dequeueReusableCell​(withIdentifier: 
"GameCell"​)! 
 
Dessa forma, garantimos que todas as vezes que houver a necessidade de uma rolagem na 
tabela através do scrolling podemos reutilizar o objeto, evitando a criação de novos objetos para 
cada célula exibida na tela. Logo, a memória é desalocada e objetos reutilizados sempre que 
necessário. Esse gerenciamento de objetos TableViewCell é feito automaticamente pela 
plataforma. 
Execute a aplicação e veja o resultado final. É eu sei… não ficou um aplicativo fantástico no 
estado da arte  (ainda) mas, podemos entender o ​core ​de como funciona uma tableView.  
Em resumo, criamos uma view, conectamos com a view controller com esta view e com o 
model e por fim, fizemos um dataSource que construi células e atribui os dados em cada célula. 
 

 
 
PASSO #4: SECTIONS E ROWS NA UITABLEVIEW 
Agora que temos uma table construída, adicionar seções com cabeçalho fica muito mais fácil. 
 
A primeira coisa a se fazer é adicionar mais produtos. Neste caso, eu adicionei a seguinte 
estrutura de imagens e jogos. 
 
Console: PS4 
- Titulo: Resident Evil 7 
- God of War 3 
- Outlast 
Console: Wii 
- The Legend of Zelda Skyward 
- Super Mario Bros. 
Console: Xbox 360 
- Gears of War 
 
Segundo passo é modificar nossos arquivos .swift: 
 
1. Adicionar um array de game array ​[[Game]] ​no model 
2.  Adicionar um array de String com os Titulos da seção [ String ] no model 
3. Adicionar a variável: ​var titles = Games.getAllTitle() 
4. Método ​numberOfSections: ​retornar ​titles.count 
5. Método ​numberOfRowsInSection: ​retornar ​games[section].count 
6. Adicionar Método ​titleForHeaderInSection: ​retornar ​titles[section] 
7. Trocar ​games[indexPath.row] ​para 
games[indexPath.section][indexPath.row] 
 
Veja a seguir o código completo do Model e ViewController e o resultado final da nossa tabela 
com seções. 
//
// Games.swift
// gamestore
//
// Created by Tiago Aguiar on 3/29/17.
// Copyright © 2017 Code Spartan. All rights reserved.
//

import Foundation

struct Game {
var name: String
var desc: String
var imageName: String
}

struct Games {
static func getAllGames() -> [[Game]] {
return [
[
Game(name: "Resident Evil 7", desc: "horror game",
imageName: "resident_evil_7"),
Game(name: "God of War 3", desc: "adventure game",
imageName: "god_of_war_3"),
Game(name: "Outlast", desc: "horror game", imageName:
"outlast"),
],
[
Game(name: "The Legend of Zelda Skyward", desc:
"adventure game", imageName:
"legend_of_zelda_sky"),
Game(name: "Super Mario Bros.", desc: "adventure game",
imageName: "super_mario_bros")
],
[
Game(name: "Gears of War", desc: "action game",
imageName: "gears_of_war"),
]
]
}

static func getAllTitle() -> [String] {


return ["PS4", "Wii", "Xbox 360"]
}
}
//
// GameViewController.swift
// gamestore
//
// Created by Tiago Aguiar on 3/29/17.
// Copyright © 2017 Code Spartan. All rights reserved.
//

import UIKit

class GameViewController: UIViewController {

@IBOutlet weak var tableView: UITableView!

var games = Games.getAllGames()


var titles = Games.getAllTitle()

override func viewDidLoad() {


super.viewDidLoad()

tableView.dataSource = self
}

override func didReceiveMemoryWarning() {


super.didReceiveMemoryWarning()
}

extension GameViewController: UITableViewDataSource {

func numberOfSections(in tableView: UITableView) -> Int {


return titles.count
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {


return games[section].count
}

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {


return titles[section]
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {


let cell = tableView.dequeueReusableCell(withIdentifier: "GameCell")!

cell.textLabel?.text = games[indexPath.section][indexPath.row].name
cell.detailTextLabel?.text = games[indexPath.section][indexPath.row].desc
cell.imageView?.image = UIImage(named: games[indexPath.section][indexPath.row].imageName)

return cell
}

}
PASSO #5: CUSTOM UITABLEVIEWCELL - O PODER PARA 
CRIAR CÉLULAS DO JEITO QUE VOCÊ QUISER! 
Vamos entrar na parte mais divertida e benéfica da ​UITableView, ​criar suas próprias 
células e deixar a sua arte fluir pelo aplicativo. 
Aqui vamos aplicar um pouco mais de Design no aplicativo e fazer com que os nossos produtos 
(jogos digitais) tenha uma melhor apresentação.  
 
Este passo é simples, mas não é fácil. Logo, é de suma importância ter a total atenção nos 
próximos passos. 
 
Antes de mais nada, vamos mudar o estilo da nossa ​UITableViewCell ​para ​custom. 

 
Aumente o tamanho da célula na ​storyboard ​para começar o Design. 
Adicione uma ​ImageView ​com ​constraint ​para aplicar o ​AutoLayout.

Você terá ​constraints c​ om ​Top, Left = 0. Width, Height = 100​. 
Adicione mais 3 ​UILabel ​que servirá para mostrar o título do jogo, o tipo e a descrição. 

 
Você terá ​constraints ​com ​Top, Left, Right = 8 ​para cada ​UILabel.
Para que a imagem mantenha a proporção mesmo adicionadno uma ​constraints ​de 
largura e altura = 100, adicione o ​content mode ​para​ aspect fit.

Altere a fonte de ​UILabel​  das de acordo com sua preferência. 
 
Crie a classe ​GameCell ​da mesma forma que criou a primeira ViewController [ cmd + n ]. 
Você terá uma: ​class ​GameCell: UITableViewCell. 
 
Lembra que para nossas classes se conectarem com a view precisamos referênciá-las na 
storyboard e depois, adicionar os ​@IBOutlet?
 
Esse é o próximo passo. 

 

 
Ainda não temos o atributo type e desc definidos no nosso model. 
Altere a Struct Game. 
 
//
// Games.swift
// gamestore
//
// Created by Tiago Aguiar on 3/29/17.
// Copyright © 2017 Code Spartan. All rights reserved.
//

import Foundation

struct Game {
var name: String
var type: String
var imageName: String
var desc: String
}

struct Games {
static func getAllGames() -> [[Game]] {
return [
[
Game(name: "Resident Evil 7", type: "horror game", imageName: "resident_evil_7",
desc: "O título coloca o jogador na pele de Ethan Winters, que deve ir em
busca de sua namorada desaparecida – isso depois que ela própria enviou uma
misteriosa mensagem, após anos sem dar notícias. Ao chegar ao local, o
personagem precisa lidar com uma família um tanto estranha e ameaçadora."),
Game(name: "God of War 3", type: "adventure game", imageName: "god_of_war_3", desc:
"Quando God of War 3 foi anunciado em 2008 para PlayStation 3, muito se
falou sobre as principais inovações nas mecânicas. O God of War 2 apresentou
uma história fantástica, apesar da mesma jogabilidade do primeiro episódio
da saga."),
Game(name: "Outlast", type: "horror game", imageName: "outlast", desc: "Outlast foi
lançado este mês para PC, trazendo uma experiência de horror bem além da
concorrência. A equipe da Red Barrels, formada por profissionais
responsáveis por jogos como Prince of Persia: Sands of Time, Assassin’s
Creed e Splinter Cell, conseguiu atingir um nível impressionante de tensão
no game, mas isso não quer dizer que Outlast não possua falhas"),
],
[
Game(name: "The Legend of Zelda Skyward", type: "adventure game", imageName:
"legend_of_zelda_sky", desc: "E mais uma vez, a Nintendo nos presenteia com
um belíssimo jogo, digno de ser um “Zelda”, acessível para iniciantes,
indispensável para os fãs e com o acréscimo de elementos que, possivelmente,
definirão o futuro da série"),
Game(name: "Super Mario Bros.", type: "adventure game", imageName:
"super_mario_bros", desc: "Desde o lançamento do Nintendo 3DS os fãs aguardam
por um game do Mario com uma pegada mais “clássica”, lembrando os jogos mais
antigos da franquia. O game Super Mario 3D Land foi muito bom, mas tinha
pouco daquele Mario “2D” que a grande parte dos jogadores cresceu jogando, e
é com New Super Mario Bros")
],
[
Game(name: "Gears of War", type: "action game", imageName: "gears_of_war", desc:
"Muitos jogadores de todo o planeta procuram somente diversão em seus jogos,
não importando qual gênero ou estilo. Afinal, essa é a proposta principal de
todos os videogames: entreter. Muitos games de esporte, luta, ação ou tiro
conseguem facilmente prender os jogadores por horas em frente à televisão.
"),
]
]
}

static func getAllTitle() -> [String] {


return ["PS4", "Wii", "Xbox 360"]
}
}
Certo! Vamos adicionar os novos dados na ​UITableViewCell ​customizada que criamos. 
Neste momento, você já deve ter uma classe da célula, uma view na storyboard e IBOutlets 
conectados entre view e classe (código swift). 
 
Vamos alterar o método ​cellForRowAt ​para que ele fique assim… 
 
let cell = tableView.dequeueReusableCell(withIdentifier: "GameCell") as! GameCell 
cell.game = games[indexPath.section][indexPath.row]   
return cell 
 
E a partir de agora, a ​GameCell ​terá seu próprio método que atribui os valores do model. 
Esta é a forma elegante de se trabalhar com TableViewCell e dados vindo de um objeto model. 
 
Note também que fizemos um ​casting  ​do objeto ​UITableViewCell ​para​ GameCell. 
 
O novo método garante que quando um nova célula for solicitada, o método ​cellForRowAt  
atribua o objeto inteiro ao ​GameCell. 
 
var game: Game! { 
    didSet { 
        self.updateUI() 
    } 

 
Veja no código completo para entender melhor. 
//
// GameCell.swift
// gamestore
//
// Created by Tiago Aguiar on 4/1/17.
// Copyright © 2017 Code Spartan. All rights reserved.
//

import UIKit

class GameCell: UITableViewCell {

@IBOutlet weak var imgCover: UIImageView!


@IBOutlet weak var lblTitle: UILabel!
@IBOutlet weak var lblType: UILabel!
@IBOutlet weak var lblDesc: UILabel!

var game: Game! {


didSet {
self.updateUI()
}
}

fileprivate func updateUI() {


imgCover.image = UIImage(named: game.imageName)
lblTitle.text = game.name
lblType.text = game.type
lblDesc.text = game.desc
}

override func awakeFromNib() {


super.awakeFromNib()

override func setSelected(_ selected: Bool, animated: Bool) {


super.setSelected(selected, animated: animated)
}

}
Terminado o trabalho na ​GameCell, ​coloque a aplicação para executar e veja o resultado. 
 

 
 
Você está quase lá! Perceba que a descrição ficou cortada, isto é, tem apenas uma linha e o 
título do Zelda, por exemplo, ficou com reticências. Vamos corrigir isso. 
 
Na storyboard, selecione a última label e diminui o número de linhas para 0. 

 
Agora adicione uma ​constraint ​bottom nesta última label da mesma forma que fazemos em 
outros componentes. Nesse momento, você pode se deparar com alguns conflitos de 
constraint. ​Para resolvê-los, vamos alterar as prioridades das ​constraints. 
 
Altere as prioridades de acordo com a imagem abaixo sendo que: 
Label 1 ( title ) -> 
content hugging priority 
horizontal: 251 
vertical: 251 
content compression resistance priority 
horizontal: 750 
vertical: 750 
 
Label 2  ( type ) -> 
content hugging priority 
horizontal: 251 
vertical: 252 
content compression resistance priority 
horizontal: 750 
vertical: 750 
 
Label 3 ( desc ) -> 
content hugging priority 
horizontal: 251 
vertical: 252 
content compression resistance priority 
horizontal: 750 
vertical: 751 

 
Uma outra forma de corrigir os conflitos é solicitar ao próprio Xcode que defina as prioridade 
para você. Quando ocorre um erro de ​constraint ​o Xcode mostra uma pequena bola vermelha 
onde você pode clicar e solicitar a melhor opção pelo IDE. 
 
Corrigido a View, em tese, ele crescerá automaticamente porque agora não definimos um 
número de linhas maior que 0. 
 
Antes de executar você deve avisar que sua table view terá um ajuste dinamico no tamanho 
das linhas. Logo, adicione o seguinte código ao viewDidLoad. 
 
tableView.estimatedRowHeight = tableView.rowHeight 
tableView.rowHeight = UITableViewAutomaticDimension 
//
// GameViewController.swift
// gamestore
//
// Created by Tiago Aguiar on 3/29/17.
// Copyright © 2017 Code Spartan. All rights reserved.
//

import UIKit

class GameViewController: UIViewController {

@IBOutlet weak var tableView: UITableView!

var games = Games.getAllGames()


var titles = Games.getAllTitle()

override func viewDidLoad() {


super.viewDidLoad()

tableView.dataSource = self
tableView.estimatedRowHeight = tableView.rowHeight
tableView.rowHeight = UITableViewAutomaticDimension
}

override func didReceiveMemoryWarning() {


super.didReceiveMemoryWarning()
}

extension GameViewController: UITableViewDataSource {

func numberOfSections(in tableView: UITableView) -> Int {


return titles.count
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {


return games[section].count
}

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {


return titles[section]
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {


let cell = tableView.dequeueReusableCell(withIdentifier: "GameCell") as! GameCell

cell.game = games[indexPath.section][indexPath.row]

return cell
}

}
 

 
 
Legal! Agora só falta ajustar o título para caber na célula. 
Você pode corrigir isso alterando o atributo ​Autoshrink ​na label. 

 
Com esse parâmetro, você indica ao aplicativo para usar a fonte padrão, porém, se não for 
possível exibir o texto por completo, tente o valor minimo definido (​Minimum Font Size​). 
 
Alteramos para 9 e o resultado é o seguinte: 
 
Agora você pode criar views customizadas para a sua tableview. 
 
Nesse momento, você pode ter tido diversas dúvidas e até dificuldade. Mas isso é 
completamente normal. Crie outras tabelas, customize diferente, faça você as alterações 
necessárias para aprender mais. O que eu fiz aqui foi destrinchar do que uma tableview é capaz 
e como usar ela conectando Design e dados. Cabe a você otimizar e melhorar as suas 
habilidades como desenvolvedores iOS. 
 
Mas ainda não acabou! Quero te ensinar mais! 
 
Os próximos passos são ordenação e exclusão de registros na tabela. 
 
Vamos começar. 
 
 
 
 
 
PASSO #6: EXCLUSÃO DE CÉLULAS NA TABLEVIEW 

            
 
Há duas maneiras de excluir um registro em uma tabela. Arrastando o registro para o lado e 
clicando em Delete ou em Editar na ​toolbar​. 
 
Para adicionar o botão na ​toolbar​ você precisará usar uma variável chamada 
editButtonItem.

self​.​navigationItem​.​rightBarButtonItem​ = ​editButtonItem 

Adicione o pedaço de código acima no método ​viewDidLoad. 
 
Como não estamos utilizando uma ​UITableViewController ​precisamos indicar que 
nossa tableView agora será editável. O seguinte método deve estar na sua ​viewController. 
 
override​ ​func​ setEditing(​_​ editing: ​Bool​, animated: ​Bool​) { 
    ​super​.​setEditing​(editing, animated: animated) 
    ​self​.​tableView​.​setEditing​(editing, animated: animated) 

 
 
Na extension onde temos nosso ​DataSource, ​adicione o seguinte código: 
 
 
 
func​ tableView(​_​ tableView: ​UITableView​, commit editingStyle: 
UITableViewCellEditingStyle​, forRowAt indexPath: ​IndexPath​) { 
    ​if​ editingStyle == .​delete​ { 
        ​games​[indexPath.​section​].​remove​(at: indexPath.​row​) 
        tableView.​deleteRows​(at: [indexPath], with: .​automatic​) 
    } 

 
Este bloco de código irá ser executado quando houver uma ação na ​tableView​ como edição ou 
exclusão. Nesse caso, além de remover do objeto ​tableView​, também removemos do ​array 
games​ o registro. 

PASSO #7: REORDENAÇÃO DE CÉLULAS NA TABLEVIEW 

Se você quiser reordenar os elementos na tabela, você precisará adicionar ao seu método 
viewDidLoad ​ um novo ​protocol​ conhecido como Delegate. 
 
Basta adicionar a seguinte linha de código e adicionar à extension a 
UITableViewDelegate 

tableView​.​delegate​ = ​self 
extension​ ​GameViewController​: ​UITableViewDataSource​, 
UITableViewDelegate​ { 

 
Feito isso, nossa tabela terá um ​observer​ responsável por escutar eventos na tabela. Agora, 
vamos indicar em quais células podem ocorrer o evento de ordenação ( ​canMoveRowAt ​). 
 
Como queremos reordernar todos os elementos em de cada seção, o retorno deste método 
será sempre ​true​. 
 
 
func​ tableView(​_​ tableView: ​UITableView​, canMoveRowAt indexPath: ​IndexPath​) -> ​Bool​ { 
        ​return​ ​true 

 
 
Outra coisa que faremos uma verificação é não deixar que uma célula de uma seção possa ser 
movida para dentro de outra seção, pois isso não faz sentido para este nosso aplicativo que lista 
jogos de acordo com o console específico. 
 
   
func​ tableView(​_​ tableView: ​UITableView​, targetIndexPathForMoveFromRowAt sourceIndexPath: 
IndexPath​, toProposedIndexPath proposedDestinationIndexPath: ​IndexPath​) -> ​IndexPath​ { 
    ​if​ sourceIndexPath.​section​ != proposedDestinationIndexPath.​section​ { 
        ​return​ sourceIndexPath 
    } ​else​ { 
        ​return​ proposedDestinationIndexPath 
    } 

   
 
Perceba que nesse método acima, sempre que um elemento sobrescreve outro elemento 
quando seguramos a célula com o touch e arrastamos ela para baixo por exemplo, nós 
verificamos se a seção é a mesma. Caso seja diferente, retornamos o mesmo indice (indexPath) 
para evitar a reordenação neste caso. 
 
 
func​ tableView(​_​ tableView: ​UITableView​, moveRowAt sourceIndexPath: ​IndexPath​, to 
destinationIndexPath: ​IndexPath​) {  
    ​if​ sourceIndexPath != destinationIndexPath { 
        ​let​ game = ​games​[sourceIndexPath.​section​][sourceIndexPath.​row​]; 
   
       ​games​[sourceIndexPath.​section​].​remove​(at: sourceIndexPath.​row​) 
       ​games​[sourceIndexPath.​section​].​insert​(game, at: destinationIndexPath.​row​) 
       tableView.​moveRow​(at: sourceIndexPath, to: destinationIndexPath) 
       tableView.​reloadData​() 
    } 

   
Com a validação de seção ok, o método acima é executado e removemos tanto da tabela 
quanto do array o elemento e, colocamos ele na posição de destino. Ao final, daremos um 
reloadData na tabela para garantir que as células possam ser reconstruídas novamente. 
PASSO #8: STATIC CELL E UM DESAFIO PARA VOCÊ 
 
Você já é capaz de listar dados em qualquer aplicativo e ainda de uma forma elegante e 
customizada! 
 
A partir de agora quero propor um desafio para você. Dessa forma, poderá colocar em prática 
tudo o que já aprendeu até aqui, descobrir mais obstáculos e melhorar a suas habilidades como 
desenvolvedor iOS. 
 
Até esse momento, criamos uma lista de dados dinâmicos, que cresce e diminui de acordo com 
nossos arrays. Existe um outro tipo de célula conhecida como ​Static Cell ​que utilizamos criar 
telas de detalhes de um modelo de dados como, por exemplo, o nosso jogo digital em si. 
 
O desafio é: Criar uma TableViewController com uma Static Cell para mostrar a imagem e a 
descrição do produto ao clicar em cada item na TableView principal. 
 
Pra fazer isso, você precisará criar a view em si, controllers e o método prepareForSegue, para 
transportar o seu objeto Game entre as controllers. 
 
Para te ajudar, mas sem resolver o desafio, irei colocar as classes para que você possa ler o 
código e revisá-lo. É como se eu estivesse mostrando a resultado de uma conta matemática 
sem resolver o problema. ​:-) 
 
Dica 1: Main.storyboard 

 
 
 
GameViewController: 
 
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 
    let gameDetailVC = segue.destination as! GameDetailViewController 
    if let gameCell = sender as? GameCell { 
        gameDetailVC.game = gameCell.game 
    } 

 
 
 
//
// GameViewController.swift
// gamestore
//
// Created by Tiago Aguiar on 3/29/17.
// Copyright © 2017 Code Spartan. All rights reserved.
//

import UIKit

class GameViewController: UIViewController {

@IBOutlet weak var tableView: UITableView!

var games = Games.getAllGames()


var titles = Games.getAllTitle()

override func viewDidLoad() {


super.viewDidLoad()

self.navigationItem.rightBarButtonItem = editButtonItem

tableView.dataSource = self
tableView.delegate = self

tableView.estimatedRowHeight = tableView.rowHeight
tableView.rowHeight = UITableViewAutomaticDimension
}

override func setEditing(_ editing: Bool, animated: Bool) {


super.setEditing(editing, animated: animated)
self.tableView.setEditing(editing, animated: animated)
}

override func didReceiveMemoryWarning() {


super.didReceiveMemoryWarning()
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {


let gameDetailVC = segue.destination as! GameDetailViewController
if let gameCell = sender as? GameCell {
gameDetailVC.game = gameCell.game
}
}

extension GameViewController: UITableViewDataSource, UITableViewDelegate {

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
games[indexPath.section].remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .automatic)
}
}

func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {


return true
}

func tableView(_ tableView: UITableView, targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath, toProposedIndexPath


proposedDestinationIndexPath: IndexPath) -> IndexPath {
if sourceIndexPath.section != proposedDestinationIndexPath.section {
return sourceIndexPath
} else {
return proposedDestinationIndexPath
}
}

func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {

if sourceIndexPath != destinationIndexPath {
let game = games[sourceIndexPath.section][sourceIndexPath.row];

games[sourceIndexPath.section].remove(at: sourceIndexPath.row)
games[sourceIndexPath.section].insert(game, at: destinationIndexPath.row)
tableView.moveRow(at: sourceIndexPath, to: destinationIndexPath)
tableView.reloadData()
}
}

func numberOfSections(in tableView: UITableView) -> Int {


return titles.count
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {


return games[section].count
}

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {


return titles[section]
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {


let cell = tableView.dequeueReusableCell(withIdentifier: "GameCell") as! GameCell

cell.game = games[indexPath.section][indexPath.row]

return cell
}

}
//
// GameDetailViewControllerTableViewController.swift
// gamestore
//
// Created by Tiago Aguiar on 4/8/17.
// Copyright © 2017 Code Spartan. All rights reserved.
//

import UIKit

class GameDetailViewController: UITableViewController {

@IBOutlet weak var gameImageView: UIImageView!


@IBOutlet weak var descLabel: UILabel!

var game: Game?

override func viewDidLoad() {


super.viewDidLoad()

tableView.estimatedRowHeight = 44.0

if let game = game {


title = game.name
gameImageView.image = UIImage(named: game.imageName)
descLabel.text = game.desc
}
}

override func didReceiveMemoryWarning() {


super.didReceiveMemoryWarning()
}

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0 {
return 250.0
}
return UITableViewAutomaticDimension
}

}
CONSIDERAÇÕES FINAIS 
 
Agora você sabe que 20% dos seus esforços deve ser direcionados para o TableView porque 
ela é responsável por estar em 80% do aplicativo. Logo, criar aplicativos iOS é bem mais 
simples do que você imaginava. 
 
Você só precisa dominar a storyboard e conectar views e controllers usando os métodos que a 
própria Apple disponibiliza em suas classes. 
 
Seja o facebook, o Instagram, Whatsapp, Spotify ou Twitter, você poderá criar algo similar e até 
melhores que estes, basta entender os principios por trás desses grandes apps e você verá que 
eles são realmente simples. 
 
 
 
ACESSE O CÓDIGO FONTE COMPLETO 
https://www.dropbox.com/s/iyra73hefcl6guj/gamestore.zip?dl=0 
 
 
ACESSE MEU CANAL NO YOUTUBE 
https://goo.gl/PBDFKU 
 
 
ACESSE MINHA PÁGINA NO FACEBOOK 
https://goo.gl/o5QMlp 
 
 
ACESSE MEU WEBSITE OFICIAL 
https://goo.gl/iDlRqE 

Vous aimerez peut-être aussi