Código mais seguro em Swift com controles de acesso

Rocketseat

Navegação Rápida:
Faaala, dev? Tudo pronto para dar mais um passo na sua jornada com Swift?
Sabe quando você está construindo algo incrível, mas começa a sentir que o código está virando uma daquelas gavetas de "coisas aleatórias"? Onde qualquer parte do seu app pode mexer em tudo, e você fica com aquele medinho de que uma mudança aqui quebre algo totalmente inesperado lá na frente? Pois é, organização e segurança são chaves!
É aí que entram os controles de acesso em Swift! Eles são como os seguranças superinteligentes do seu código, definindo quem pode entrar e o que pode fazer em cada parte do seu projeto. Parece complicado? Que nada!
Neste artigo direto ao ponto, vamos desvendar juntos esses "guardiões" do Swift. Você vai entender exatamente o que são, por que são essenciais e como usar cada nível de acesso para deixar seu código mais limpo, seguro e profissional.
Bora desvendar esses segredos e dar um boost nos seus projetos Swift?
O que são controles de acesso?
Imagine seu código como uma casa inteligente. Você não deixaria a porta da rua escancarada, nem daria a chave do seu cofre pessoal para qualquer visitante, certo? Controles de acesso funcionam de forma parecida: eles restringem o acesso a partes do seu código (classes, structs, métodos, propriedades) com base em onde esse código está sendo chamado.
É sobre visibilidade e permissão.
Por que isso é tão importante?
- Segurança: impede que partes do seu código sejam usadas ou modificadas de forma inadequada, evitando bugs e comportamentos inesperados.
- Organização: ajuda a definir interfaces claras. Você expõe apenas o necessário, escondendo a complexidade interna. Fica mais fácil entender como usar um componente sem precisar saber todos os seus segredos.
- Trabalho em equipe: em times, define limites claros. Cada um sabe o que pode usar do código do outro sem medo de quebrar a implementação interna.
- Manutenção: facilita na hora de refatorar ou melhorar uma parte do código. Se os detalhes internos estão escondidos, você pode mudá-los sem afetar quem usa a parte "pública" do seu componente.
Entendido o porquê? Agora, vamos conhecer os guardiões.
Os 5 guardiões do código Swift
Swift nos oferece cinco níveis de controle de acesso, do mais restrito ao mais aberto. Vamos conhecer cada um:
private
- Acesso: só pode ser acessado de dentro da mesma definição (classe, struct, enum) e de extensões dessa definição que estejam no mesmo arquivo.
- Uso típico: para detalhes de implementação super internos, variáveis auxiliares que só fazem sentido dentro daquele bloco específico. É o seu diário trancado na gaveta.
struct CofreDoMayk { private var combinacaoSecreta: String = "123456" // Só o Mayk aqui dentro sabe func tentarAbrir(senha: String) -> Bool { // Pode acessar combinacaoSecreta aqui dentro return senha == self.combinacaoSecreta } } let meuCofre = CofreDoMayk() // print(meuCofre.combinacaoSecreta) // ERRO! Não pode acessar de fora. print(meuCofre.tentarAbrir(senha: "123456")) // OK, usa o método público
fileprivate
- Acesso: pode ser acessado de qualquer lugar dentro do mesmo arquivo fonte (
.swift
).
- Uso típico: quando uma funcionalidade precisa ser compartilhada entre diferentes classes ou structs, mas apenas dentro daquele arquivo específico. É uma conversa na sala de estar, só a família (o arquivo) ouve.
// Arquivo: UtilsDaIsabela.swift fileprivate func logInternoDoArquivo(mensagem: String) { print("[LOG ISABELA]: \(mensagem)") } class GerenciadorDeLogin { func logarUsuario(nome: String) { // ... lógica de login ... logInternoDoArquivo(mensagem: "Tentativa de login para: \(nome)") // OK, mesmo arquivo } } struct ValidadorDeSenha { func validar(senha: String) -> Bool { logInternoDoArquivo(mensagem: "Validando senha...") // OK, mesmo arquivo return senha.count > 6 } } // Em outro arquivo .swift, a função logInternoDoArquivo seria inacessível.
internal
- Acesso: pode ser acessado de qualquer lugar dentro do mesmo módulo (seu aplicativo ou framework).
- Uso típico: a grande maioria do código do seu aplicativo. Classes, funções e propriedades que precisam interagir entre si dentro do seu projeto, mas não precisam ser expostas para fora (caso você estivesse criando um framework).
// Não precisa escrever 'internal', é o padrão! class PerfilUsuario { var nome: String // internal por padrão var email: String // internal por padrão init(nome: String, email: String) { self.nome = nome self.email = email } func exibirBoasVindas() { // internal por padrão print("Boas-vindas, \(nome)!") } } // Em qualquer outro arquivo DENTRO do mesmo app/módulo: let perfilDaFernanda = PerfilUsuario(nome: "Fernanda", email: "fernanda@rocketseat.team") perfilDaFernanda.exibirBoasVindas() // OK print(perfilDaFernanda.nome) // OK
Este é o nível padrão! Se você não escrever nada (
private
, public
, etc.), o Swift assume que é internal
.public
- Acesso: pode ser acessado de qualquer lugar, inclusive de fora do módulo (por exemplo, se outro app importar seu framework).
- Uso típico: para definir a interface pública de um framework ou biblioteca.
// Em um Framework "ComponentesDoRodrigo.framework" public class BotaoCustomizado { public var titulo: String = "Clique Aqui" public init() {} // O inicializador precisa ser public também! public func acaoDoClique() { print("Botão clicado!") } } // Em um App que importa "ComponentesDoRodrigo.framework": // let meuBotao = BotaoCustomizado() // OK // meuBotao.titulo = "Meu Botão" // OK // meuBotao.acaoDoClique() // OK // class MeuBotaoEspecial : BotaoCustomizado {} // ERRO! Não pode subclassificar public fora do módulo.
Entidades
public
não podem ser subclassificadas (para classes) ou sobrescritas (para métodos) fora do módulo onde foram definidas. Pense como uma API: você pode usar, mas não pode alterar a estrutura fundamental dela por fora.open
- Acesso: o mais permissivo. Pode ser acessado de qualquer lugar, dentro ou fora do módulo.
- Uso típico: usado principalmente em frameworks que são projetados para serem extensíveis por quem os utiliza. Pense em classes base que outros devs podem querer herdar e customizar. Se você está apenas desenvolvendo seu app e não um framework, provavelmente nunca vai precisar usar
open
// Em um Framework "FrameworkBaseDoDiego.framework" open class ViewControllerBase { open var nomeDaTela: String = "Tela Genérica" open func viewDidAppear() { // Método aberto para ser sobrescrito print("\(nomeDaTela) apareceu!") } } // Em um App que importa "FrameworkBaseDoDiego.framework": class MinhaTelaPrincipal : ViewControllerBase { // OK! Pode subclassificar open. override func viewDidAppear() { // OK! Pode sobrescrever open. self.nomeDaTela = "Tela Principal do App" super.viewDidAppear() // Chama a implementação original print("Lógica adicional da minha tela!") } }
Classes
open
podem ser subclassificadas fora do módulo, e métodos open
podem ser sobrescritos fora do módulo.Ufa! Esses são os 5 níveis. Parece muito, mas a prática leva à perfeição!
Colocando em prática: gerenciando tarefas
Vamos ver um exemplo mais integrado, usando diferentes níveis para gerenciar tarefas:
// Arquivo: TarefaManager.swift // Função auxiliar só para este arquivo fileprivate func registrarLog(id: UUID, acao: String) { print("[\(Date())] Tarefa \(id): \(acao)") } public struct Tarefa { // Pública: pode ser usada em qualquer lugar do app public let id: UUID // Pública e imutável: todos veem, ninguém muda public var descricao: String // Pública e mutável: descrição pode ser editada public var concluida: Bool = false // Pública: status pode ser alterado internal let projetoAssociado: String // Interna: só código do módulo sabe o projeto private var notasSecretas: String = "" // Privada: só a struct Tarefa manipula // Inicializador público public init(descricao: String, projeto: String) { self.id = UUID() self.descricao = descricao self.projetoAssociado = projeto // Definido na criação registrarLog(id: self.id, acao: "Criada no projeto '\(projeto)' por Laís") // Usa func fileprivate } // Método público para marcar como concluída public mutating func marcarConcluida() { self.concluida = true registrarLog(id: self.id, acao: "Marcada como concluída") limparNotasSecretas() // Chama método privado } // Método público para adicionar notas (que ficam privadas) public mutating func adicionarNotaSecreta(_ nota: String) { self.notasSecretas += "\(nota)\n" registrarLog(id: self.id, acao: "Nota secreta adicionada") } // Método privado para limpar notas ao concluir private mutating func limparNotasSecretas() { self.notasSecretas = "" print("Notas secretas da tarefa \(id) limpas.") } } // Classe interna para gerenciar a lista de tarefas internal class GerenciadorDeTarefas { internal var tarefas: [Tarefa] = [] internal func adicionar(_ tarefa: Tarefa) { self.tarefas.append(tarefa) print("Gerenciador: Tarefa \(tarefa.id) adicionada.") // Poderia acessar tarefa.projetoAssociado aqui, pois é internal } // ... outros métodos internos para buscar, remover tarefas, etc. }
Analisando as escolhas
Tarefa
(struct):public
porque queremos criar e usar tarefas em várias partes do nosso app (ex: na UI, na lógica de negócios).
id
,descricao
,concluida
:public
porque são informações essenciais que outras partes do app precisam ler e, em alguns casos, modificar (descricao
,concluida
).id
élet
(constante) para garantir unicidade após a criação.
projetoAssociado
:internal
talvez porque a associação com um projeto seja uma lógica gerenciada apenas dentro deste módulo de gerenciamento, não exposta diretamente para a UI, por exemplo.
notasSecretas
:private
porque são detalhes internos da tarefa. A struct oferece um métodopublic
(adicionarNotaSecreta
) para interagir com elas de forma controlada. Ninguém de fora pode ler ou limpar as notas diretamente.
registrarLog
(func):fileprivate
porque é uma função auxiliar usada apenas pelas entidades (Tarefa
,GerenciadorDeTarefas
) definidas neste arquivoTarefaManager.swift
.
limparNotasSecretas
(método):private
pois é uma ação interna daTarefa
, chamada apenas pelo métodomarcarConcluida
.
GerenciadorDeTarefas
(class):internal
(padrão) porque toda a lógica de gerenciamento da lista de tarefas acontece dentro deste módulo. A UI, por exemplo, interagiria com ele, mas ele não é feito para ser usado por outro módulo/framework.
Viu como cada nível tem seu propósito para criar um sistema mais organizado e seguro?
Regra de ouro: qual nível escolher?
Na dúvida, siga o princípio do menor privilégio:
- Comece sempre com
private
. É o mais seguro.
- Se precisar acessar de outra função ou classe no mesmo arquivo, mude para
fileprivate
.
- Se precisar acessar de outros arquivos dentro do seu app/módulo, use
internal
(ou simplesmente não coloque nada, já que é o padrão).
- Só use
public
ouopen
se você estiver criando um framework ou biblioteca que será usado por outros módulos ou apps, e você precisa definir uma interface externa clara.
Para a vasta maioria do código que você escreverá para seus aplicativos iOS,internal
,fileprivate
eprivate
serão seus melhores amigos!
E no universo iOS?
Dominar os controles de acesso é FUNDAMENTAL no desenvolvimento iOS! Por quê?
- Arquitetura limpa (MVVM, MVC, VIPER...): ajuda a separar as responsabilidades. Sua View não deve acessar detalhes privados do seu ViewModel ou Service. Controles de acesso ajudam a impor isso.
- Testabilidade: componentes com interfaces bem definidas (graças aos controles de acesso) são mais fáceis de testar isoladamente.
- Reutilização: facilita criar componentes reutilizáveis e seguros dentro do seu próprio app.
- Menos bugs: evita que uma tela altere um estado interno de outra parte do app sem querer, causando comportamentos bizarros.
O código mais robusto, mais fácil de manter e menos propenso a quebrar. Tudo o que a gente quer!
Conclusão
Parabéns! Você desvendou os segredos dos controles de acesso em Swift! Agora você sabe que
private
, fileprivate
, internal
, public
e open
não são só palavras bonitas, mas ferramentas poderosas para:- Proteger seu código contra usos indevidos.
- Organizar melhor seus projetos.
- Facilitar a colaboração e a manutenção.
Dominar esses fundamentos do Swift é o primeiro passo para criar aplicativos iOS incríveis que impactam o mundo. É a base para construir interfaces fluidas, lógicas de negócio sólidas e experiências que encantam os usuários.
Se você quer acelerar sua jornada, ir do zero à App Store dominando não só Swift em profundidade, mas também Xcode, arquiteturas como MVVM, integração com back-end e todos os segredos para publicar seu app, a Formação iOS com Swift da Rocketseat foi feita sob medida para você! Lá, você terá um guia completo, passo a passo, para se tornar um desenvolvedor iOS de destaque no mercado.
Nunca pare de estudar e codar! O universo da programação é vasto e cheio de possibilidades. Continue explorando, construindo e, claro, controlando o acesso ao seu código como um mestre!
Artigos_
Explore conteúdos relacionados
Descubra mais artigos que complementam seu aprendizado e expandem seu conhecimento.