Tiago Aguiar

Classes Vs. Struct: Qual a diferença em Swift?

avatar
Preview Image

Qual a diferença entre Classes e Struct em Swift? Essa é a principal dúvida que desenvolvedores iOS tem quando começam a estudar a linguagem de programação Swift.

Então se você quer aprender mais sobre swift, continue lendo este artigo para aprender:

  • A principal diferença entre Classes e Struct
  • Quando eu devo utilizar Classes e quando devo utilizar Struct
  • Uma introdução a programação orientada a protocols e porque isso é importante.

Só pra dar um breve “spoiler”, Struct é um poderoso recurso da linguagem de programação Swift e pode deixar seu código mais rápido, seguro, flexível e reutilizável.

Vamos ver em mais detalhes!

Classes Vs. Struct: O que eles tem em comum

Primeiramente vamos dar uma olhada o que as Classes e as Structs (Structures) tem em comum. Basicamente eles podem:

  • Definir propriedades para guardar valores
  • Definir funções para comportamento
  • Definir subscripts para ter acesso a valores dentro de elementos como collection e outros tipos de sequences.
  • Definir construtores para inicializar estados de variáveis
  • Ser extendidas com a palavra reservada extension.
  • Podem implementar protocols para ter suporte a programação orientada a protocols

Agora vamos ver algumas coisas que Classes podem fazer e Structs não.

  • Classes possuem o conceito de herança. Logo, é possível extender uma UIButton porque ela é uma classe.
  • Classes podem definir “destrutor” deinit() que são funções chamadas antes da instância ser desalocada.
  • Classes podem ter uma ou mais referências para uma única instância (importante!)

A Principal Diferença Entre Classes e Structs

Agora que você já sabe o que estes dois elementos tem em comum e o que classes podem fazer e structs não pode, vamos ver a principal diferença entre classes e structs.

Classes são reference types. Isto é, seus valores são passados por referência para o mesmo espaço de memória. Já Structs são value types. Ou seja, seus valores são copiados para um novo espaço de memória.

Isto significa que, se você passar uma instância de class para uma variável X, aquela variável X será um “link” (chamado de referência) entre o objeto original e a nova variável. Logo, se você fizer qualquer alteração na variável X, o objeto original sofrerá essa alteração. Ao invés dele copiar toda a estrutura de dados para um novo espaço de memória, ele apenas cria uma referência para o espaço de memória atual. Veja o exemplo:

1
2
3
4
5
6
7
8
9
10
11
12
class GoogleSheet {
	var author: String
	init(author: String) {
		self.author = author
	}
}

let file = GoogleSheet(author: "Fulano")
let fileChanged = file
fileChanged.author = "Ciclano"

print(file.author) // Mudou! "Ciclano"

Quanto a Struct, ela não cria uma referência para o objeto original em uma variável. Ela faz uma cópia da estrutura do objeto original em um novo espaço de memória (value type). Logo, se você alterar os dados da variável X, o objeto original não sofrerá nenhuma alteração.

Veja o exemplo abaixo:

1
2
3
4
5
6
7
8
9
struct Excel {
	var author: String
}

let fileExcel = Excel(author: "Fulano")
var fileExcelChanged = fileExcel
fileExcelChanged.author = "Ciclano"

print(fileExcel.author) // Ainda! "Fulano"

Uma analogia simples para entender essa diferença entre struct e class é você imaginar que Classes são como arquivos de planilhas que ficam no Google Sheet. Se tiver duas pessoas (variáveis) apontando para o mesmo arquivo, aquele que alterar por último será o responsável pela última versão (objeto original). Ou seja, se você e eu estamos alterando um arquivo (class), como nós dois temos acesso (reference) a este arquivo, alteramos o estado dele.

Já a struct é semelhante a uma planilha Excel no computador, se eu alterar o arquivo e compartilhar com você pelo pen drive o arquivo será copiado para o seu computador (value type). Logo, o que você alterar não afetará o outro.

Em curtas palavras: value types são passadas copiando o valor e reference types são passadas criando uma referência.

Onde Usar Structs?

É recomendado utilizar structs quando você:

  • Precisar de estrutura de dados pequenas: Como objetos de base de dados que você quer apenas passar no código como User, Product, etc.
  • Precisar utilizar ambientes multi-thread: Para instâncias com conexões de banco de dados abertas em diferentes threads por exemplo, é muito mais seguro usar struct. Visto que elas são copiadas de uma thread para outra, evitando assim, um deadlock ou coisa do tipo.
  • Não precisar de herança: Desta forma você garante que ninguém herda atributos e métodos e também garante velocidade porque haverá apenas um único espaço de memória não compartilhado e sem dados “extras” de subclasses por exemplo.
  • Quiser fazer uso da programação orientada a protocol: Faz mais sentido usar structs.

As structs não precisam definir um construtor, eles já estão lá indiretamente.

Onde Usar Classes?

Ok, já que structs são tão eficientes quando devo utilizar classes então? Como mencionei anteriormente, classes possuem funcionalidades que structs não possue como:

  • Herança: Este recurso não pode ser feito em structs como MyViewController: UIViewController ou Car: Vehicle. Mesmo assim, structs ainda permite implementar protocols.
  • Destructor: Se você precisar livrar recursos quando um objeto perde a vida, com classes você pode fazer isso em deinit().

Em algumas situações vale muito mais a pena ter classes para herança por exemplo do que structs como no caso do Design Pattern Decorator.

Um outro exemplo são ViewController e objetos do tipo Window. Não faz sentido termos uma cópia (struct) de ViewController ou Window porque precisamos somente de uma única instância ativa na aplicação.

Percebe que a escolha de classes e struct está muito mais relacionado a escolha de variáveis do tipo referência e variáveis do tipo valor. Se fizer sentido pra você copiar um valor, escolha struct, se fizer sentido ter uma referência para um valor (e não copiá-lo), então a melhor escolha será as classes.

Usando Struct com Programação Orientada a Protocols

Structs são ótimas quando usado junto à POP (Protocol Oriented Programming). Para aqueles que não conhecem, uma programação orientada a protocols possuem dois princípios fundamentais:

  1. Structs podem assinar um protocol assim como classes
  2. Protocols podem ser extendidos

Veja alguns problemas que protocols podem resolver:

Se você tiver uma classe chamada Guitar Les Paul e Battery. Ao invés de criar uma hierarquia como Guitar Les Paul -> Guitar -> Instruments e Battery -> Instruments, você pode criar um protocol Playable que pode tornar sua classe Guitar Les Paul em um instrumento “tocável”.

Como todo protocol precisa ser implementado por uma “classe” com regras a serem seguidas. As structs precisariam disso. Porém, através de extensions você pode fornecer uma implementação padrão a um protocol.

O que significa que você pode usar o conceito de decorator sem implementar um protocol em uma classe!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Define the protocol
protocol Playable {
	func play()
}

// Extend the protocol with a default implementation
extension Playable {
	func play() {
		print("Playing the instruments !!!")
	}
}

struct GuitarLesPaul: Playable {
	var chords = 6
}

var guitar = GuitarLesPaul()
guitar.play()
// Output: Playing the instruments !!!

Considerações Finais

Esta é a diferença entre Struct Vs. Classes.

Neste artigo você aprendeu:

  • A principal diferença e similaridades entre classes e structs
  • Quando devo usar Classe e Struct
  • Como Protocols e Structs podem trabalhar juntos em Programação Orientada a Protocolos - Protocol Oriented Programming

Compartilhe esse artigo se ele te ajudou de alguma forma ;)

Maravilha! Em breve você receberá conteúdos exclusivos por e-mail. Continue lendo os artigos para aprender mais sobre programação.