Tu primera app de iOS
Al terminar: Crear la app de iOS, enlazar el paquete Torneo, entender App, Scene y scenePhase y escribir tus primeras pruebas.
Al terminar tendrás en ~/Marcador-Swift/MarcadorApp una app de iOS recién creada que arranca en el simulador con la pantalla de la plantilla, con el nombre «Marcador», el identificador com.sebastiannarvaez.marcador y la versión mínima de iOS puesta en 18.0 en el proyecto y en la app. Todavía no enseña nada del partido: eso llega en las dos lecciones siguientes, cuando le enlaces el paquete Torneo y escribas sus primeras pruebas.
Importa porque un proyecto de Xcode tiene piezas que un paquete no tiene (targets, schemes, ajustes de compilación, firma) y casi todo error de «no compila y no sé por qué» de aquí en adelante vive en una de ellas.
Es la primera vez que abres un proyecto de Xcode, así que la lección va despacio: primero las palabras, después un ejercicio corto en tu Playground y, al final, el proyecto de verdad. Temas: proyecto, target, scheme, firma, identificador y versión mínima.
Qué es un proyecto de Xcode
Hasta ahora trabajaste con un paquete: una carpeta con un Package.swift que dice qué código tiene y qué pruebas. Una app de iPhone necesita más: un nombre y un icono, una versión mínima de iOS, una firma y varias formas de compilarse. Todo eso vive en un proyecto de Xcode, una carpeta con extensión .xcodeproj y el código de la app a su lado.
Target, scheme y ajustes
Tres palabras describen un proyecto de Xcode:
| Palabra | Qué es | En Marcador |
|---|---|---|
| Objetivo (target) | Una receta para producir un resultado: la app, un grupo de pruebas | MarcadorApp, MarcadorAppTests, MarcadorAppUITests |
| Esquema (scheme) | Qué targets se compilan al pulsar Run o Test, y con qué configuración | Uno llamado MarcadorApp |
| Ajustes de compilación (build settings) | Las opciones de cada target: nombre, versión mínima de iOS, modo de Swift… | Se editan en Xcode y se guardan en el fichero project.pbxproj |
project.pbxproj es un texto largo que Xcode escribe por ti dentro de MarcadorApp.xcodeproj. No se edita a mano: se cambia desde la interfaz.
Qué es firmar
Firmar una app es adjuntarle un certificado y un perfil que dicen «esta app la publica este desarrollador y puede correr en estos dispositivos». iOS no instala en un iPhone real nada que no esté firmado. En el simulador no hace falta: Xcode firma «para ejecutar en local», sin cuenta de por medio.
Un Team (equipo) es la cuenta de desarrollador con la que Xcode firma. Si guardaste tu Apple Account en Xcode (Instalar Xcode y el simulador, paso 6), tienes un Personal Team gratuito. Para este curso en el simulador, cualquier opción vale: tu Personal Team o ninguno. Solo importa con un iPhone real como destino: sin Team, Xcode se detiene con
Signing for "MarcadorApp" requires a development team. Select a development team in the Signing & Capabilities editor.y la solución es elegir ahí tu Personal Team.
El identificador y la versión mínima
El identificador del paquete (bundle identifier) es el nombre único de la app instalada, escrito al revés como un dominio. Es el applicationId de Android. En el simulador no se registra en ningún sitio, así que usa el de la guía: com.sebastiannarvaez.marcador. Las órdenes de Terminal y el registro de las lecciones lo usan tal cual; si algún día pones el tuyo, cámbialo también en esas órdenes y en el Logger que escribirás en la lección siguiente.
La versión mínima de iOS (Minimum Deployments) es el sistema más antiguo donde la app se puede instalar. El asistente pone la de tu Xcode (una muy reciente, p. ej. 26.2), y la pone en dos niveles: en el proyecto entero, que heredan todos sus targets, y en la app. La bajarás a 18.0 en los dos sitios por una regla: una app no puede pedir menos que lo que exigen sus paquetes. Torneo declara .iOS(.v18) en su Package.swift (la línea platforms de async/await y Task), así que la app tiene que pedir 18 o más. Si pidiera 17, Xcode se negaría a compilar, porque el paquete no se puede usar en un iOS 17. Se ve en la lección siguiente, donde enlazas Torneo.
La regla es una comparación, y una comparación se escribe en Swift. Un ejemplo con otros datos: una atracción de feria pide una altura mínima, y sube quien mide lo mismo o más.
// Una atracción de feria pide una altura mínima: sube quien mide lo mismo o más.
func puedeSubir(alturaDeLaPersona: Int, alturaMinima: Int) -> Bool {
alturaDeLaPersona >= alturaMinima // `>=` significa «mayor o igual»: da true o false
}
let alturas = [110, 120, 150] // tres personas, en centímetros
for altura in alturas { // una vuelta por cada persona
// `condición ? uno : otro` elige entre dos textos según sea true o false
let resultado = puedeSubir(alturaDeLaPersona: altura, alturaMinima: 120) ? "sube" : "no sube"
print("Mide \(altura) cm, mínimo 120 cm: \(resultado)")
}Al ejecutarlo en el Playground, la consola imprime:
Mide 110 cm, mínimo 120 cm: no sube
Mide 120 cm, mínimo 120 cm: sube
Mide 150 cm, mínimo 120 cm: subeReto · Ejercicio: quién puede pedir menos
En tu Playground, escribe una función, compila, que reciba la versión mínima de iOS de una app y la de un paquete que esa app usa, y diga si la app compila: solo si la de la app es igual o mayor que la del paquete. Pruébala con tres apps, de iOS 17, 18 y 26, que usan un paquete de iOS 18, e imprime una línea por cada una. Lo que debe salir:
App iOS 17, paquete iOS 18: no compila
App iOS 18, paquete iOS 18: compila
App iOS 26, paquete iOS 18: compilaVer solución
// La versión mínima de iOS de una app no puede ser más baja que la de sus paquetes.
func compila(minimoDeLaApp: Int, minimoDelPaquete: Int) -> Bool {
minimoDeLaApp >= minimoDelPaquete
}
let casos = [17, 18, 26]
for app in casos {
let resultado = compila(minimoDeLaApp: app, minimoDelPaquete: 18) ? "compila" : "no compila"
print("App iOS \(app), paquete iOS 18: \(resultado)")
}Solo la app de iOS 17 pide menos de lo que exige el paquete. Los nombres de la función y de los parámetros son libres: lo que importa es la salida.
Paso 1 · Crea el proyecto con el asistente
Objetivo: un proyecto de Xcode llamado MarcadorApp, dentro de ~/Marcador-Swift, al lado del paquete Torneo.
El asistente de proyectos es el formulario con el que Xcode crea un proyecto nuevo, con los ficheros mínimos para que compile.
- Abre Xcode. En la ventana de bienvenida pulsa Create New Project…; si ya hay un proyecto abierto, usa File → New → Project….
- Arriba elige la pestaña iOS, la plantilla App y pulsa Next.
- Rellena el formulario así:
| Campo | Qué poner | Para qué sirve |
|---|---|---|
| Product Name | MarcadorApp | El nombre del proyecto y de la app |
| Team | Déjalo como esté | Con quién se firma la app; en el paso 4 eliges el tuyo (o ninguno) |
| Organization Identifier | com.sebastiannarvaez | La primera mitad del identificador único de la app; el asistente le pega el nombre del producto |
| Interface | SwiftUI | La forma moderna de dibujar pantallas, que aprenderás en las próximas lecciones |
| Language | Swift | |
| Testing System | Swift Testing with XCTest UI Tests | Crea dos grupos de pruebas: unitarias con Swift Testing y de interfaz con XCTest (otro marco de pruebas de Apple; lo verás en Tus primeras pruebas en iOS) |
| Storage | None | Sin base de datos |
- Pulsa Next. Xcode abre un selector de carpetas: entra en
Marcador-Swiftdentro de tu carpeta personal (la que creaste en Tu primer paquete de Swift) y pulsa Create.
Si en ese selector ves la casilla Create Git repository on my Mac, desmárcala: este curso no usa control de versiones.
Xcode crea la carpeta ~/Marcador-Swift/MarcadorApp y abre el proyecto.
Paso 2 · Recorre lo que ha generado
Objetivo: saber qué es cada cosa del panel de la izquierda antes de tocar nada.
A la izquierda está el Project navigator (el panel con la lista de ficheros; se muestra y se oculta con Cmd+1). Es lo que ves ahora:
- El icono azul
MarcadorAppes el proyecto: al seleccionarlo, el editor de la derecha enseña sus ajustes (lo usarás en el paso 4). Hay tres cosas llamadasMarcadorApp: el icono azul, la carpeta de debajo y, más adelante, un fichero.swift; las lecciones te dirán cuál con «el icono azul» o «la carpeta». - La carpeta
MarcadorAppguarda el código de la app. Es una carpeta sincronizada: Xcode la vigila, y cualquier.swiftque pongas dentro entra en la app sin que tengas que registrarlo en ningún sitio. MarcadorAppTestsyMarcadorAppUITestsson otras dos carpetas sincronizadas, una por cada grupo de pruebas.
Lo que Xcode genera se queda directamente en la carpeta del código. Casi todo lo que escribas tú irá en carpetas con nombre, cada una con lo que va junto; en la raíz solo queda lo que une la app entera.
Ahora, la barra de herramientas de arriba: en el centro tiene el selector del scheme (MarcadorApp) y, justo al lado, el del destino (dónde se ejecuta la app: un simulador, un iPhone conectado…). A la izquierda de los selectores está el botón de Run, el triángulo.
Los tres paneles que vas a usar más: el Project navigator (Cmd+1), el Issue navigator (Cmd+5), que lista errores y avisos de compilación, y el Report navigator (Cmd+9), que guarda el registro de cada compilación y de cada ejecución de pruebas. La consola de la app sale en el Debug area, el panel de abajo: View → Debug Area → Activate Console (Cmd+Shift+Y).
Paso 3 · Ejecuta la plantilla tal como viene
Objetivo: ver la app de la plantilla en el simulador antes de cambiar nada, para saber que tu Xcode funciona.
- En el selector de destino (junto a
MarcadorApp), despliega la lista y elige un iPhone de la sección de simuladores: el que tengas (la guía usa iPhone 17, que pide iOS 26; con un runtime anterior te saldrá, por ejemplo, un iPhone 16). Esa lista sale de los simuladores que instalaste en Instalar Xcode y el simulador; desde la Terminal puedes verla conxcrun simctl list devices available. Si la lista está vacía y ves un botón Get, falta el runtime de iOS: vuelve a esa lección. - Pulsa el botón Run (el triángulo) o Cmd+R. La primera compilación tarda un rato (de uno a varios minutos); abajo, en el centro de la barra de herramientas, Xcode va diciendo qué hace. Termina con Build Succeeded.
- Se abre la app Simulator con un iPhone y, dentro, la app: un globo terráqueo y el texto «Hello, world!».
- Para pararla, el botón cuadrado de la barra de herramientas o Cmd+. (Cmd y punto).
La pantalla que ves está en ContentView.swift. Ábrela (clic en el Project navigator): es un struct ContentView: View con un VStack, una Image y un Text("Hello, world!"). Aún no hace falta entenderlo: lo reemplazarás en la lección siguiente y SwiftUI: primeros pasos lo explica a fondo.
Paso 4 · Firma, identificador y versión mínima
Objetivo: ajustar la versión mínima de iOS del proyecto, y el nombre, el identificador y la versión mínima del target de la app, y elegir un Team.
Selecciona el icono azul MarcadorApp en el Project navigator. En el editor aparecen dos listas: PROJECT y TARGETS. Elige, bajo TARGETS, el target MarcadorApp (el de la app, no los de pruebas). Arriba del editor hay pestañas: General, Signing & Capabilities, Info, Build Settings…
El Team. Dónde se elige:
- Pestaña Signing & Capabilities.
- Casilla Automatically manage signing marcada: Xcode crea y renueva los certificados por ti.
- Desplegable Team: la lista ofrece tu Personal Team, Add an Account… o None. Elige tu Personal Team o déjalo en None; las lecciones siguientes lo llaman «el Team que elegiste en el paso de firma (o ninguno)».
El nombre y el identificador: pestaña General, apartado Identity: Display Name Marcador (el nombre bajo el icono de la app) y Bundle Identifier com.sebastiannarvaez.marcador. El identificador también se ve en Signing & Capabilities: son el mismo ajuste en dos sitios.
La versión mínima, en dos sitios. Los dos de pruebas (MarcadorAppTests y MarcadorAppUITests) no la toman del ajuste de la app, sino del proyecto:
- Bajo PROJECT (no bajo TARGETS), elige
MarcadorApp, pestaña Info, apartado Deployment Target: pon 18.0 en iOS Deployment Target. Los menús pueden cambiar un poco según tu versión de Xcode; si no lo encuentras, en la pestaña Build Settings del proyecto buscaIPHONEOS_DEPLOYMENT_TARGETy pon18.0. - Bajo TARGETS,
MarcadorApp, pestaña General, apartado Minimum Deployments: elige 18.0 en el desplegable.
Los tres ajustes de compilación que Xcode ya dejó puestos, y que verás en lecciones posteriores, están en la pestaña Build Settings (escribe el nombre en el buscador de arriba a la derecha):
| Ajuste (nombre en Build Settings) | Valor | Qué hace |
|---|---|---|
Swift Language Version (SWIFT_VERSION) | 5 | Modo de lenguaje Swift 5 para la app; Torneo compila en Swift 6 y los dos modos conviven |
Default Actor Isolation (SWIFT_DEFAULT_ACTOR_ISOLATION) | MainActor | Todo el código de la app es @MainActor sin escribirlo. Solo está en el target de la app: ni los de pruebas ni el paquete Torneo lo llevan |
Generate Info.plist File (GENERATE_INFOPLIST_FILE) | Yes | El Info.plist es la ficha que describe la app al sistema (nombre, versión, permisos); aquí no hay fichero: se genera en cada compilación |
Punto de control
- Pulsa Cmd+R: la app de la plantilla arranca en el simulador, con el globo y «Hello, world!». Bajo su icono, al salir al inicio del simulador, pone «Marcador».
- Selecciona el icono azul → target
MarcadorApp→ General: Bundle Identifier escom.sebastiannarvaez.marcadory Minimum Deployments,18.0. Bajo PROJECT →MarcadorApp→ Info, iOS Deployment Target también es18.0. - En Build Settings ves
SWIFT_DEFAULT_ACTOR_ISOLATIONenMainActor. - Tu Playground muestra las tres líneas del ejercicio: la app de iOS 17 no compila y las de 18 y 26 sí.
Comprueba lo que entendiste
5 preguntas · necesitas 4 para completar la lección
1.Al pulsar Run o Test, ¿qué decide qué targets se compilan y con qué configuración?
2.¿Por qué puedes ejecutar la app en el simulador sin elegir un Team?
3.El paquete
Torneodeclara.iOS(.v18). ¿Qué versión mínima de iOS puede pedir la app que lo usa?4.Con un simulador de iOS 18 y la versión mínima de iOS puesta solo en el target de la app, Cmd+U dice que el target de pruebas pide iOS 26.2. ¿Qué falta?
5.¿Qué es el bundle identifier de una app de iOS y a qué equivale en Android?