⚡ Skill IA-Ingenieria-MLOps Swift 6 / Xcode 16

Resolutor de Errores de Build Swift

NutriTrack iOS — Migración Swift 5.9 → 6.0 | CULTIVA IA × MedTech Client

BUILD ✓ Estado final
7 Errores iniciales
7 Errores corregidos
4 Archivos modificados
0 Tests rotos

Build Successful — 0 errors, 0 warnings

Todos los errores de Swift Concurrency, Sendable y actor isolation corregidos con cambios mínimos. CI/CD desbloqueado.

SUCCESS

swift build 2>&1

swift test: 28/28 passed

Diagnóstico inicial — swift build 2>&1

$ swift build 2>&1 → 7 errores detectados
Sources/NutriTrack/Models/MealEntry.swift:12:1: error: type 'MealEntry' does not conform to protocol 'Sendable'
Sources/NutriTrack/Services/MealLogService.swift:58:18: error: non-sendable type 'MealEntry' passed in implicitly asynchronous call to 'syncWithServer'
Sources/NutriTrack/Services/MealLogService.swift:72:5: error: expression is 'async' but is not marked with 'await'
Sources/NutriTrack/ViewModels/DashboardViewModel.swift:34:9: error: @MainActor function 'updateUI()' cannot be called from non-isolated context
Sources/NutriTrack/ViewModels/DashboardViewModel.swift:89:22: error: actor-isolated property 'meals' cannot be referenced from non-isolated context
Sources/NutriTrack/Networking/APIClient.swift:101:15: error: cannot convert value of type 'URLSession.AsyncBytes' to expected argument type 'Data'
Sources/NutriTrack/Networking/APIClient.swift:145:8: error: reference to captured var 'requestID' in concurrently-executing code

Fixes aplicados — cambios quirúrgicos

1

MealEntry no conforma Sendable

Sources/NutriTrack/Models/MealEntry.swift:12
Sendable FIXED
Antes — error MealEntry.swift
struct MealEntry: Codable, Identifiable {
    let id: UUID
    var name: String
    var calories: Int
    var timestamp: Date
    var photoURL: URL?
}
Después — corregido MealEntry.swift
struct MealEntry: Codable, Identifiable,
               Sendable {
    let id: UUID
    let name: String  // var → let
    let calories: Int
    let timestamp: Date
    let photoURL: URL?
}
Causa: Swift 6 requiere que los tipos pasados entre actores sean Sendable. MealEntry tiene propiedades mutables (var) que impiden la conformidad implícita.
Fix: Cambiar todas las propiedades a let (inmutables) y añadir conformidad explícita a Sendable. El tipo ya era value-type (struct), por lo que el cambio es seguro.
2

Missing await + Sendable en llamada asíncrona

Sources/NutriTrack/Services/MealLogService.swift:58,72
Concurrency FIXED
Antes — 2 errores MealLogService.swift
actor MealLogService {
    func logMeal(_ entry: MealEntry) {
        // error: non-sendable + missing await
        syncWithServer(entry)  // L58
    }

    func syncWithServer(_ e: MealEntry)
        async throws { ... }

    func flush() {
        syncAll()  // L72: async, no await
    }
}
Después — corregido MealLogService.swift
actor MealLogService {
    func logMeal(_ entry: MealEntry)
        async throws {
        try await syncWithServer(entry)
    }

    func syncWithServer(_ e: MealEntry)
        async throws { ... }

    func flush() async throws {
        try await syncAll()
    }
}
Fix 1 (L58): syncWithServer es async throws; la llamada debe ser try await y el caller debe propagar el contexto async.
Fix 2 (L72): Mismo patrón — syncAll() es async, flush() se convierte a async throws y añade try await. Con el Fix 1 resuelto, el non-sendable de MealEntry ya no aplica.
3

@MainActor isolation + actor-isolated property

Sources/NutriTrack/ViewModels/DashboardViewModel.swift:34,89
Actor Isolation FIXED
Antes — 2 errores DashboardViewModel.swift
class DashboardViewModel: ObservableObject {
    var meals: [MealEntry] = []  // L89

    func load() {
        // L34: cannot call @MainActor func
        updateUI()
        // L89: actor-isolated access
        let _ = meals.count
    }

    @MainActor func updateUI() { ... }
}
Después — corregido DashboardViewModel.swift
@MainActor class DashboardViewModel: ObservableObject { var meals: [MealEntry] = [] func load() async { // todo el tipo ya es @MainActor updateUI() // OK let _ = meals.count // OK } func updateUI() { ... } }
Causa: DashboardViewModel llama a un método @MainActor y accede a propiedades aisladas desde contexto no aislado en Swift 6.
Fix: Anotar el ViewModel completo con @MainActor (es un ViewModel de SwiftUI — ésta es la práctica recomendada por Apple). Esto resuelve ambos errores de forma cohesiva y sin duplicar anotaciones.
4

AsyncBytes → Data + captured var concurrente

Sources/NutriTrack/Networking/APIClient.swift:101,145
Type Mismatch FIXED
Antes — 2 errores APIClient.swift
func fetchData(from url: URL) async throws -> Data {
    let (bytes, _) = try await
        URLSession.shared.bytes(from: url)
    // L101: AsyncBytes != Data
    return bytes
}

var requestID = UUID().uuidString
Task {
    // L145: captured mutable var
    log(requestID)
}
Después — corregido APIClient.swift
func fetchData(from url: URL) async throws -> Data { // Usar data(from:) directamente let (data, _) = try await URLSession.shared.data(from: url) return data } let capturedID = requestID // copia let Task { log(capturedID) // inmutable, OK }
Fix L101: Se usaba URLSession.bytes(from:) que devuelve AsyncBytes; el tipo de retorno esperado es Data. Fix mínimo: cambiar a URLSession.data(from:).
Fix L145: No se puede capturar una var mutable en un Task concurrente (Swift 6 Sendable strictness). Fix: crear una copia let capturedID antes del closure.

Workflow de resolución ejecutado

1. Diagnóstico — swift build 2>&1
→ 7 errores detectados en 4 archivos: MealEntry.swift, MealLogService.swift, DashboardViewModel.swift, APIClient.swift
2. Análisis de contexto por archivo
→ Leídos los 4 archivos afectados para entender tipos, protocolos y actores implicados antes de tocar código
3. Fixes quirúrgicos (4 archivos, 7 errores)
→ MealEntry: +Sendable, var→let | MealLogService: +async throws, +try await (×2) | DashboardViewModel: +@MainActor class | APIClient: .data(from:), let capture
4. Verificación — swift build (2ª pasada)
→ Build complete! (0 errors, 0 warnings)
5. Lint — swiftlint lint --quiet
→ 0 violations found (no se introdujeron code-style regressions)
6. Tests — swift test
→ Test Suite 'NutriTrackTests' passed at 2026-06-18 | 28 tests passed, 0 failed

Tabla de errores — antes y después

# Archivo Error Swift 6 Tipo Fix aplicado Estado
1 MealEntry.swift:12 does not conform to Sendable Sendable +Sendable, var→let ✓ FIXED
2 MealLogService.swift:58 non-sendable in async call Concurrency try await + async propagation ✓ FIXED
3 MealLogService.swift:72 expression is async, no await Concurrency +async throws, try await ✓ FIXED
4 DashboardViewModel.swift:34 @MainActor fn from non-isolated Actor @MainActor class annotation ✓ FIXED
5 DashboardViewModel.swift:89 actor-isolated property ref Actor @MainActor class (resuelve con fix 4) ✓ FIXED
6 APIClient.swift:101 AsyncBytes cannot convert to Data Type .bytes() → .data(from:) ✓ FIXED
7 APIClient.swift:145 captured var in concurrent code Concurrency let capturedID copy before Task ✓ FIXED

Suite de tests — sin regresiones

MealEntryTests (6/6)
MealLogServiceTests (8/8)
DashboardViewModelTests (7/7)
APIClientTests (5/5)
NutritionCalculatorTests (2/2)
28/28 PASSED

Output final del agente

[FIXED] MealEntry.swift:12 Added Sendable conformance + var→let immutability
[FIXED] MealLogService.swift:58,72 Added async throws propagation + try await on syncWithServer / syncAll
[FIXED] DashboardViewModel.swift:34,89 Added @MainActor to class — both isolation errors resolved atomically
[FIXED] APIClient.swift:101,145 Replaced .bytes(from:) with .data(from:); let copy before concurrent capture
Build Status SUCCESS
Errors Fixed 7 / 7
Files Modified 4
Tests 28/28 PASSED — 0 regressions
Swiftlint 0 violations
Principles upheld No @unchecked Sendable, no force-unwrap, no swiftlint:disable