Class é um tipo por referência (reference type) na linguagem Swift, cujas instâncias são passadas por referência em vez de copiadas na atribuição. Ao contrário das structs, as classes suportam herança, desinicialização e contagem automática de referências ARC para gerenciamento de memória. De acordo com o Swift Programming Language Guide, 2026, class é necessária para trabalhar com os frameworks de UI da Apple (UIKit, AppKit) e implementar padrões que exigem identidade compartilhada do objeto. A escolha entre class e struct é uma das decisões arquitetônicas fundamentais em Swift.
Pontos-chave
Class — um tipo composto por referência em Swift que agrupa propriedades e métodos em uma única entidade com suporte a herança e despacho dinâmico. Ao contrário de struct, uma instância de classe é criada no heap, e uma variável armazena uma referência a esta instância, não os dados em si.
Quando você atribui uma variável de classe a outra variável, ambas referenciam o mesmo objeto na memória. Alterações através de uma referência são visíveis através da outra — esta é uma propriedade fundamental dos tipos por referência, usada em padrões de delegação, observação e estado compartilhado.
De acordo com a Documentação da Apple Swift, as classes são a única maneira de trabalhar com UIKit e AppKit, onde todos os componentes de UI herdam de UIView e UIViewController. Além disso, as classes são necessárias para implementar padrões que exigem identidade de objeto (duas referências para um objeto) e ciclo de vida controlado.
A semântica de tipo por referência — a propriedade-chave das classes. Ao atribuir uma classe a uma nova variável, o Swift copia a referência, não os dados. Todas as variáveis que referenciam a mesma instância veem seu estado atual e podem modificá-lo. Este comportamento difere fundamentalmente dos tipos por valor, onde cada variável obtém uma cópia independente.
// Exemplo de semântica de tipo por referência
class User {
var name: String
init(name: String) { self.name = name }
}
let user1 = User(name: "Alice")
let user2 = user1 // user2 — mesma referência
user2.name = "Bob"
print(user1.name) // "Bob" — alterado via user2!
// Verificação de identidade com o operador ===
print(user1 === user2) // true — mesmo objeto
Os operadores === (identidade) e !== verificam se duas variáveis referenciam a mesma instância de classe. Isso difere de == (igualdade), que compara valores de propriedades. O operador === não está disponível para struct — tipos por valor não têm identidade.
Herança — um mecanismo pelo qual uma classe pode adotar as propriedades e métodos de uma classe pai. Em Swift, uma classe só pode herdar de um pai (herança única), mas pode implementar múltiplos protocolos. A palavra-chave override permite sobrescrever um método ou propriedade herdados.
Qualquer classe que não herde de outra classe automaticamente se torna base (não confundir com NSObject). Uma subclasse especifica o pai com dois pontos após seu nome. Se uma subclasse sobrescreve um método do pai, ela deve chamar super.método() para preservar o comportamento do pai — este é um requisito do compilador.
A palavra-chave final antes de class impede a herança. O compilador pode otimizar chamadas de métodos de uma classe final através de despacho estático, melhorando o desempenho. Use final para classes não destinadas à extensão — documenta sua intenção e acelera o código.
// Exemplo de herança de classes em Swift
class Vehicle {
var speed: Double = 0
func description() -> String {
"Speed: \(speed) km/h"
}
}
// Car herda de Vehicle
class Car: Vehicle {
var brand: String = "Unknown"
override func description() -> String {
"\(brand) - \(speed) km/h"
}
}
// Classe final — impede herança
final class ElectricCar: Car {
var batteryLevel: Double = 100
}
let tesla = ElectricCar()
tesla.brand = "Tesla"
tesla.speed = 120
print(tesla.description()) // "Tesla - 120.0 km/h"
A herança é um mecanismo poderoso, mas responsável. Hierarquias profundas (mais de 5 níveis) complicam a manutenção e os testes. Para reutilização funcional sem herança, use protocolos com extension e programação orientada a protocolos — uma abordagem que a Apple promove como alternativa a hierarquias profundas de classes.
Swift usa ARC (Contagem Automática de Referências) para gerenciamento de memória de classes. Cada instância de classe tem um contador de referências fortes. Quando uma nova referência forte é criada, o contador aumenta; quando destruída, diminui. Quando o contador chega a zero, a memória é liberada.
Deinit — método chamado automaticamente antes da liberação de uma instância de classe. Libera recursos: fecha arquivos, cancela inscrições de notificações, para temporizadores. Deinit está disponível apenas para classes — structs e enums não o possuem.
Para prevenir ciclos de referências fortes (retain cycles), Swift fornece referências weak e unowned. Weak é uma referência opcional que automaticamente se torna nil quando o objeto é liberado. Unowned não é opcional, mas referencia um objeto que tem garantia de viver mais que o contexto atual. Um ciclo de retenção típico ocorre em um relacionamento pai-filho: o filho mantém uma referência forte ao pai.
// Exemplo de ARC e referência fraca
class Parent {
var name: String
var child: Child?
init(name: String) { self.name = name }
deinit { print("\(name) desalocado") }
}
class Child {
var name: String
weak var parent: Parent? // weak previne ciclo de retenção
init(name: String) { self.name = name }
deinit { print("\(name) desalocado") }
}
var parent: Parent? = Parent(name: "Anna")
parent?.child = Child(name: "Mia")
parent?.child?.parent = parent
parent = nil // Ambos os objetos desalocados!
// Sem weak criaria um ciclo de retenção
Sempre use weak para referências de um objeto filho ao pai e para listas de captura em closures. Use unowned apenas quando tiver certeza de que o objeto sobreviverá ao contexto atual — o uso incorreto de unowned pode causar um crash ao acessar memória liberada.
A escolha entre class e struct é uma decisão arquitetônica que afeta desempenho, segurança em threads e design de API. Considere a tabela de diferenças-chave para tomar a decisão correta em cada caso.
| Característica | class | struct |
|---|---|---|
| Tipo | Tipo por referência | Tipo por valor (cópia) |
| Memória | Heap + ARC | Pilha / inlined |
| Herança | Suporta (pai único) | Não suporta |
| Deinit | Disponível | Não disponível |
| Identidade (===) | Suporta | Não suporta |
| Mutating | Não necessário (sempre mutating) | Apenas com mutating |
| Init memberwise | Não gerado | Gerado automaticamente |
| Segurança em threads | Não garantida (estado compartilhado) | Garantida (cópia) |
Use classes quando precisar de identidade compartilhada (várias partes do código trabalhando com um objeto), herança ou interação com Objective-C runtime. Para todo o resto, structs são preferíveis — são mais rápidas, mais seguras em código multithread e não exigem gerenciamento de memória.
Apesar da recomendação da Apple de usar struct por padrão, as classes são necessárias em vários cenários específicos. Vamos examinar cada um com exemplos práticos.
Todos os componentes de UI no iOS e macOS são classes que herdam de UIView (iOS) ou NSView (macOS). Você não pode substituir UIViewController por uma struct — ele requer herança e deinit para liberar recursos. Ao trabalhar com UIKit, use classes para controladores, visualizações e seus delegados.
O padrão Singleton (uma instância de classe para toda a aplicação) requer semântica de referência. Gerenciadores: NetworkManager, SettingsManager, AnalyticsService — geralmente são implementados como classes com uma propriedade static compartilhada. Structs não são adequadas porque cada cópia seria uma instância independente.
Quando um objeto deve ser a única fonte de verdade e é passado entre módulos por referência — use class. Isso se aplica ao gerenciamento de estado, onde alterar um objeto em um lugar deve ser visível em todos os componentes dependentes. Para ObservableObject no SwiftUI, as classes são obrigatórias.
// ObservableObject — class necessária para SwiftUI
import SwiftUI
class AppViewModel: ObservableObject {
@Published var isLoggedIn: Bool = false
@Published var username: String = ""
func login(user: String) {
isLoggedIn = true
username = user
}
}
// Uso em uma View do SwiftUI
struct ContentView: View {
@StateObject var viewModel = AppViewModel()
var body: some View {
Text(viewModel.isLoggedIn ? "Bem-vindo" : "Entrar")
}
}
Regra: se um objeto deve ter identidade (duas referências -> um objeto), ser uma instância única ou trabalhar com UIKit/Objective-C — escolha class. Se um objeto simplesmente contém dados — escolha struct.
Perguntas frequentes
Class é um tipo por referência em Swift que suporta herança, desinicialização e ARC para gerenciamento de memória. Instâncias de classe são armazenadas no heap e variáveis contêm uma referência ao objeto, não sua cópia.
Class — tipo por referência (passado por referência), suporta herança e deinit. Struct — tipo por valor (copiado), não suporta herança, mas implementa protocolos e obtém init memberwise automaticamente. Swift recomenda struct como tipo padrão.
ARC (Contagem Automática de Referências) — um mecanismo de gerenciamento de memória para classes Swift. Cada instância tem um contador de referências fortes. Quando o contador chega a zero, a memória é liberada. Referências weak e unowned previnem retain cycles entre objetos.
Deinit — um método de classe chamado automaticamente antes da liberação de sua memória. Usado para fechar arquivos, cancelar inscrições de notificações e outras operações de limpeza. Deinit está disponível apenas em classes — structs não o possuem.
Use class para componentes de UI UIKit/AppKit, singleton, ObservableObject no SwiftUI, objetos com identidade compartilhada (delegate, observer) e ao trabalhar com Objective-C runtime. Para modelos de dados, DTOs e configurações, struct é preferível.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também