Mejores Practicas
## Objetivos de Aprendizaje
- Seguir guias de estilo de Swift
- Escribir codigo limpio y mantenible
- Usar Xcode efectivamente
- Dominar modismos de Swift
## Convenciones de Nomenclatura
### Tipos y Protocolos
```swift
// Usar PascalCase para tipos y protocolos
struct PerfilUsuario {}
class GestorRed {}
protocol FuenteDatos {}
enum MetodoHTTP {}
// Nombres de protocolos describen comportamiento
protocol Lector {}
protocol Escritor {}
```
### Variables y Funciones
```swift
// Usar camelCase para variables y funciones
let nombreUsuario = "Alicia"
var estaAutenticado = false
func obtenerUsuario() {}
func calcularTotal() {}
```
### Constantes
```swift
// Constantes a nivel de modulo usan camelCase
let maximoReintentos = 3
let tiempoLimitePredeterminado: TimeInterval = 30
// Pero casos de enum usan camelCase
enum Resultado {
case exito
case fracaso
}
```
### Detalles Privados
```swift
class Usuario {
// Publico
var nombre: String
// Privado - el prefijo underscore es opcional
private var _datosCacheados: String?
private var idInterno: UUID?
}
```
## Organizacion del Codigo
### Estructura de Archivos
```swift
// 1. Imports
import Foundation
import UIKit
// 2. Declaracion de Clase/Struct
// 3. Propiedades
// 4. Inicializacion
// 5. Metodos
// 6. Extensiones
// 7. Ayudantes privados
```
### Conformidad a Protocolos
```swift
class MiControladorVista: UIViewController {
// Poner conformidad a protocolo en extension
}
extension MiControladorVista: UITableViewDataSource {
func tablaView(_ tablaView: UITableView, numeroDeFilasEnSeccion seccion: Int) -> Int {
return 0
}
}
extension MiControladorVista: UITableViewDelegate {
func tablaView(_ tablaView: UITableView, didSeleccionarFilaAt indicePath: IndexPath) {
// Manejar
}
}
```
## Modismos de Swift
### Preferir let sobre var
```swift
// Bien
let nombre = "Alicia"
let conteo = elementos.conteo
let filtrado = elementos.filter { $0 > 0 }
// Cuando se necesita mutabilidad
var mutable = [1, 2, 3]
mutable.append(4)
```
### Preferir guard sobre if let
```swift
// Bien
func procesar(nombre: String?) {
guard let nombre = nombre else { return }
// Usar nombre aqui
}
// Evitar anidamiento
func procesar(nombre: String?) {
if let nombre = nombre {
if nombre.conteo > 0 {
// Anidamiento profundo - evitar esto
}
}
}
```
### Usar Trailing Closures
```swift
// Bien
numeros.map { $0 * 2 }
URLSession.shared.dataTask(with: url) { datos, _, _ in
// Manejar
}.resume()
```
### Valores por Defecto
```swift
// Usar nil coalescing
let nombreMostrar = usuario.nombre ?? "Anonimo"
// O parametro por defecto
func saludar(_ nombre: String = "Mundo") {
print("Hola, \(nombre)!")
}
```
## Manejo de Errores
### Preferir Throws sobre Opcionales
```swift
// Bien - cuando el fallo tiene significado
func parsearJSON(_ datos: Data) throws -> [String: Any] {
guard let json = try JSONSerialization.jsonObject(with: datos) as? [String: Any] else {
throw ErrorParseo.formatoInvalido
}
return json
}
// Usar try? cuando el fallo no necesita detalles
if let _ = try? validar(email) {
// Valido
}
```
### Tipo Result para Callbacks
```swift
func obtenerUsuario(completacion: @escaping (Result) -> Void) {
// Exito
completacion(.exito(usuario))
// Fracaso
completacion(.fracaso(ErrorRed.sinConexion))
}
```
## Control de Acceso
### Minimizar Exposicion
```swift
// Bien - exponer solo lo necesario
public class ClienteAPI {
private let urlBase: URL
private var respuestasCacheadas: [URL: Data] = [:]
}
// Evitar
class Persona {
var nombre: String = "" // Publico por defecto
var edad: Int = 0 // Deberia ser privado?
var ssn: String = "" // Definitivamente privado
}
```
### Preferir private sobre fileprivate
```swift
class MiClase {
// private - solo accesible dentro de esta clase
private var ayudante: Ayudante
// fileprivate - solo dentro del mismo archivo
fileprivate var estadoCompartido: String = ""
}
```
## Opcionales
### Desencapsulado Seguro
```swift
// Bien
if let valor = opcional {
usar(valor)
}
// Mejor para salida anticipada
func procesar() {
guard let valor = opcional else { return }
usar(valor)
}
// Nil coalescing para valores por defecto
let nombreMostrar = usuario.nombre ?? "Anonimo"
```
### Evitar Force Unwrap
```swift
// Mal
let nombre = opcional!
// Alternativas buenas
if let nombre = opcional { }
guard let nombre = opcional else { }
let nombre = opcional ?? "pordefecto"
```
## Rendimiento
### Tipos Valor Cuando Corresponda
```swift
// Usar struct para datos simples
struct Punto {
var x: Double
var y: Double
}
// Usar class para identidad compartida
class Persona {
var nombre: String
// Compartido en toda la app
}
```
### Propiedades Lazy
```swift
class ImportadorDatos {
// Operacion pesada solo cuando se necesita
lazy var datos: Data = {
return cargarDatosPesados()
}()
}
```
### Evitar Ciclos de Retencion
```swift
// Usar weak para delegates
weak var delegate: MiDelegate?
// Usar listas de captura en closures
algunLlamado { [weak self] resultado in
self?.manejar(resultado)
}
```
## Pruebas
### Inyeccion de Dependencias
```swift
// Bien - testeable
class ServicioRed {
let sesion: URLSession
init(sesion: URLSession = .shared) {
self.sesion = sesion
}
}
// Testeable con mock
let sesionMock = MockURLSession()
let servicio = ServicioRed(sesion: sesionMock)
```
### Diseno Orientado a Protocolos
```swift
protocol ProtocoloAlmacenamiento {
func guardar(_ datos: Data) throws
func cargar() throws -> Data
}
class AlmacenamientoArchivo: ProtocoloAlmacenamiento { }
class AlmacenamientoUserDefaults: ProtocoloAlmacenamiento { }
```
## Documentacion
### Comentarios
```swift
// Linea unica para explicacion breve
/*
Multi-linea para explicacion mas larga
o comentarios detallados
*/
/**
Comentario de documentacion (usado por Xcode)
*/
```
### Comentarios MARK
```swift
class MiClase {
// MARK: - Propiedades
var nombre: String
// MARK: - Inicializacion
init() { }
// MARK: - Metodos Publicos
func metodoPublico() { }
// MARK: - Metodos Privados
private func metodoPrivado() { }
}
```
## Consejos de Xcode
### Atajos de Teclado
| Accion | Atajo |
|--------|-------|
| Ejecutar | Cmd+R |
| Compilar | Cmd+B |
| Limpiar | Cmd+Shift+K |
| Buscar | Cmd+F |
| Reemplazar | Cmd+Alt+F |
| Ir a Definicion | Cmd+Clic |
| Auto-indentar | Ctrl+I |
| Comentar | Cmd+/ |
### Navegacion
| Accion | Atajo |
|--------|-------|
| Abrir Rapidamente | Cmd+Shift+O |
| Navegador | Cmd+0 |
| Editor Asistente | Cmd+Alt+Enter |
| Abrir en Pestana | Cmd+Enter |
### Refactorizacion
- Cmd+Shift+E: Refactorizar
- Extraer Metodo: Seleccionar codigo, clic derecho > Refactorizar
- Renombrar: Ctrl+Cmd+E
## Patrones Comunes
### Singleton
```swift
final class Singleton {
static let compartido = Singleton()
private init() {
// Inicializacion privada
}
}
```
### Metodo de Fabrica
```swift
class Boton {
func crearBoton(estilo: EstiloBoton) -> UIButton {
let boton = UIButton(type: .system)
boton.setTitle(estilo.titulo, for: .normal)
return boton
}
}
```
### Patron Builder
```swift
class ConstructorUsuario {
private var nombre: String = ""
private var edad: Int = 0
func establecerNombre(_ nombre: String) -> ConstructorUsuario {
self.nombre = nombre
return self
}
func establecerEdad(_ edad: Int) -> ConstructorUsuario {
self.edad = edad
return self
}
func construir() -> Usuario {
return Usuario(nombre: nombre, edad: edad)
}
}
```
## Resumen
- Usar PascalCase para tipos, camelCase para variables
- Preferir `let` sobre `var`, `struct` sobre `class` cuando corresponda
- Usar `guard` para salida anticipada y desencapsulado opcional
- Minimizar exposicion con control de acceso apropiado
- Evitar desencapsulado y conversion forzada
- Usar protocolos para abstraccion y pruebas
- Documentar con comentarios MARK y documentacion Swift
- Aprender atajos de Xcode para productividad
- Escribir codigo testeable con inyeccion de dependencias
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →