dicembre 21, 2025
13 min di lettura

Domande per il Colloquio di Sviluppatore Mobile Junior (iOS): Guida Completa

interview
career-advice
job-search
entry-level
Domande per il Colloquio di Sviluppatore Mobile Junior (iOS): Guida Completa
MB

Milad Bonakdar

Autore

Padroneggia i fondamenti dello sviluppo iOS con domande essenziali per il colloquio che coprono Swift, UIKit, SwiftUI, la persistenza dei dati e l'architettura delle app iOS per sviluppatori junior.


Introduzione

Lo sviluppo iOS è diventato una delle competenze più richieste nello sviluppo di app mobile. Con Swift come linguaggio principale e framework potenti come UIKit e SwiftUI, gli sviluppatori iOS creano esperienze per milioni di utenti in tutto il mondo.

Questa guida copre le domande essenziali per i colloqui per Junior iOS Developer. Esploreremo i fondamenti di Swift, lo sviluppo dell'interfaccia utente, la persistenza dei dati, il networking e le migliori pratiche iOS per aiutarti a prepararti per il tuo primo ruolo come sviluppatore iOS.


Fondamenti di Swift (6 Domande)

1. Qual è la differenza tra var e let in Swift?

Risposta:

  • var: Dichiara una variabile mutabile. Il suo valore può essere modificato dopo l'inizializzazione.
  • let: Dichiara una costante immutabile. Una volta impostato, il suo valore non può essere modificato.
  • Best Practice: Usa let di default per sicurezza e chiarezza. Usa var solo quando sai che il valore cambierà.
let name = "John"  // Non può essere modificato
var age = 25       // Può essere modificato
age = 26           // Valido
// name = "Jane"   // Errore: Impossibile assegnare un valore

Rarità: Molto Comune Difficoltà: Facile


2. Spiega gli Optional in Swift. Cos'è l'Optional Binding?

Risposta: Gli Optional rappresentano un valore che potrebbe essere nil (assenza di un valore).

  • Dichiarazione: Usa ? dopo il tipo: var name: String?
  • Metodi di Unwrapping:
    • Force Unwrapping: name! (pericoloso, crasha se nil)
    • Optional Binding: Unwrapping sicuro usando if let o guard let
    • Nil Coalescing: name ?? "Default"
    • Optional Chaining: user?.address?.city
var email: String? = "[email protected]"

// Optional Binding
if let unwrappedEmail = email {
    print("Email: \(unwrappedEmail)")
} else {
    print("Nessuna email")
}

// Guard statement
guard let email = email else { return }
print(email)

Rarità: Molto Comune Difficoltà: Facile


3. Qual è la differenza tra una class e una struct in Swift?

Risposta:

  • Class: Tipo di riferimento (memorizzato nell'heap). Supporta l'ereditarietà. Passato per riferimento.
  • Struct: Tipo di valore (memorizzato nello stack). Nessuna ereditarietà. Passato per copia.
  • Quando usare:
    • Struct: Per modelli di dati semplici, quando si desidera una semantica di valore (copie indipendenti)
    • Class: Quando è necessaria l'ereditarietà, la semantica di riferimento o i deinitializer
struct Point {
    var x: Int
    var y: Int
}

class Person {
    var name: String
    init(name: String) { self.name = name }
}

var p1 = Point(x: 0, y: 0)
var p2 = p1  // Copia creata
p2.x = 10    // p1.x è ancora 0

var person1 = Person(name: "John")
var person2 = person1  // Stesso riferimento
person2.name = "Jane"  // person1.name è anche "Jane"

Rarità: Molto Comune Difficoltà: Media


4. Cosa sono le Closure in Swift?

Risposta: Le Closure sono blocchi di funzionalità autonomi che possono essere passati e utilizzati nel tuo codice. Sono simili alle lambda o alle funzioni anonime in altri linguaggi.

  • Sintassi: { (parametri) -> ReturnType in statements }
  • Cattura di Valori: Le Closure possono catturare e memorizzare riferimenti a variabili dal loro contesto circostante.
  • Uso Comune: Completion handler, callback, operazioni su array.
// Closure semplice
let greet = { (name: String) -> String in
    return "Ciao, \(name)!"
}
print(greet("Alice"))

// Sintassi di trailing closure
let numbers = [1, 2, 3, 4, 5]
let doubled = numbers.map { $0 * 2 }
print(doubled)  // [2, 4, 6, 8, 10]

Rarità: Molto Comune Difficoltà: Media


5. Spiega la differenza tra riferimenti weak e unowned.

Risposta: Entrambi vengono utilizzati per prevenire cicli di ritenzione (perdite di memoria) nei tipi di riferimento.

  • weak: Riferimento opzionale che diventa automaticamente nil quando l'oggetto a cui si fa riferimento viene deallocato. Usare quando il riferimento potrebbe sopravvivere all'oggetto.
  • unowned: Riferimento non opzionale che presuppone che l'oggetto esisterà sempre. Si arresta in modo anomalo se vi si accede dopo la deallocazione. Usare quando si è certi che il riferimento non sopravviverà all'oggetto.
class Person {
    var name: String
    weak var apartment: Apartment?  // weak per prevenire il ciclo di ritenzione
    init(name: String) { self.name = name }
}

class Apartment {
    var unit: String
    unowned let tenant: Person  // unowned - l'appartamento ha sempre un inquilino
    init(unit: String, tenant: Person) {
        self.unit = unit
        self.tenant = tenant
    }
}

Rarità: Comune Difficoltà: Media


6. Cosa sono i Protocolli in Swift?

Risposta: I Protocolli definiscono un blueprint di metodi, proprietà e altri requisiti adatti a un particolare compito o funzionalità. Classi, struct ed enum possono adottare protocolli.

  • Simile a: Interfacce in altri linguaggi
  • Estensioni di Protocollo: Possono fornire implementazioni predefinite
  • Programmazione Orientata al Protocollo: Paradigma preferito di Swift
protocol Drawable {
    func draw()
}

struct Circle: Drawable {
    var radius: Double
    
    func draw() {
        print("Disegno cerchio con raggio \(radius)")
    }
}

struct Rectangle: Drawable {
    var width: Double
    var height: Double
    
    func draw() {
        print("Disegno rettangolo \(width)x\(height)")
    }
}

Rarità: Molto Comune Difficoltà: Facile


Basi di UIKit (5 Domande)

7. Qual è la differenza tra UIView e UIViewController?

Risposta:

  • UIView: Rappresenta un'area rettangolare sullo schermo. Gestisce il disegno e la gestione degli eventi. Esempi: UILabel, UIButton, UIImageView.
  • UIViewController: Gestisce una gerarchia di viste. Gestisce il ciclo di vita della vista, le interazioni dell'utente e la navigazione. Contiene una vista radice e gestisce le sue sottoviste.
  • Relazione: Un view controller gestisce le viste. Un view controller può avere molte viste.

Rarità: Molto Comune Difficoltà: Facile


8. Spiega i metodi del ciclo di vita di un View Controller.

Risposta: I view controller hanno metodi specifici del ciclo di vita chiamati in ordine:

  1. viewDidLoad(): Chiamato una volta quando la vista viene caricata in memoria. Impostazioni che devono avvenire una sola volta.
  2. viewWillAppear(_:): Chiamato prima che la vista appaia sullo schermo. Può essere chiamato più volte.
  3. viewDidAppear(_:): Chiamato dopo che la vista appare sullo schermo. Avvia le animazioni qui.
  4. viewWillDisappear(_:): Chiamato prima che la vista scompaia.
  5. viewDidDisappear(_:): Chiamato dopo che la vista scompare. Pulisci le risorse.
override func viewDidLoad() {
    super.viewDidLoad()
    // Impostazione una tantum: configura l'interfaccia utente, carica i dati
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    // Aggiorna i dati, inizia ad ascoltare le notifiche
}

Rarità: Molto Comune Difficoltà: Facile


9. Cos'è Auto Layout e come si usano i vincoli (constraints)?

Risposta: Auto Layout è un sistema di layout basato su vincoli che ti consente di creare interfacce utente adattive che funzionano su diverse dimensioni dello schermo e orientamenti.

  • Vincoli (Constraints): Definiscono le relazioni tra le viste (larghezza, altezza, spaziatura, allineamento)
  • Metodi:
    • Interface Builder: Editor visuale in Xcode
    • Programmatico: API NSLayoutConstraint o NSLayoutAnchor
    • Visual Format Language: Basato su stringhe (meno comune ora)
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(button)

NSLayoutConstraint.activate([
    button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
    button.centerYAnchor.constraint(equalTo: view.centerYAnchor),
    button.widthAnchor.constraint(equalToConstant: 200),
    button.heightAnchor.constraint(equalToConstant: 50)
])

Rarità: Molto Comune Difficoltà: Media


10. Qual è la differenza tra frame e bounds?

Risposta:

  • frame: La posizione e le dimensioni della vista nel sistema di coordinate della sua supervista. Usato per posizionare la vista.
  • bounds: La posizione e le dimensioni della vista nel suo proprio sistema di coordinate. L'origine è solitamente (0, 0). Usato per disegnare il contenuto all'interno della vista.
  • Differenza Chiave: frame è relativo al genitore, bounds è relativo a se stesso.
let view = UIView(frame: CGRect(x: 50, y: 100, width: 200, height: 150))
print(view.frame)   // (50, 100, 200, 150) - posizione nella supervista
print(view.bounds)  // (0, 0, 200, 150) - proprio sistema di coordinate

Rarità: Comune Difficoltà: Media


11. Come gestisci l'input utente da un UITextField?

Risposta: Esistono diversi approcci:

  • Target-Action: Aggiungi target per l'evento .editingChanged
  • Delegate: Conformarsi al protocollo UITextFieldDelegate
  • Combine: Usa i publisher (approccio moderno)
class ViewController: UIViewController, UITextFieldDelegate {
    let textField = UITextField()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Approccio Delegate
        textField.delegate = self
        
        // Approccio Target-Action
        textField.addTarget(self, action: #selector(textChanged), for: .editingChanged)
    }
    
    @objc func textChanged(_ textField: UITextField) {
        print("Testo: \(textField.text ?? "")")
    }
    
    // Metodo Delegate
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }
}

Rarità: Molto Comune Difficoltà: Facile


Basi di SwiftUI (4 Domande)

12. Cos'è SwiftUI e in cosa è diverso da UIKit?

Risposta: SwiftUI è il framework UI dichiarativo di Apple introdotto in iOS 13.

  • UIKit: Imperativo (dici al sistema come costruire l'interfaccia utente passo dopo passo). Maturo, ampiamente utilizzato.
  • SwiftUI: Dichiarativo (descrivi come dovrebbe apparire l'interfaccia utente). Moderno, meno codice, aggiornamenti automatici.
  • Caratteristiche Chiave:
    • Anteprima live in Xcode
    • Multipiattaforma (iOS, macOS, watchOS, tvOS)
    • Aggiornamenti dell'interfaccia utente guidati dallo stato
    • Animazioni integrate
// SwiftUI
struct ContentView: View {
    @State private var count = 0
    
    var body: some View {
        VStack {
            Text("Count: \(count)")
            Button("Increment") {
                count += 1
            }
        }
    }
}

Rarità: Molto Comune Difficoltà: Facile


13. Spiega @State, @Binding e @ObservedObject in SwiftUI.

Risposta: Questi sono wrapper di proprietà per la gestione dello stato in SwiftUI:

  • @State: Stato privato di proprietà della vista. Quando cambia, la vista viene renderizzata nuovamente.
  • @Binding: Crea una connessione bidirezionale a una proprietà @State di proprietà di una vista padre.
  • @ObservedObject: Fa riferimento a un oggetto esterno (classe conforme a ObservableObject). La vista si aggiorna quando le proprietà @Published dell'oggetto cambiano.
class UserData: ObservableObject {
    @Published var name = ""
}

struct ParentView: View {
    @State private var isOn = false
    @ObservedObject var userData = UserData()
    
    var body: some View {
        VStack {
            ChildView(isOn: $isOn)  // Passa il binding
            Text(userData.name)
        }
    }
}

struct ChildView: View {
    @Binding var isOn: Bool  // Riceve il binding
    
    var body: some View {
        Toggle("Switch", isOn: $isOn)
    }
}

Rarità: Comune Difficoltà: Media


14. Come crei una lista in SwiftUI?

Risposta: Usa la vista List per visualizzare raccolte scorrevoli di dati.

struct ContentView: View {
    let fruits = ["Apple", "Banana", "Orange", "Grape"]
    
    var body: some View {
        List(fruits, id: \.self) { fruit in
            Text(fruit)
        }
    }
}

// Con modello personalizzato
struct Task: Identifiable {
    let id = UUID()
    let title: String
}

struct TaskListView: View {
    let tasks = [
        Task(title: "Buy groceries"),
        Task(title: "Walk the dog")
    ]
    
    var body: some View {
        List(tasks) { task in
            Text(task.title)
        }
    }
}

Rarità: Comune Difficoltà: Facile


15. Cosa sono i View Modifiers in SwiftUI?

Risposta: I modificatori di vista sono metodi che creano una nuova vista con proprietà modificate. Sono concatenabili.

  • Modificatori Comuni: .padding(), .background(), .foregroundColor(), .font(), .frame()
  • L'Ordine Conta: I modificatori vengono applicati in sequenza
Text("Hello, World!")
    .font(.title)
    .foregroundColor(.blue)
    .padding()
    .background(Color.yellow)
    .cornerRadius(10)
    .shadow(radius: 5)

// Modificatore personalizzato
struct PrimaryButtonStyle: ViewModifier {
    func body(content: Content) -> some View {
        content
            .padding()
            .background(Color.blue)
            .foregroundColor(.white)
            .cornerRadius(8)
    }
}

extension View {
    func primaryButton() -> some View {
        modifier(PrimaryButtonStyle())
    }
}

Rarità: Comune Difficoltà: Facile


Dati e Networking (5 Domande)

16. Come fai una richiesta di rete in iOS?

Risposta: Usa URLSession per le attività di networking.

func fetchData() {
    guard let url = URL(string: "https://api.example.com/data") else { return }
    
    let task = URLSession.shared.dataTask(with: url) { data, response, error in
        if let error = error {
            print("Errore: \(error)")
            return
        }
        
        guard let data = data else { return }
        
        // Analizza JSON
        do {
            let decoder = JSONDecoder()
            let result = try decoder.decode(MyModel.self, from: data)
            print(result)
        } catch {
            print("Errore di decodifica: \(error)")
        }
    }
    
    task.resume()
}

Rarità: Molto Comune Difficoltà: Media


17. Cos'è Codable in Swift?

Risposta: Codable è un alias di tipo per i protocolli Encodable & Decodable. Consente una facile conversione tra tipi Swift e rappresentazioni esterne come JSON.

  • Sintesi Automatica: Swift genera automaticamente il codice di codifica/decodifica se tutte le proprietà sono Codable.
  • Chiavi Personalizzate: Usa l'enum CodingKeys per mappare nomi di proprietà diversi.
struct User: Codable {
    let id: Int
    let name: String
    let email: String
}

// Decodifica JSON
let json = """
{
    "id": 1,
    "name": "John Doe",
    "email": "[email protected]"
}
""".data(using: .utf8)!

let decoder = JSONDecoder()
let user = try decoder.decode(User.self, from: json)

// Codifica in JSON
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let jsonData = try encoder.encode(user)

Rarità: Molto Comune Difficoltà: Facile


18. Come rendi persistenti i dati localmente in iOS?

Risposta: Molteplici opzioni per la persistenza dei dati locale:

  • UserDefaults: Semplice storage chiave-valore per piccole quantità di dati (impostazioni, preferenze)
  • File System: Salva i file nella directory Documents o Cache
  • Core Data: Framework di Apple per la gestione e la persistenza del grafo di oggetti
  • SQLite: Database relazionale
  • Keychain: Storage sicuro per dati sensibili (password, token)
// UserDefaults
UserDefaults.standard.set("John", forKey: "username")
let username = UserDefaults.standard.string(forKey: "username")

// File System
let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let filePath = documentsPath.appendingPathComponent("data.json")

// Scrivi
try data.write(to: filePath)

// Leggi
let loadedData = try Data(contentsOf: filePath)

Rarità: Molto Comune Difficoltà: Facile


19. Qual è la differenza tra operazioni sincrone e asincrone?

Risposta:

  • Sincrone: Blocca il thread corrente fino al completamento dell'operazione. Può bloccare l'interfaccia utente se eseguita sul thread principale.
  • Asincrone: Non blocca il thread. L'operazione viene eseguita in background e viene chiamato un completion handler al termine.
  • Thread Principale: Gli aggiornamenti dell'interfaccia utente devono avvenire sul thread principale. Usa DispatchQueue.main.async per passare al thread principale.
// Sincrono (MALE per le chiamate di rete)
let data = try Data(contentsOf: url)  // Blocca fino al completamento

// Asincrono (BENE)
URLSession.shared.dataTask(with: url) { data, response, error in
    // Questo viene eseguito sul thread in background
    
    DispatchQueue.main.async {
        // Aggiorna l'interfaccia utente sul thread principale
        self.label.text = "Dati caricati"
    }
}.resume()

Rarità: Comune Difficoltà: Facile


20. Cos'è Grand Central Dispatch (GCD)?

Risposta: GCD è l'API di basso livello di Apple per la gestione di operazioni concorrenti.

  • Dispatch Queues: Code FIFO che eseguono attività in serie o in modo concorrente
  • Main Queue: Coda seriale per gli aggiornamenti dell'interfaccia utente
  • Global Queues: Code concorrenti con priorità diverse (background, utility, userInitiated)
// Esegui sul thread in background
DispatchQueue.global(qos: .background).async {
    // Calcolo pesante
    let result = performExpensiveOperation()
    
    // Aggiorna l'interfaccia utente sul thread principale
    DispatchQueue.main.async {
        self.label.text = result
    }
}

// Ritarda l'esecuzione
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
    print("Eseguito dopo 2 secondi")
}

Rarità: Comune Difficoltà: Media


Newsletter subscription

Consigli di carriera settimanali che funzionano davvero

Ricevi le ultime idee direttamente nella tua casella di posta

Decorative doodle

Distinguiti dai Reclutatori e Ottieni il Lavoro dei Tuoi Sogni

Unisciti a migliaia di persone che hanno trasformato la loro carriera con curriculum potenziati dall'IA che superano l'ATS e impressionano i responsabili delle assunzioni.

Inizia a creare ora

Condividi questo post

Riduci il Tempo di Scrittura del Curriculum del 90%

La persona in cerca di lavoro media impiega più di 3 ore per formattare un curriculum. La nostra IA lo fa in meno di 15 minuti, portandoti alla fase di candidatura 12 volte più velocemente.