Categories
Swift Development

100 Dias de Swift Día 7

Estas son mis notas para el curso de swift https://www.hackingwithswift.com/100

Entrada anterior

“Energy and persistence conquer all things”

Benjamin Franklin 

«Energía y tenacidad, conquistan todas las cosas»

Benjamin Franklin

Closures, part two

Esta es la segunda parte del tema de closures y aquí es donde las cosas se vuelven mas complejas.

Using closures as parameters when they accept parameters

Anteriormente usamos «() -> Void» para pasar un closure que no acepta parámetros y nos regresa nada, pero ahora especificaremos un tipo de valor dentro de los paréntesis

func viajar(acción: (String) -> Void) {
     print("Estoy listo para partir.")
     acción("CDMX")
     print("¡Ya llegue!")
 }

viajar { (lugar: String) in
    print("voy para \(lugar) en mi auto")
}

Recuerda los nombres de los parámetros en los closures se indican dentro de las llaves

Using closures as parameters when they return values

De la misma manera podemos remplazar Void por un valor para que nuestra Closure regrese y luego usarlo dentro de la función.

func viajar(acción: (String) -> String) {
     print("Estoy listo para partir.")
     let adondeVas = acción("CDMX")
     print(adondeVas)
     print("¡Ya llegue!")
 }

viajar { (lugar: String) -> String in
    return "voy para \(lugar) en mi auto"
}

Shorthand parameter names

Hemos creado una función que acepta un closure como parámetro que a su vez acepta una String parámetro y regresa una String

Como Swift sabe que nuestro parámetro es una String y que estamos regresando una String podemos simplificar nuestra expresión de esta forma

//Sin especificar el tipo de parametro
viajar { lugar -> String in
    return "voy para \(lugar) en mi auto"
}

//Sin especificar el tipo de valor que retorna
viajar { lugar  in
    return "voy para \(lugar) en mi auto"
}

Closures with multiple parameters

También es posible utilizar Closures con multiples parámetros

func viajar(acción: (String, Int) -> String) {
     print("Estoy listo para partir.")
     let adondeVas = acción("CDMX", 60)
     print(adondeVas)
     print("¡Ya llegue!")
 } 

viajar { (lugar, km)  in
    return "voy para \(lugar) a \(km)km/hora en mi auto"
}

//version simplificada
viajar {
    return "voy para \($0) a \($1)km/hora en mi auto"
}
 

Como puedes ver en el segundo ejemplo es incluso posible simplificar aun mas la expresión usando nombres de parámetros acortados «$0» y «$1» aun así muchas personas evitan usarlos pues pueden dificultar la legibilidad de tu código.

Returning closures from functions

De la misma forma que podemos pasar closures como parámetros en una función, también podemos devolverlas como respuesta de una función.

La sintaxis aquí es un poco confusa por que usamos dos veces «->»

En el siguiente ejemplo creamos la función viajar que no acepta parámetros pero regresa un closure, este closure acepta una string y regresa nada como respuesta.

func viajar() -> (String) -> Void {
    return {
        print("Voy a \($0)")
    }
}
//función sin parámetros devuelve como respuesta un closure que acepta una string y devuelve como respuesta nada 

Ahora podemos llamar a viajar para obtener esa closure y luego usarla

let resultado = viajar()
resultado("Guadalajara")

Ahora técnicamente podemos llamar directamente a la closure pero la verdad no es muy recomendado


let resultado = viajar()("Guadalajara")

Capturing values

Si usas un valor externo dentro de tu closure, swift lo captura, esto quiere decir que lo guarda junto tu closure.

Modifiquemos nuestra closure en viajar para contar cuantas veces es llamada.

func viajar() -> (String) -> Void {
    var contador = 1
    return {
        print("Por \(contador)vez  Voy a \($0)")
        contador += 1
    }
}

Ahora cuando llamemos este closure podremos ver que el valor del contador es conservado

let resultado = viajar()
 
resultado("Guadalajara")
resultado("Guadalajara")
resultado("Guadalajara")
¡Genial! ¿no?

Resumen

Puedes asignar closures a variables y luego llamarlas

Los closures pueden aceptar parámetros y responder con valores, como una función normal

Puedes pasar closures como parámetros en una función, estas closures pueden tener sus propios parámetros y regresar respuestas con sus propios valores

Si el ultimo parámetro de una fungino es una closure, puedes usar una sintaxis reducida

Swift provee de manera automática nombres cortos para los parámetros de tu closure como $0 y $1

Sí usas valores externos en una closure, estos son capturados y guardados. para que puedas hacer referencia a ellos después

//y así terminamos con closures un tema bastante complejo pero que es usado mucho en SwiftUI veremos que tal en UIKIT

Referencias

https://www.hackingwithswift.com/100/7

https://www.hackingwithswift.com/100

Proximo día

Categories
Swift Development

100 Dias de Swift Día 6

Día 6

Estas son mis notas para el curso de Swift https://www.hackingwithswift.com

Entrada anterior

“you can’t expect to hit the jackpot if you don’t put a few nickels in the machine.”

Flip Wilson’s law

«No esperes darle al premio gordo, sin antes poner un par de monedas en la maquina»

Flip Wilson’s law

Closures, part one

Este tema es la principal razón por la que decidí volver a a retomar las lecciones básicas de Swift este tema se me había complicado bastante y no lo entendí al 100% la primera vez

Creating basic closures

Swift nos deja crear funciones como si fueran cualquier otro tipo de dato como Strings o Int, asignarla a una variable e incluso pasar esta función a otra función como parámetro.

Comencemos un simple ejemplo

let manejar = {
    print("Estoy manejando un auto")
}

Esto crea una función sin nombre que ahora podemos llamar a esa función con el nombre de la constante que creamos

manejar()

Accepting parameters in a closure

Aceptar parámetros en un «closure» es posible pero de forma un poco diferente al de una función , los parámetros se listan dentro de las llaves, dentro de paréntesis y seguidos de la palabra reservada «in»

let manejar = { (destino: String) in 
    print("Estoy manejando a \(destino) en un auto")
}

Una de las diferencias entre closures y functions es que closures no necesitan etiquetas para los parámetros

Returning values from a closure

Closures también pueden regresar valores, de manera similar a los parámetros, solo debemos indicarlos antes del «in» y usar «return» como en una función normal

 let manejar = { (destino: String) -> String in
     return "Estoy manejando a \(destino) en un auto"
 }
 
let mensaje = manejar("Pachuca")
print(mensaje)

Closures as parameters

Los closures pueden ser usados como parámetros dentro de una función, pero la sintaxis puede ser complicada

let manejar = {
    print("Estoy manejando un auto")
}

Si queremos pasar ese closure en una función debemos especificar el parámetro como «( ) -> Void». Eso significa que que no acepta parámetros y no regresa nada.

 let manejar = {
     print("Estoy manejando en un auto")
 }
 
 func viajar(acción: () -> Void) {
     print("Estoy listo para partir.")
     acción()
     print("¡Ya llegue!")
 }

 viajar(acción: manejar)

Trailing closure syntax

Si el ultimo parámetro de tu función es un closures Swift te permite pasarlo de manera especial esto es llamado trailing closure syntax. En lugar de pasar tu closure como un parámetro, lo pasas directo después de la función entre llaves.

 func viajar(acción: () -> Void) {
     print("Estoy listo para partir.")
     acción()
     print("¡Ya llegue!")
 }
 
 viajar(){
    print("Estoy viajando en un Barco")
 }

De hecho como esta función no tiene ningún parámetro podemos omitir los paréntesis

 viajar{
    print("Estoy viajando en un Avión")
 }

// Aquí termina la parte 1 mañana continuare la parte 2 y  hare el resumen de ambas 

Referencias

https://www.hackingwithswift.com/100

https://www.hackingwithswift.com/100/6

Proximo día

Categories
Swift Development

100 Dias de Swift Día 5

Día 5

Estas son mis notas para el curso de Swift https://www.hackingwithswift.com

Entrada anterior

“Dennis Ritchie (the creator of the C programming language) encouraged modularity by telling all and sundry that function calls were really, really cheap in C. Everybody started writing small functions and modularizing. Years later we found out that function calls were still expensive, and our code was often spending 50% of its time just calling them. Dennis had lied to us! But it was too late; we were all hooked…”

Steve Johnson

“Dennis Ritchie (el creador del lenguaje de programación C) alentó la modularidad diciendo a todos que cada una de las llamadas a funciones eran realmente muy rápidas en C. Todos comenzaron a escribir pequeñas funciones y modularizar. Años después descubrimos que las llamadas a funciones seguían siendo lentas, y nuestro código a menudo pasaba el 50% de su tiempo simplemente haciendo las llamadas. ¡Dennis nos había mentido! Pero era demasiado tarde; todos estábamos enganchados … “

Steve Johnson

Esta cita es de tiempos mas oscuros cuando las llamadas a funciones eran algo lento

Writing functions

Las funciones nos permiten reciclar código y usarlo en varios lugares después, repertir código es normalmente una mala idea.

Para crear una función usamos la palabra reservada «func» luego el nombre de tu función, luego abrimos y cerramos paréntesis como en el siguiente ejemplo.

func bienvenida() {
 let mensaje = "Bienvenido a mi App"
 print(mensaje)
}

ahora podemos correr este código solo usando «bienvenida()»

bienvenida()

Correr el código de una función también se conoce como Llamar a una función

Accepting parameters

Las funcione se vuelven mas poderosas cuando permitimos que acepten parámetros para hacer esto solo debemos especificar entre paréntesis el nombre del parámetro y el tipo de dato.

func bienvenida(nombre: String) {
 let mensaje = "Bienvenido \(nombre) a mi App"
 print(mensaje)
}

bienvenida(nombre: "Misael")
bienvenida(nombre: "Juan")

Este código puede imprimir un mensaje de saludo personalizado para cada usuario

Otro ejemplo para sumar números

func suma(numeroA: Int , NumeroB: Int){
    let suma = numeroA + NumeroB
    print(suma)
}

suma(numeroA: 4, NumeroB: 5)
suma(numeroA: 12, NumeroB: 10)

Returning values

Regresar valores

Así como podemos proporcionar parámetros podemos devolver valores para hacer esto usamos « ->» y ademas el tipo de dato, para devolver el valor usamos «return»

func suma(numeroA: Int , NumeroB: Int) -> Int{
     let suma = numeroA + NumeroB
     return suma
     // ningún código sera ejecutado después del return
 }

Ahora podemos usar el valor que nos regresa la función para algo mas

let resultadoDeLaSuma = suma(numeroA: 4, NumeroB: 12)
print("El resultado de la suma es \(resultadoDeLaSuma)")

Parameter labels

Etiquetas para los parámetros

Podemos usar las etiquetas de los parámetros para hacer mas legible nuestro código, para eso solo suministramos dos nombres separados por un espacio. El primero se usa fuera de la función y el otro de manera externa.

 func bienvenida(a nombre: String) {
  let mensaje = "Bienvenido \(nombre) a mi App"
  print(mensaje)
 }

bienvenida(a: "Misael")

Omitting parameter labels

Ahora habrás notado que funciones como «print(“Hello”)» no tienen una etiqueta en el parámetro, en ciertas ocasiones es también mas legible omitir el nombre del parámetro por ejemplo

 func saludarA(_ nombre: String) {
  let mensaje = "Bienvenido \(nombre) a mi App"
  print(mensaje)
 }

saludarA("Misael")
saludarA("Juan")

Esto puede hacer mas legible nuestro código, pero también podría hacerlo mas confuso por ejemplo

ponerAlarma(5)

Este código es bastante confuso ¿La alarma es para las 5am o 5pm o es para dentro de 5 minutos u horas o días?

Así que piensa con cuidado como hacer tu código mas legible

Default parameters

Podemos suministrar valores por default para nuestras funciones solo agregando «=» después del tipo de dato

func saludarA(_ nombre: String, amablemente: Bool = true) {
    var mensaje = ""
    if amablemente == true {
        mensaje = "Bienvenido \(nombre) a mi App"
    } else {
        mensaje = "¡Oh no, es \(nombre) de nuevo 🤢!"
    }
    
  print(mensaje)
 }

saludarA("Misael")
saludarA("Juan", amablemente: false)

Como ves podemos llamar a esta función de dos maneras diferentes

Variadic functions

Algunas funciones pueden usar varios parámetros del mismo tipo, para eso solo añadimos «…» después del tipo de dato, swift creara un Array con los valores que suministremos

func calcularCuadrados(numeros: Int...) {
    for numero in numeros {
        print("\(numero) al cuadrado es \(numero * numero)")
    }
}

calcularCuadrados(numeros: 1,2,3,4,5,6,7,8,9,10)

Writing throwing functions

Cuando se suministra un dato erróneo a una función esta puede fallar, swift nos deja «tirar» errores cuando algo sale mal, usando la palabra reservada «throw»

Para empezar debemos crear un enum con los tipos de error

enum errorDeContraseña: Error {
    case muyObvia
}
func revisarContraseña(_ contraseña: String) throws -> Bool {
    if contraseña == "contraseña" {
        throw errorDeContraseña.muyObvia
    }

    return true
}
Sin embargo podemos ver que usar la función de esta forma nos muestra una alerta

y así podemos saber exactamente en que fallo nuestra función

Running throwing functions

Ahora bien a Swift no le gusta tener errores cuando llamamos a una función así que necesitamos llamarla de manera segura, para hacer esto usamos las palabras reservadas «do» para iniciar un código que podría causar problemas, «try» frente a la función que puede causar problemas, y «catch» para manejar el error de manera mas elegante

 do {
     try revisarContraseña("contraseña")
     print("¡Buena contraseña!")
 } catch {
     print("¿Enserio 😐?")
 }
Ahora todo funciona fluido

Inout parameters

Los parámetros de una función son constantes, si queremos que nuestros parámetros cambien el valor suministrado en lugar de regresar uno nuevo debemos usar «inout» antes del tipo de dato y ademas «&» antes de el nombre de tu variable, que por cierto no puedes usar constates pues tu valor sera cambiado

 func dobleOnada(numero: inout Int) {
     numero *= 2
 }
 
 var miNumero = 10
 dobleOnada(numero: &miNumero)
 
 print(miNumero)
como puedes ver esta función cambia efectivamente el valor de tu variable

Resumen

Las funciones nos permiten reutilizar código

Las funciones aceptan parámetros solo especia a Swift que tipo de parámetros son

Las funciones pueden regresaros valores, solo especifica que tipo de valor deseas recibir

Puedes usar diferentes etiquetas para los parámetros u omitir sus nombres para hacer mas legible tu código

Los parámetros pueden tener valores por default lo cual es util para escribir menos código que tiende a repetirse

Podemos usar parámetros que usen cero o mas valores y Swift los convertirá en un Array

Las funciones pueden arrojar errores (throw errors) pero debemos usarlas con try y catch

Podemos usar inout para cambiar variables dentro de una función, aunque lo mejor es devolver una valor nuevo.

// y bueno eso fue el resumen de funciones, la verdad es que hay algunos temas muy simples como arrojar errores que son muy útiles 

Referencias

https://www.hackingwithswift.com/100

https://www.hackingwithswift.com/100/5

Proximo Día

Categories
Swift Development

100 Dias de Swift Día 4

Día 4

Estas son mis notas del curso hackingwithswift

Entrada anterior

“it’s hardware that makes a machine fast, but it’s software that makes a fast machine slow.”

Craig Bruce

«Es el hardware lo que hace rápida a una maquina, pero el software es lo que la hace lenta.»

Craig Bruce

Loops

Los loops adoptan varias formas pero su mecánica es la misma, un código que se repite hasta que una condición se vuelva falsa

For

El loop mas comun es «For», que itera sobre Arrays y Ranges, cada iteración nueva asigna un elemento a una constante. Por ejemplo en el siguiente Range

let contar = 1...10
for numero in contar {
    print("el numero es \(numero)")
}

super simple verdad, lo mismo con los Arrays

let albums = ["Red", "1989", "Reputation"]

for album in albums {
    print("\(album) esta en Apple Music")
}

Si no necesitas crear ninguna constante puedes hacer el loop de esta manera

for _ in 1...5 {
    print("Hoy no se fia, mañana si")
}

While

«While» es también un loop muy usado, básicamente ejecuta una acción si se cumple la condición

var numero = 1

while numero <= 10 {
    print(numero)
    numero += 1
}

print("Listos o no, allá voy!")

Repeat

Es similar a While solo que la condición va al final esto quiere decir que el código se ejecuta primero y luego verifica la condición

var numero = 1

repeat {
    print(numero)
    numero += 1
} while number <= 20

print("Listos o no, allá voy!")

La mayor diferencia como puedes ver es que el código con «repeat» se ejecutara por lo menos una vez

while false {
//Este código nunca se ejecuta
    print("Esto es falso")
}

repeat {
//Este código se ejecutara una vez
    print("Esto es falso")
} while false

Break

Si quieres salir de un bucle puedes usar «break»

var numero = 1

repeat {
    print(numero)
    if numero == 10 {
      print("Ya me aburrí, Listos o no, allá voy!")
      break
    }
    numero += 1

} while number <= 20

print("Listos o no, allá voy!")

Si tienes loops anidados y quieres salir de ambos puedes usar «break (etiqueta de tu loop principal)»

etiquetaLoopPadre: for i in 1...10 {
    for j in 1...10 {
        let resultado = i * j
        print ("\(i) * \(j) es igual a \(resultado)")

        if resultado == 50 {
            print("Eso es todo")
            break etiquetaLoopPadre
        }
    }
}

Continue

Así como podemos salir de un loop podemos omitir ciertos elementos usando «continue» por ejemplo en el siguiente ejemplo solo imprimimos números pares

for i in 1...10 {
    if i % 2 == 1 {
    //omitir si es primo
        continue
    }

    print(i)
}

Loops infinitos

Los loop infinitos son algo muy común en iOS básicamente son loops que se ejecutan de manera indeterminada, pero ten cuidado recuerda establecer una salida para tu bucle si no se repetirá para siempre.

Lo mas común es poner una condición verdadera en un While

var contador = 0

while true {
    print(" ")
    contador += 1

    if contador == 273 {
        break
    }
}

Resumen

Los loops se repiten hasta que una condición es falsa

Los loops mas comunes son For y While

Puedes omitir usar la constate de For si no la necesitas

Puedes usar Repeat en lugar de While si quieres que tu código se ejecute por lo menos una vez

Para salir de un bucle usa break y para omitir un elemento continue

y por ultimo los loops infinitos necesitan que les suministres una salida para

//y bueno esos son los loops 

Referencias

https://www.hackingwithswift.com/100/4

https://www.hackingwithswift.com/100

Proximo Día

Categories
Swift Development

100 Dias de Swift Día 3

Día 3

Estas son mis notas del curso hackingwithswift

Entrada Anterior

“Computers are like Old Testament gods: lots of rules and no mercy.”

Joseph Campbell

“Las computadoras son como el Antiguo Testamento : Un montón de reglas y sin misericordia .”

Joseph Campbell

Operators and conditions

Operadores y condiciones

Los operadores nos permiten combinar diferentes tipos de datos, los operadores son símbolos matemáticos, como «+» y «-», en Swift hay muchos de estos.

Empecemos con dos variables de ejemplos

let primerPuntaje = 12
let segundoPuntaje = 8

Podemos sumar y restar de esta forma

let total = primerPuntaje + segundoPuntaje
let diferencia = primerPuntaje - segundoPuntaje

y podemos dividir y multiplicar usando «*» y «/» :

let producto = primerPuntaje * segundoPuntaje
let división = primerPuntaje / segundoPuntaje

Swift tiene un operador especial para calcular el residuo de una operación, calcula cuántas veces un numero cabe en otro, entonces regresa el valor que queda.

let residuo = 25 % segundoPuntaje
El resultado es 1

Operator overloading

Operator overloading es una forma sofisticada de decir que lo que el operador hace depende del valor con el que lo usemos aquí un ejemplo + puede sumar números

let sentidoDeLaVidaElUniversoYTodoLoDemás = 42
let elDobleSentidoDeLaVidaElUniversoYTodoLoDemás = 42 + 42

//disculpa la fuerte referencia a The Hitchhiker's Guide to the Galaxy, de Douglas Adams así venia en el curso 😅

Pero también puede unir cadenas de texto

let celos = "Estos celos me hacen "
let acción =  celos + "Daño"

Incluso podemos unir Arrays

let primeraMitad = ["Jorge", "Hernán"]
let segundaMitad = ["Eduardo", "Luis", "Óscar"]

let 🐯Norte =  primeraMitad + segundaMitad

Recuerda que Swift no permite mezclar diferentes tipos de datos así que no trates de sumar un String y un Int

Compound assignment operators

Swift permite combinar los operadores con un cambio de valor, de esta forma podemos reasignar valores en un solo paso, usando los operados que ya conocemos «+,-,*,/» pero con «=» al final

Por ejemplo

var puntaje = 95
puntaje -= 5

De forma similar podemos combinar dos Strings en un paso

var refrán = "Camarón que se duerme"
refrán += " se lo lleva la corriente"

Comparison operators

Estos operadores funciona mas o menos como en matemáticas

let primerPuntaje = 6
let segundoPuntaje = 4

hay dos operadores para revisar igualdad:

« == » revisa que dos valores sean iguales y « != » que se pronuncia no iguales y revisa que dos valores no sean el mismo

primerPuntaje == segundoPuntaje
primerPuntaje != segundoPuntaje

Hay cuatro operadores para comparar valores como en matemáticas

« > » mayor que

« < » menor que

« >= » mayor o igual que

« <= » menor o igual que

primerPuntaje >= segundoPuntaje
primerPuntaje <= segundoPuntaje

Ademas estos funciona con Strings también, ya que las Strings tienen un orden alfabético natural

"Taylor" <= "Swift"

Conditions

Condiciones ahora que conocemos los operadores podemos usar declaraciones condicionales con « if »

Para demostrar esto usaremos una de las funciones de Swift llamada « print( )» que nos sirve para mostrar texto

Por ejemplo podemos usar una condición cuando se llega al puntaje mas alto para imprimir un mensaje de victoria

let primerPuntaje = 30
let segundoPuntaje = 70

if primerPuntaje + segundoPuntaje == 100 {
 print("Ganaste 🥳")
}

El código entre las llaves « { } » se ejecutara cuando la condición sea cierta, y puedes ademas proveer una alternativa si la condición retorna falso usando « else »

if primerPuntaje + segundoPuntaje == 100 {
 print("Ganaste 🥳")
} else {
 print("Sigue intentando")
}

Puedes ademas proveer mas condiciones usando « else if»

if primerPuntaje + segundoPuntaje == 100 {
 print("Ganaste 🥳")
} else if primerPuntaje + segundoPuntaje == 50 {
 print("Bien vas a la mitad sigue intentando")
}else {
 print("Sigue intentando")
}

Combining conditions

Swift tiene tiene dos operadores para combinar operadores estos son « && » (pronunciado «y») y « || » (pronunciado « o » )

Por ejemplo

let edad1 = 16
let edad2 = 21
if edad1 > 18 && edad2 > 18 {
 print("Ambos son mayores de edad")
}

En esta caso Swift no ejecutara el código pues la primera condición no es verdadera de hecho ni siquiera revisara la segunda pues la primera es falsa

Por otro lado el operador « Or » evaluara las segunda condición incluso si la primera no es verdadera

if edad1 > 18 || edad2 > 18 {
 print("Al menos uno es mayor de edad")
}

Aunque se pueden usar mas de un && y || en una condición lo mejor es mantener las cosas simples para facilitar la lectura

The ternary operator

Operadores terciarios

Existe un operador muy poco usado llamado operador terciario « : »

//Bueno el curso decía eso pero yo lo uso mucho en SwiftUI 

Aqui un ejemplo

print(edad1 > 18 && edad2 > 18 ? "Ambos son mayores de edad" : "Alguno de ellos no lo es")

Switch statements

Si tienes muchas condiciones if y else es mejor usar otra estructura llamada « switch case » veamos el siguiente ejemplo

let clima = "soleado"

Se puede usar switch en un bloque para para imprimir diferentes mensajes

switch clima {
case "lluvia":
    print("Lleva un paraguas")
case "nieve":
    print("Usa un abrigo ")
case "soleado":
    print("Usa protector solar")
default:
    print("¡Disfruta tu día!")
}

En el ultimo ejemplo « default » es requiero por Swift para asegurarnos que se cubran todos los posibles casos

Swift solo correrá el código dentro de cada caso si quieres que Swift pase al siguiente caso usa « fallthrough »

switch clima {
case "lluvia":
    print("Lleva un paraguas")
case "nieve":
    print("Usa un abrigo ")
case "soleado":
    print("Usa protector solar")
    fallthrough
default:
    print("¡Disfruta tu día!") 
}

Range operators

Swift nos ofrece dos maneras de hacer rangos « ranges » para eso tenemos los operados « ..< » y « … » el primer crear un rango de valores excluyendo el ultimo valor, el segundo crear un rango de valores que incluye el ultimo valor

Por ejemplo

let rango = 1..<5
//contiene los números 1,2,3 y 4

let rango2 = 1...5
//contiene los valores 1,2,3,4 y 5

Los rangos pueden ser usados en un switch

let puntaje = 85

switch puntaje {
case 0..<50:
    print("fallaste")
case 50..<85:
    print("lo hiciste bien")
default:
    print("¡Lo hiciste genial!")
}

Resumen

Los operados en swift sirven para hacer operaciones aritméticas +,-,*,/

Hay operadores que sirven para modificar tus variables en un paso como += y -=

Puedes usar if, else y else if para correr código en base a una condición

Swift tiene un operador terciario que si bien no es muy conveniente usarlo en bloques de código de Swift es mejor usarlo solo en SwiftUI

Si tenemos varias condiciones es mejor usar una estructura switch

Podemos crea rangos usando ..< y … dependiendo de cual usemos el ultimo numero podría excluirse

//y bueno ese fue le día 3

Referencias

https://www.hackingwithswift.com/100/3

https://www.hackingwithswift.com/100

Proximo Día

Categories
Swift Development

100 Dias de Swift Día 2

Día 2

Estas son mis notas del curso del curso hackingwithswift

Entrada Anterior

“when the going gets tough, everyone leaves.”

Lynch’s Law

«Cuando las cosas se ponen difíciles, todos se van.»

Lynch’s Law 

Arrays

Matrizes

Los Arrays son una colección de valores que se guardan como si fueran uno.

Por ejemplo la Liga de la Justicia

let batman = "Bruno Días"
let superMan = "Clark Ken"
let wonderWoman = " Diana Prince"

let ligaDeLaJusticia = [batman, superMan, wonderWoman]

Un Array inicia y termina con corchetes « [ ]» , los elementos deben estar separados por comas, y para poder leer los elementos dentro del Array usamos el numero de elemento, comenzando la cuenta desde el cero, por ejemplo para acceder al primer elemento seria así

//Acceder a batman
ligaDeLaJusticia[0]

Si tratas de un leer un valor que no existe en el array por ejemplo ligaDeLaJusticia[3] Swift fallara

Si estas usando type annotations se especifican dentro de los corchetes por ejemplo

let númerosEnteros = [Int]
let númerosDecimales = [Double]
let nombres = [String]

Sets

Colecciones

Los Sets son colecciones de de valores igual que los Arrays. pero con dos diferencias, 1) los elementos no se guardan en ningún orden y 2) ningún elemento se puede repetir

Puedes crear un Set a partír de un Array así:

let colores = Set(["rojo","Azul", "Amarillo"])

Estos valores no se guardan en nigua orden y no puedes acceder a ellos como en un Array, y si tratas de agregar un valor duplicado este se ignorara

Tuples

Tuplas

Las Tuplas permiten guardar varios valores en forma de uno solo, son diferentes de los array en tres cosas 1) no puedes añadir o remover elementos, 2) no puedes cambiar el tipo de dato de los elementos dentro de ella, 3) puedes acceder a los elementos en su interior usando su posición numérica o el nombre, pero swift no te dejara leer números o nombres que no existen.

Ejemplo

var name = (first: "Taylor", last: "Swift")

Luego acceder a los valores por nombre o numero

//accedemos al mismo valor de dos formas diferentes 
name.0
name.first

finalmente recuerda que puedes cambiar los valores dentro pero no su tipo de dato.

Arrays vs Sets vs Tuples

Si bien estos valores podrían parecer iguales tienen distintos usos

Para una colección de valores fijos donde cada elemento tiene una posición o valor único, usamos una Tupla («Tuple»)

Para un colección de valores que debe ser único o donde necesitas revisar rápido que el valor exista, usa un Colección («Set»)

y si necesitas una colección de valores que contenga valors duplicados y el orden importa debería usar una Matriz («Array»)

//Spoiler la mayoría de las veces sera un Array

Dictionaries

Los diccionarios son colecciones de datos igual que las matrices, pero a diferencia de las matrices en lugar de acceder a ellas por medio de su posición numérica, puedes acceder a ellas usando lo que quieras

Por ejemplo podemos usar un String para acceder a las profesiones de un grupo de amigos

var ocupaciones = [ 
    "Misael" : "Programador", 
    "Armando": "Sistemas", 
] 
 
ocupaciones["Armando"] = "Soporte Tecnico" 
 
print(ocupaciones["Armando"]) 

Cuando usamos type anotations podemos declarar el tipo usando dos puntos para separar, por ejemplo:

var diccionarioVacio = [String:Float]() 

Dictionary default values

Valores por defecto para diccionarios

Si tratamos de acceder a un valor que no existe Swift nos regresara un valor «nil» o nulo; nada en absoluto

Pero podemos usar un valor por defecto o «default»

var ocupaciones = [ 
    "Misael" : "Programador", 
    "Armando": "Sistemas", 
] 
  
//esta devuelve nil 
print(ocupaciones["Luis"]) 

//esta devuelve un valor por default

print(ocupaciones["Luis"], default: "Desconocido") 

Creando Colecciones vacías

Para crear una matriz vacía o un diccionario, usamos la sintaxis de iniciación  

let arregloVacio = [String]() 
 
let diccionarioVacio = [String:Float]() 

Si el tipo de información puede ser inferida, se puede escribir de manera simplificada 

var arregloVacio = [String]() 
 
var diccionarioVacio = [String:Float]() 
 
    arregloVacio = [] 
 
    diccionarioVacio = [:] 

Esto es útil cuando queremos cambiar el valor o pasar un valor a una función.  

Enums 

Numeraciones

Sirven para agrupar valores relacionados de forma que son mas fáciles de usar por ejemplo

En lugar de tener :

let resultado = "Fallo"
let resultado2 = "Falla"
let resultado3 = "Fallido"

Esto genera diferentes valores que podrían tener diferentes significados así que los Enums nos ayudan a tener todo mas organizado por ejemplo

enum Resultado {
    case éxito
    case error
}

let resultado = Resultado.error

Con eso evitamos usar diferentes tipos cada vez y nuestro código gana coherencia por lo que es mas fácil de leer y mantener

Valores Asociados a los Enums

Ademas de simplemente guardar valores los Enums pueden tener valores asociados por ejemplo si tenemos un Enum con varias actividades

enum Actividades {
    case aburrido
    case corriendo
    case conversando
    case cantando 
}

Imaginemos ahora que queremos especificar de que estamos hablando

enum Actividades {
    case aburrido
    case corriendo(destino: String)
    case conversando(tema: String)
    case cantando(volumen: Int)
}

let hablando = Actividades.hablando(tema: "Star Wars")

Resumen

«Arrays» ,«Sets» , «Tuples», y «Dictionaries» te permiten guardar grupos de elementos bajo un solo valor, de formas diferentes.

Los Arrays guardan valores en el orden que tu dispongas, se pueden repetir y acceder a ellos por su posición numérica

Los Sets guarda elementos sin ningún orden y no puedes acceder a ellos por su posición numérica

Las Tuples tienen un tamaño fijo, puedes añadir nombres a cada elemento, puedes leer elementos usando posiciones numéricas o los nombres.

Los Dictionaries guardan elementos de acuerdo a sus llaves y puedes leerlos de nuevo usando sus llaves

Los Enums son una forma de agrupar valores relacionados para que no te equivoques al escribirlos, por ejemplo para tipos de errores, adicionalmente puedes relacionarlos con otros valores.

//y bien ese fue el día 2, la verdad casi siempre se usan Arrays y Dictionaries es muy raro que se usen otros a excepción de los Enums que son muy utiles para hacer tu codigo mas legible

Referencias

Todas estas notas están basadas en el curso de hackingwithswift el cual te recomiendo tomar directo en su sitio web

Aqui los enlaces

https://www.hackingwithswift.com/100

https://www.hackingwithswift.com/100/2

Proximo Día

Categories
Swift Development

Core Data & CloudKit in the New MultiPlatform Apps of SwiftUI

On my last post I added Core Data to my SwiftUI Multiplatform project, I a get some feedback on twitter and now I can show your how to add CloudKit to Synchronize data between your devices

if haven’t read that Entry this is the link

So first of all I wanna say thanks to Malcom Hall

He give me a better approach to the Core Data class so now we are using the new @StateObject

Step 1

so first of all we are gonna make a little refactor to our code on the PersistentCloudKitContainer.swift Class

Right now the class looks like this

//
//  PersistentCloudKitContainer.swift
//  ruleOfThree
//
//  Created by Francisco Misael Landero Ychante on 27/06/20.
//

import CoreData
public class PersistentCloudKitContainer {
    // MARK: - Define Constants / Variables
    public static var context: NSManagedObjectContext {
        return persistentContainer.viewContext
    }
    // MARK: - Initializer
    private init() {}
    // MARK: - Core Data stack
    public static var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: "ruleOfThree")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        container.viewContext.automaticallyMergesChangesFromParent = true
        container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        return container
    }()
    // MARK: - Core Data Saving support
    public static func saveContext () {
        let context = persistentContainer.viewContext
        if context.hasChanges {
            do {
                try context.save()
            } catch {
                let nserror = error as NSError
                fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
            }
        }
    }
}

So first of all we are gonna make the class conforms to ObservableObject

...
public class PersistentCloudKitContainer: ObservableObject {
...

Next we are gonna delete the follow lines

...  
// MARK: - Define Constants / Variables
    public static var context: NSManagedObjectContext {
        return persistentContainer.viewContext
    }
    // MARK: - Initializer
    private init() {}
...

next we are changing or var persistentContainer to be lazy and also to return a NSPersistentCloudKitContainer

... 
// MARK: - Core Data stack
    lazy var persistentContainer: NSPersistentCloudKitContainer = {
let container = NSPersistentCloudKitContainer(name: "yourModelDataName")
...

also we are adding the next unwrapper

...
guard let description = container.persistentStoreDescriptions.first else {
            fatalError("No descriptions found")
        }
 description.setOption(true as NSObject, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
...

So this is what we have now

import CoreData
public class PersistentCloudKitContainer: ObservableObject {
    
    // MARK: - Core Data stack
    lazy var persistentContainer: NSPersistentCloudKitContainer = {
        let container = NSPersistentCloudKitContainer(name: "ruleOfThree")
        
        guard let description = container.persistentStoreDescriptions.first else {
            fatalError("No descriptions found")
        }
        
        description.setOption(true as NSObject, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
        
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        container.viewContext.automaticallyMergesChangesFromParent = true
        container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        
        NotificationCenter.default.addObserver(self , selector: #selector(processUpdate), name: .NSPersistentStoreRemoteChange, object: nil)
        
        return container
    }()
    
}

Next we are gonna make a little changes on or @main

import SwiftUI
import CoreData

@main
struct ruleOfThreeApp: App {
    @StateObject var coreData = PersistentCloudKitContainer()
    var body: some Scene {
        WindowGroup {
            ContentView().environment(\.managedObjectContext, coreData.persistentContainer.viewContext)
        }
    }
}

Cool now we can add CloudKit

Step 2

adding Cloud Kit

So now we go to our Project file and were we have our targets we chose iOS, then singning & Capabilities

Now on the button + capability we chose iCloud

Once added we select the CloudKit checkbox and then on containers we select our container if you don’t have one make a new one just write the name and its ready.

We make the same for macOs

Step 3

Now we go to our Data Modelo and under Configurations > Default we open the inspector on the lateral side an chose Use with CloudKit

And that’s all, we now can run or simulator and test, you need to login on the simulator with the same iCloud account

References

Categories
Swift Development

100 Dias de Swift Día 1

Día 1

Después de termina 100daysOfSwiftUI tenia dudas sobre que seguir aprendiendo para mejorar mis habilidades como desarrollador y encontrar un trabajo.

Si bien creo firmemente que SwiftUI es el futuro y lo usare al 100% para mis apps personales y trabajos freelancer, sin duda UIKIT va a estar por aquí un largo rato así que decidí tomar a 100daysOfSwift classic para aprender UIKIT y esta vez ire documentado todo en mi blog personal para tener una referencia en español para mi, espero esto sea de ayuda para quienes se aventuren en este interesante reto.

“the secret to getting ahead is getting started.” 

Mark Twain

«El secreto para avanzar es iniciar»

Mark Twain

Bien para comenzar Abrimos Xcode y creamos un nuevo playground

Variables

Las variables son espacios donde podemos guardar datos, declarar una variable es tan fácilmente como esto;

var saludo = "Hola 🖖🏼"

Algo genial de el ecosistema apple es que podemos usar emojis en todas partes

Ahora como esto es una variable podemos cambiar su valor tan fácilmente como esto;

saludo = "Adios ✌🏼"

No es necesario volver a escribir «var» otra vez por que la variable ya fue creada y ahora solo estamos cambiando su valor

Strings and integers

Cadenas de texto y Números Enteros

Swift es un lenguaje «type-safe» o de escritura segura, eso significa que cada variable debe tener un tipo de dato especifico

En nuestra variable saludo, escribimos un texto por tanto era un variable de tipo «String»

Ahora si queremos escribir la edad de alguien lo hacemos de la siguiente manera

var edad = 24

Eso contiene un numero entero, así que swift le asigna el tipo «Int» un tipo de valor entero.

si queremos escribir números grandes de manera mas legible podemos hacerlo de la siguiente manera

var población = 8_000_000

Strings y Int son diferentes tipos de datos y no se deben mezclar, así pues si bien pudimos asignar un nuevo valor a saludo como «Adios» no podemos asignarle un valor de un tipo diferente como «24».

Multi-line strings

Cadenas de texto multi linea, como ya vimos para crear una variable de tipo String usamos comillas dobles «”» pero para una cadena de texto con multiples lineas debemos usar tres comillas dobles de la siguiente manera:

var texto = """
Este texto
tiene 
multiples 
lineas
"""

Swift espera que las comillas tanto iniciales como finales vayan en su propia linea

Ahora si lo que quieres es simplemente dar formato a tu código para hacerlo mas legible pero no quieres los saltos de linea realmente en tu texto solo tienes que añadir una «\» al final

var texto = """
Este texto \
no tiene \
multiples \
lineas
"""
¿Genial no?

Doubles and booleans

Números con punto decimal y valores verdadero / falso

cada vez que creamos una variable con punto decimal swift nos asigna el tipo Double por ejemplo:

var pi = 3.1416

Double es un tipo diferente de Int y no pueden ser mezclados

Los Booleanos son mucho mas simples son simplemente valores que pueden ser Verdaderos o Falsos (true / false )

Por ejemplo

var ellaTeAma = false
//Lo gracioso es que es verdad 😹
//💔😢

String interpolation

Incrustando variables en texto

Ahora vemos como incrustar variables directo a texto, para hacer es bátanme simple solo usamos «\» seguido de tu variable entre paréntesis «( )»

Por ejemplo

var tuPuntaje = 95
var texto = "Tu puntaje fue \(tuPuntaje)"

como ves es bástate sencillo y lo puedes hacer a veces que quieras

var resultados = "Los resultados del examen \(texto)"

Lo mejor de todo esto es que «string interpolation» no esta limitado a variables si no que podemos correr código también.

Constantes

Las variables son geniales para guardar valores que cambian, ahora bien algunas veces tenemos valores que nunca cambian, en ese caso es mejor usar constantes en swift este tipo es «Let»

Por ejemplo

let yoSoy = "Batman 🦇"

si tratas de modificar ese valor Xcode no te dejara, esto es bueno pues así evitas cambiar constantes por accidente

yoSoy = "Bruno Días"

Type annotations

Especificar el tipo

Swift sigan a cada variable y constate un tipo basado en que valor es dado al momento de ser creada. Por ejemplo aquí swift puede deducir que es un String

var saludo = "Hola 🖖🏼"

y no podrás asignarle un tipo de valor diferente después

esto se llama «type inference» o deducción de tipo

Ahora si quieres ser explícito sobre el tipo de valor de tu variable debes decláralas de esta forma:

let nombre: String = "Bruno Días"
let edad: Int = 50
let altura: Double = 1.78
let elEsBatman: Bool = true

Como nota Baléanos (Booleans) y Enteros (Intergers) tiene el nombre corto «Bool» e «Int»

Resumen

Creamos variables usando «var» y constantes usando «let»

Las cadenas de texto inician y terminan con comillas dobles «”», pero si quires que el texto sea multi linea debes usar tres cada una en su propia linea

Variables de tipo Enteros (Int) guardan números completos, variables con Punto decimal (Double) guarda números con fracciones, y variables de tipo Booleano (Bool) guardan valores verdaderos o falsos (true/false)

«String Interpolation» permite incrustar en el texto variables, constantes y ejecutar código.

Swift usa deducción de tipos (type inference) cuando creas una variable o constate para asignarle un tipo, pero si quieres puedes especificarlo tú mismo.

// y ese fue el resumen del día 1

Referencias

Todas estas notas están basadas en el curso de hackingwithswift

https://www.hackingwithswift.com/100

https://www.hackingwithswift.com/100/1

Proximo día

Categories
Swift Development

Core Data y CloudKit en las nuevas Apps MultiPlatafora de SwiftUI

En mi entrada anterior agregué Core Data a mi App MultiPlaforma ahora veamos si podemos agregar CloudKit para que se sincronice entre nuestros diferentes dispositivos.

Si no has leído el articulo anterior seria bueno que le dieras una leída

Paso 1

En primer lugar tenemos que añadir CloudKit a nuestro proyecto

Para eso nos dirigimos al archivo de nuestro proyecto donde podemos ver nuestros targets

Seleccionamos nuestro target y luego singning & Capabilities

Ahora seleccionamos el botón + capability y elegimos iCloud

Una vez añadido seleccionamos la casilla de CloudKit y en Containers elegimos alguno que ya tengamos o creamos uno nuevo.

Lo mismo para iOS y nuestros demás targets (Exceptuando los test )

También es necesario que en iOS añadamos BackGround Modes

y marcamos Remote Notifications

Paso 2

Así que ahora en nuestra clase PersistentCloudKitContainer.swift vamos cambiar nuestro container

En nuestra clase PersistentCloudKitContainer
let container = NSPersistentContainer(name: "ruleOfThree")

Por este que funciona con CloudKit

let container = NSPersistentCloudKitContainer(name: "ruleOfThree")

y lo mismo en el valor que retorna

...
public static var persistentContainer: NSPersistentContainer = {
...

por este otro

...
public static var persistentContainer: NSPersistentCloudKitContainer = {
...

De forma que nuestra clase queda de la siguiente forma

import CoreData
public class PersistentCloudKitContainer {
    // MARK: - Define Constants / Variables
    public static var context: NSManagedObjectContext {
        return persistentContainer.viewContext
    }
    // MARK: - Initializer
    private init() {}
    // MARK: - Core Data stack
    public static var persistentContainer: NSPersistentCloudKitContainer = {
        let container = NSPersistentCloudKitContainer(name: "ruleOfThree")
        
        guard let description = container.persistentStoreDescriptions.first else {
            fatalError("No descriptions found")
        }
        
        description.setOption(true as NSObject, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
        
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        container.viewContext.automaticallyMergesChangesFromParent = true
        container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        
        
        return container
    }()
    // MARK: - Core Data Saving support
    public static func saveContext () {
        let context = persistentContainer.viewContext
        if context.hasChanges {
            do {
                try context.save()
            } catch {
                let nserror = error as NSError
                fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
            }
        }
    }
}

Paso 3

Ahora el siguiente paso es dirigirnos a nuestro modelo de datos y marcar bajo Configurations > Default y en la vista del inspector marcamos used with CloudKit

Con eso ya podemos correr nuestros simuladores y probar sí están sincronizando. Para esto es necesario loggearnos en nuestros dos simuladores

Paso 4 (Extra)

Bien en este punto CloudKit y la sincronización ya funciona de manera correcta pero quiero añadir algunos ajustes extras para optimizar mis registros, evitar duplicados y poder reordenar los elementos.

así que regresamos a nuestra clase y añadimos el siguiente bloque de código

guard let description = container.persistentStoreDescriptions.first else {
            fatalError("No descriptions found")
}

description.setOption(true as NSObject, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)

Con este código podemos recibir notificaciones cuando algo cambie en nuestro modelo de datos

NotificationCenter.default.addObserver(self, selector: #selector(self.processUpdate), name: .NSPersistentStoreRemoteChange, object: nil)

Ahora gracias a la recomendación de un profesional en twitter encontré una mejor forma de implementar la sincronización

Bien esta nueva implementación tiene muchas mejoras la principal es que ahora utilizamos @StateObject para manejar nuestro modelo de datos

Para eso es necesario hacer que nuestra clase se ajuste a ObservableObject

...
public class PersistentCloudKitContainer: ObservableObject {
...

Así que borramos

...  
// MARK: - Define Constants / Variables
    public static var context: NSManagedObjectContext {
        return persistentContainer.viewContext
    }
    // MARK: - Initializer
    private init() {}
...

y ahora nuestra clase queda de esta forma

import CoreData
public class PersistentCloudKitContainer: ObservableObject {
    
    // MARK: - Core Data stack
    lazy var persistentContainer: NSPersistentCloudKitContainer = {
        let container = NSPersistentCloudKitContainer(name: "ruleOfThree")
        
        guard let description = container.persistentStoreDescriptions.first else {
            fatalError("No descriptions found")
        }
        
        description.setOption(true as NSObject, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
        
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        container.viewContext.automaticallyMergesChangesFromParent = true
        container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        
        NotificationCenter.default.addObserver(self , selector: #selector(processUpdate), name: .NSPersistentStoreRemoteChange, object: nil)
        
        return container
    }()
    
}

Ahora lo que sigue es modificar en nuestro @main


import SwiftUI
import CoreData

@main
struct ruleOfThreeApp: App {
    @StateObject var coreData = PersistentCloudKitContainer()
    var body: some Scene {
        WindowGroup {
            ContentView().environment(\.managedObjectContext, coreData.persistentContainer.viewContext)
        }
    }
}

y con eso podemos agregar funciones extras a nuestra clase por ejemplo en mi caso para poder reorder mis listas.

Referencias

En este caso base mi código en el siguiente tutorial

Categories
Swift Development

Core Data and Multiplatform SwiftUI Apps WWDC20

Dub Dub is over and SwiftUI now rules, now it can be used to make full apps through the all ecosystem . But one thing missing on the first beta of Xcode 12 is the Core Data checkbox, it’s a bug? I don’t know, hope we get it back soon but this is how I added Core Data manually

Step 1

Make a new Multiplatform SwiftUI App, so on Xcode new Project> Multiplatform> App and new

This make an Multiplatform app for iOS, iPadOS and macOs
new Multiplatform Apps don’t have AppDelegate and SceneDelegate

Step 2

Time to add or new data model, this was default when we make a core data app on iOS but here we have to added it manually.

so ⌘ + N and we chose Data Model from Core Data section

Don’t forget to check all our targets iOS and macOs also to add the DataModel to the shared Folder

Now we can make or data model like always

Im adding a constraints on name to avoid duplicated values

Step 3

make or SubClass for the data model, this is optional but let me create wrappers for the optionals Strings and Dates so is easy to handle on SwiftUI

First of all now forget to change codegen to manual/none to avoid have an error like this

this happens when we create the subclass but not tell to the data model we are handling it manual

So once we do that we go to editor menu and chose Editor > Create NSManagedObject Subclass

Now we chose or data model

and or entity

same way like we did it before we chose or targets and save the subclass on the shared folder

Voilà we have or subclass now we can handle the wrappers

to avoid optimal string we simply add a new public var

public var wname : String {
      name ?? "No name"
    }

and to make easy the relationship handling we add a new var when we put the relationship like and array

 public var elementArray: [Element] {
        
        let set = elements as? Set<Element> ?? []
         
        return set.sorted {
            $0.wName > $1.wName
        }
        
    }

we do the same on all others entity subclass

Step 4

Connect SwiftUI and CoreData

ok this is the important part, our apps is declared here full on swiftUI

import SwiftUI 

@main
struct ruleOfThreeApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

The new SwiftUI App is elegante and simple, so we are just adding what we need

import CoreData

let context = PersistentCloudKitContainer.persistentContainer.viewContext

ContentView().environment(.managedObjectContext, context)

import SwiftUI
import CoreData

@main
struct ruleOfThreeApp: App {
    
    let context = PersistentCloudKitContainer.persistentContainer.viewContext
        
    var body: some Scene {
        WindowGroup {
            ContentView().environment(\.managedObjectContext, context)
        }
    }
}

Thats all, so now we need a Class to connect to our Data Model

 ⌘ + N and we make a new swiftUI file, we save it on the shared folder and we chose all our targets

So they are two main points in this class

The first is this

 let container = NSPersistentContainer(name: “dataModelName”)

were we put our data Model Name

and the second is this two lines

container.viewContext.automaticallyMergesChangesFromParent = true

container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy

where we define or merge Policy

//
//  PersistentCloudKitContainer.swift
//  ruleOfThree
//
//  Created by Francisco Misael Landero Ychante on 27/06/20.
//

import CoreData
public class PersistentCloudKitContainer {
    // MARK: - Define Constants / Variables
    public static var context: NSManagedObjectContext {
        return persistentContainer.viewContext
    }
    // MARK: - Initializer
    private init() {}
    // MARK: - Core Data stack
    public static var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: "ruleOfThree")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        container.viewContext.automaticallyMergesChangesFromParent = true
        container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        return container
    }()
    // MARK: - Core Data Saving support
    public static func saveContext () {
        let context = persistentContainer.viewContext
        if context.hasChanges {
            do {
                try context.save()
            } catch {
                let nserror = error as NSError
                fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
            }
        }
    }
}

Step 5

Now we can test or data model

I just added a list and a button to add new elements to my data model

import SwiftUI

struct ContentView: View {
    
    // MARK: - Core Data
    @Environment(\.managedObjectContext) var moc
    
    @FetchRequest(entity: Rule.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Rule.order, ascending: true)] ) var rules: FetchedResults<Rule>
    
    var body: some View {
        List{
            ForEach(self.rules, id: \.self){ rule in
                Text("\(rule.order) \(rule.wname)")
            }
            Button(action: {
                saveTheRule()
            }) {
                Text("Add Rule")
            }
        }
    }

  func saveTheRule(){
        
        //New Rule
        
        let newRule = Rule(context: self.moc)
        
        newRule.baseLabel = "test"
        newRule.name = "Test name \(Int.random(in: 1..<100))" 
        
        
        //simple rule
          
            let newElement = Element(context: self.moc)
         
            newElement.name = "parameter name"
        
            
            newElement.rule = newRule

         try? self.moc.save()
         
    }

}

and now its working

So that’s is hope to get the CoreData checkbook back soon

Thanks for reading this is my first SwiftUI post, hope it helps.

All the info and code are based on this Entry on the Apples Developer Forums

https://developer.apple.com/forums/thread/117655

https://developer.apple.com/forums/thread/117655

https://developer.apple.com/forums/thread/650309