Swift: Entrada, Saída e Depuração no Swift

Escrever código é apenas metade do trabalho. Esta lição ensina como usar print, asserções e pontos de interrupção para encontrar e corrigir erros no seu código.

1. O Que Você Vai Aprender


2. Uma História Real: Um Iniciante Autodidata

(1) O Problema: Código Logicamente Correto, Resultados Errados

Mike é um iniciante autodidata em Swift trabalhando em um programa para calcular a nota média:

SWIFT
let scores = [85, 92, 78, 90, 88]
var total = 0
for i in 0...5 {
    total += scores[i]
}
let average = total / 5
print("Average: \(average)")

O programa travou imediatamente. Mike não conseguia descobrir o porquê. Ele passou 30 minutos pesquisando online, tentando várias correções. Cada modificação exigia reexecutar, mas ele ainda não conseguia identificar o problema.

(2) A Solução: Depuração Baseada em Print

Um amigo sugeriu usar print para exibir variáveis intermediárias e localizar o problema:

SWIFT
let scores = [85, 92, 78, 90, 88]
print("Array length: \(scores.count)")     // Output: 5
var total = 0
for i in 0..<scores.count {               // Use count instead of hardcoding
    print("Processing index \(i): value = \(scores[i])")
    total += scores[i]
}
print("Total: \(total)")
let average = total / 5
print("Average: \(average)")

Saída:

TEXT 📖 Somente leitura
Array length: 5
Processing index 0: value = 85
Processing index 1: value = 92
Processing index 2: value = 78
Processing index 3: value = 90
Processing index 4: value = 88
Total: 433
Average: 86

Ao exibir variáveis intermediárias, Mike descobriu imediatamente que os índices do array são 0-4, mas ele havia usado 0...5 (que inclui o índice 5).

(3) O Resultado: Eficiência de Depuração Após Dominar o Print

Dimensão Antes (Adivinhando) Depois (Depuração com Print)
Tempo para localizar o problema 30+ minutos 1-2 minutos
Precisão da correção 50% (frequentemente errada) 95%
Compreensão do código "Não faço ideia do porquê travou" "Sei o estado em cada etapa"
Confiança para resolver novos problemas 3/10 8/10

3. Uso Avançado do Print

print é a ferramenta de depuração mais usada do Swift, mas seus parâmetros fazem mais do que apenas exibir um valor.

100%
graph TB
    A[Função print] --> B["items: Valores a exibir"]
    A --> C["separator: Delimitador"]
    A --> D["terminator: Caractere final"]
    A --> E["to: Destino da saída"]
    B --> F[Múltiplos valores separados por vírgulas]
    C --> G["Padrão: espaço"]
    C --> H["Personalizado: | ou , etc."]
    D --> I["Padrão: nova linha"]
    D --> J["Personalizado: string vazia"]
Parâmetro Tipo Padrão Finalidade
items Any... Obrigatório Conteúdo a ser exibido
separator String " " Separador entre múltiplos itens
terminator String "\n" Caractere de nova linha ao final
to TextOutputStream nil Destino da saída (padrão: console)

(1) separator e terminator

SWIFT
// Default: space-separated, newline-terminated
print("Hello", "Swift", "World")
// Hello Swift World
// Custom separator
print("Hello", "Swift", "World", separator: ", ")
// Hello, Swift, World
// Custom terminator (no newline)
print("Loading", terminator: "...")
print("Done")
// Loading...Done
// Combined usage
print("A", "B", "C", separator: " | ", terminator: ".\n")
// A | B | C.

(2) debugPrint e dump

debugPrint exibe informações de depuração (com aspas e informações de tipo); dump exibe estruturas detalhadas:

SWIFT
let name = "Alice"
let numbers = [1, 2, 3]
print(name)          // Alice
debugPrint(name)     // "Alice"
dump(name)           // - "Alice"
print(numbers)       // [1, 2, 3]
debugPrint(numbers)  // [1, 2, 3]
dump(numbers)
// ▿ 3 elements
//   - 0 : 1
//   - 1 : 2
//   - 2 : 3
Função Finalidade Saída de String Saída de Array
print Saída normal Alice [1, 2, 3]
debugPrint Saída de depuração (mostra info do tipo) "Alice" [1, 2, 3]
dump Saída detalhada da estrutura - "Alice" Um elemento por linha

▶ Exemplo: Saída de Log Formatada

SWIFT
// ============================================
// Simulate system log output
// Demonstrates advanced print parameters and debugPrint
// ============================================
let event = "USER_LOGIN"
let user = "Alice"
let statusCode = 200
let duration = 0.045
// 1. Use separator to format the log
print("[\(event)]", user, "Status: \(statusCode)", separator: " | ", terminator: "")
print(" (\(duration)s)")
// [USER_LOGIN] | Alice | Status: 200 (0.045s)
// 2. Output tabular data
print()
print("=== Report ===")
print("Item", "Price", "Qty", separator: " | ")
print("-----", "-----", "---", separator: " | ")
print("Book", "12.99", "3", separator: " | ")
print("Pen", "1.50", "10", separator: " | ")
print("Bag", "49.99", "1", separator: " | ")
// 3. debugPrint for development debugging
let input: String? = "test"
debugPrint("Debug: input = \(input)")
// "Debug: input = Optional(\"test\")"

Saída:

TEXT 📖 Somente leitura
[LOGIN_USUARIO] | Alice | Status: 200 (0.045s)

=== Relatório ===
Item | Preço | Qtd
----- | ----- | ---
Livro | 12.99 | 3
Caneta | 1.50 | 10
Mochila | 49.99 | 1
Depuração: entrada = Optional("teste")

4. Asserções e Precondições

Asserções e precondições são as ferramentas de programação defensiva embutidas do Swift, capturando erros de lógica precocemente durante o desenvolvimento.

100%
graph LR
    A[Verificações em Tempo de Execução] --> B[assert]
    A --> C[precondition]
    B --> D[Apenas modo Debug]
    B --> E[Capturar problemas durante o desenvolvimento]
    C --> F[Debug + Release]
    C --> G[Erros irrecuperáveis]
Função Ativa Em Finalidade Exemplo
assert Apenas Debug Verificações de consistência interna durante o desenvolvimento assert(idade > 0)
assertionFailure Apenas Debug Disparo incondicional de asserção assertionFailure("Não deveria chegar aqui")
precondition Todos os modos Verificações de pré-condição precondition(!nome.isEmpty)
preconditionFailure Todos os modos Encerramento incondicional preconditionFailure("Erro fatal")

(1) Asserções de Depuração assert

assert só tem efeito no modo Debug; é removida no modo Release, portanto, não há impacto no desempenho:

SWIFT
func calculateDiscount(price: Double, percent: Double) -> Double {
    assert(price > 0, "Price must be greater than 0")
    assert(percent >= 0 && percent <= 100, "Discount must be between 0-100")
    let discount = price * percent / 100.0
    return price - discount
}
let finalPrice = calculateDiscount(price: 100.0, percent: 20)
print(finalPrice)  // 80.0
// The following would trigger assertion failures in Debug mode:
// calculateDiscount(price: -10, percent: 20)  // ❌ assert fails
// calculateDiscount(price: 100, percent: 150) // ❌ assert fails

(2) Verificações precondition

precondition tem efeito tanto no modo Debug quanto no Release — encerra o programa imediatamente quando uma condição não pode ser satisfeita:

SWIFT
func sendEmail(to address: String, message: String) {
    precondition(address.contains("@"), "Invalid email address: \(address)")
    precondition(!message.isEmpty, "Message cannot be empty")
    print("Sending email to \(address): \(message)")
}
sendEmail(to: "alice@example.com", message: "Hello!")
// Sending email to alice@example.com: Hello!
// The following would trigger precondition failures (all modes):
// sendEmail(to: "invalid", message: "Hi")
💡 Dica: assert é para "verificações internas" (garantir que seu próprio código está correto); precondition é para "contratos externos" (garantir que os chamadores atendem aos requisitos). Use assert abundantemente durante a depuração; use precondition para limites de API pública.

▶ Exemplo: Validação de Parâmetros

SWIFT
// ============================================
// User registration parameter checks
// Demonstrates assert and precondition usage
// ============================================
import Foundation
func registerUser(name: String, age: Int, email: String) {
    // precondition: Public API contract (active in all modes)
    precondition(name.count >= 2, "Username must be at least 2 characters")
    precondition(age >= 18, "User must be at least 18 years old")
    precondition(email.contains("@"), "Invalid email format")
    // assert: Internal logic check (Debug only)
    let emailParts = email.split(separator: "@")
    assert(emailParts.count == 2, "Email should contain exactly one @ symbol")
    let domain = String(emailParts[1])
    assert(domain.contains("."), "Email domain is invalid")
    // Actual registration logic
    print("Registration successful: \(name), age \(age)")
    print("Confirmation email sent to: \(email)")
}
// Valid call
registerUser(name: "Alice", age: 28, email: "alice@example.com")
print("---")
// Calls that would trigger precondition failures (commented out to avoid crashing)
// registerUser(name: "A", age: 20, email: "test@test.com")

Saída:

TEXT 📖 Somente leitura
Registration successful: Alice, age 28
Confirmation email sent to: alice@example.com
---

5. Depuração no Playground

O Playgrounds oferece capacidades de depuração mais poderosas que o print, incluindo visualizações ao vivo e pontos de interrupção.

(1) Visualização ao Vivo no Playground

A barra lateral no Playgrounds mostra o resultado de cada linha em tempo real:

SWIFT
// Run in Playground — the sidebar shows each step's result
let name = "Alice"    // "Alice"
var score = 0         // 0
score += 85           // 85
score += 92           // 177
let average = score / 2  // 88
100%
graph TB
    A[Depuração no Playground] --> B[Painel de Resultados ao Vivo]
    A --> C[Depuração com Pontos de Interrupção]
    A --> D[Histórico de Valores]
    B --> E[Resultados exibidos por linha]
    C --> F[Pausar / Avançar / Continuar]
    D --> G[Curvas de mudança de valor das variáveis]
Recurso Como Usar Finalidade
Visualização ao vivo A edição de código exibe resultados automaticamente à direita Ver rapidamente o resultado de cada etapa
Pontos de interrupção Clique no número da linha para adicionar um ponto de interrupção Pausar a execução, rastrear passo a passo
Histórico de valores Passe o mouse sobre uma variável Ver como uma variável muda ao longo do tempo
Visualização de expressão Selecione o código Avaliar rapidamente uma expressão selecionada

(2) Depuração com Pontos de Interrupção

Clique no lado esquerdo de um número de linha para definir um ponto de interrupção. Quando o programa atinge essa linha, ele pausa para que você possa inspecionar todos os valores atuais das variáveis:

SWIFT
func calculateTotal(items: [Double], tax: Double) -> Double {
    var subtotal = 0.0
    // Set a breakpoint on this line
    for item in items {
        subtotal += item
    }
    let taxAmount = subtotal * tax
    let total = subtotal + taxAmount
    return total
}
let cart = [29.99, 49.99, 15.00]
let final = calculateTotal(items: cart, tax: 0.08)
print("Total: $\(final)")
💡 Dica: No Xcode ou Playgrounds, clique em um número de linha para adicionar um ponto de interrupção. Quando acionado, a área de depuração na parte inferior mostra todos os valores atuais das variáveis. Você pode escolher "Continuar" ou "Avançar" para prosseguir.

▶ Exemplo: Depuração no Playground na Prática

SWIFT
// ============================================
// Practice Playground debugging techniques
// Paste this code into a Playground and run it
// ============================================
import Foundation
// 1. Set a breakpoint on the line below to observe variable values
let data: [String: Any] = [
    "product": "Swift Book",
    "price": 39.99,
    "quantity": 3,
    "inStock": true
]
// 2. Step through the following code
let productName = data["product"] as? String ?? "Unknown"
let price = data["price"] as? Double ?? 0.0
let quantity = data["quantity"] as? Int ?? 0
let inStock = data["inStock"] as? Bool ?? false
print("Product: \(productName)")
print("Price: $\(price)")
print("Quantity: \(quantity)")
print("In Stock: \(inStock)")
// 3. Observe the conditional check results
if inStock {
    let totalCost = price * Double(quantity)
    print("Total Cost: $\(totalCost)")
} else {
    print("Item is out of stock")
}
// 4. Use dump to inspect complex data
print("\n=== Debug Info ===")
dump(data)

Saída:

TEXT 📖 Somente leitura
Produto: Livro Swift
Preço: R$39.99
Quantidade: 3
Em Estoque: true
Custo Total: R$119.97

=== Informações de Depuração ===
▿ 4 pares chave/valor
  ▿ (2 elementos)
    - chave: "produto"
    - valor: "Livro Swift"
  ▿ (2 elementos)
    - chave: "preco"
    - valor: 39.99
  ▿ (2 elementos)
    - chave: "quantidade"
    - valor: 3
  ▿ (2 elementos)
    - chave: "emEstoque"
    - valor: true

6. Exemplo Completo: Ferramenta de Depuração para Análise de Notas

SWIFT
// ============================================
// Grade analysis tool
// Combines print debugging + assertion checks + formatted output
// ============================================
import Foundation
// 1. Student grade data
let studentName = "Alice"
let scores = [85.0, 92.0, 78.0, 90.0, 88.0]
// 2. Debug assertions to validate data
assert(scores.count > 0, "Score list cannot be empty")
for score in scores {
    assert(score >= 0 && score <= 100, "Score must be between 0-100: \(score)")
}
// 3. Calculate statistics
var total = 0.0
var highest = scores[0]
var lowest = scores[0]
// Set a breakpoint here to observe the loop process
for (index, score) in scores.enumerated() {
    print("[DEBUG] Index \(index): \(score)")
    total += score
    if score > highest { highest = score }
    if score < lowest { lowest = score }
}
let average = total / Double(scores.count)
// 4. Formatted output
print(String(repeating: "=", count: 35))
print("Student: \(studentName)")
print(String(repeating: "-", count: 35))
print("Subject", "Score", "Grade", separator: " | ")
print(String(repeating: "-", count: 35))
for (index, score) in scores.enumerated() {
    let grade = score >= 90 ? "A" : score >= 80 ? "B" : score >= 70 ? "C" : "D"
    print("Subject \(index + 1)", score, grade, separator: " | ")
}
print(String(repeating: "-", count: 35))
print("Total: \(total)")
print("Average: \(String(format: "%.1f", average))")
print("Highest: \(highest)")
print("Lowest: \(lowest)")
print(String(repeating: "=", count: 35))
// 5. Precondition to ensure reasonable results
precondition(average >= 0 && average <= 100, "Average is outside expected range")
precondition(highest >= lowest, "Highest score should not be lower than lowest")

Saída:

TEXT 📖 Somente leitura
[DEBUG] Index 0: 85.0
[DEBUG] Index 1: 92.0
[DEBUG] Index 2: 78.0
[DEBUG] Index 3: 90.0
[DEBUG] Index 4: 88.0
===================================
Student: Alice
-----------------------------------
Subject | Score | Grade
-----------------------------------
Subject 1 | 85.0 | B
Subject 2 | 92.0 | A
Subject 3 | 78.0 | C
Subject 4 | 90.0 | A
Subject 5 | 88.0 | B
-----------------------------------
Total: 433.0
Average: 86.6
Highest: 92.0
Lowest: 78.0
===================================

❓ Perguntas Frequentes

P: Qual é a diferença real entre print e debugPrint? R: print exibe em formato legível por humanos (ex.: Alice), enquanto debugPrint exibe em formato orientado à depuração (ex.: "Alice" com aspas). Tipos personalizados podem implementar os protocolos CustomStringConvertible e CustomDebugStringConvertible para controlar ambas as saídas. P: O assert é removido no modo Release? R: Sim. assert só tem efeito no modo Debug (-Onone). No modo Release, o compilador ignora a avaliação e execução dos asserts. Portanto, nunca coloque lógica com efeitos colaterais dentro de um assert. P: Quando devo usar precondition em vez de assert? R: precondition tem efeito em todos os modos e é para erros fatais irrecuperáveis. Exemplos: verificação de limite de array, parâmetro obrigatório sendo nil, um ramo que logicamente nunca deveria ser alcançado. Use precondition para validação de parâmetros de API pública. P: Como usar pontos de interrupção no Playgrounds? R: Clique no lado esquerdo de um número de linha para definir um ponto de interrupção. Quando o programa atinge um ponto de interrupção, ele pausa. Passe o mouse sobre qualquer variável para ver seu valor. Pressione o botão continuar ou F6 para avançar para a próxima linha. P: Por que não consigo ver a saída no console mesmo tendo usado print? R: Verifique se seu Playground está com o modo ".enableResults" ativado. No Xcode, certifique-se de que a Área de Depuração está aberta (Shift+Cmd+Y). No app Swift Playgrounds, a saída aparece no painel inferior.


📖 Resumo


📝 Exercícios

  1. Iniciante: Use print para gerar uma tabuada simples (1-3), controlando o formato com separator e terminator para exibir um estilo tabular.
  2. Intermediário: Escreva uma função dividir(_ a: Double, por b: Double) -> Double, usando precondition para verificar se o divisor não é 0 e assert para verificar se o resultado está dentro de um intervalo razoável. Em seguida, use print com formatação para exibir o resultado.
  3. Desafio: Simule um programa de saque de caixa eletrônico. Use assert para verificar se o valor do saque é múltiplo de 100 e precondition para verificar se há saldo suficiente. Use print com separator e terminator para formatar os detalhes da transação, incluindo hora, valor e saldo.
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%