CodeWithChris - CWC+ Courses
Cheatsheets
LYFA Course - Launch Your First App
Resources:
https://www.dropbox.com/sh/nh92vdepniipw2v/AAAaizYNZvE1_l5MXozzDMgCa?e=1&dl=0
Start: 07. November 2024
Module 1 - The War Card Game + Basic Syntax
-
Lesson 3 - UI Building
-
Lesson 4 - War Card Game UI
-
Lesson 6 - Swift functions
func doAdd(a:Int, b:Int) { var sum = a + b print(sum) } doAdd(5, 6)Man kann die Funktion auch mit labels versehen was die Arbeit damit vereinfacht:
func doAdd(firstNum a: Int, secondNum b: Int) -> Int { var sum = a + b return sum } doAdd(firstNum: 5, secondNum: 5)Möchte man keine Labels(z.B. a: b: etc.) anzeigen, dann kann man _ bei der Deklaration verwenden:
func doAdd(_ a: Int, _ b: Int) -> Int { var sum = a + b return sum } doAdd(2,5)Wenn die Funktion was returnen soll →


-
Lesson 7 - Buttons and Properties
https://github.com/dmkeks1/War-Card-Game
Button aus image erstellen. Hier wird eine closure benutzt.
Button { deal(). //action oder funktion } label: { Image("button") //image des buttons } -
Lesson 8 - War Card Game Logik - randomizer, Punkte, Auswertung, @State properties, conditional Logic (if statement)
https://github.com/dmkeks1/War-Card-Game
number randomizer
Int.random(in: 2...14) // randomizes Nummer zwischen 2 und 14, inkl. 2 & 14@State properties
@State ist ein property wrapper, die variable danach eine property
@State var playerCard: String = "back" // @State ist ein property wrapper -> danach property -
Challenge 1 - Number Climb Game
Module 2 - The Menu App
-
Lesson 2 - Arrays
var b: [Int] = [5, 10, 15, 20, 25] b[0] = 20 print(b) // Ausgabe ist nun 20 -
Lesson 3 - Structures
// Struct erstellen, vorzugsweise in eigener Datei MenuItem.swift struct MenuItem { var name: String var price: String var imageName: String } // erstellten Struct "initialisieren" **var menuItems: [MenuItem] = [] // Instance erstellen var firstItem = MenuItem(name: "Sushi", price: "1,99€", imageName: "sushi")** -
Lesson 5 - Swift UI List
https://github.com/dmkeks1/Menu

https://github.com/dmkeks1/Menu/blob/main/Menu/MenuView.swift
-
result

-
-
Lesson 5 - Challenge
https://github.com/dmkeks1/Lesson5Challenge/blob/main/Lesson5Challenge/ContentView.swift
-
Lesson 7 - Structures Part 2

try to organize your code logically into other files.

-
Lesson 8 - State and Updating Views
Outsourcing Data into another file/struct.
File of data is called DataService here because it provides data for us.
https://github.com/dmkeks1/Menu/blob/main/Menu/DataService.swift
Instance muss danach in dem View indem wir die Data benötigen erstellt werden.
@State var menuItems: [MenuItem] = [MenuItem]() // @State sagt SwiftUI, dass die variable wichtig ist fürs UI. // Änderungen werden überwacht und View wird bei jeder Änderung neu gedrawed var dataService = DataService() // creating an instance of DataService ... List(menuItems) {item in ... } .onAppear { // modifier of the List // call for the data menuItems = dataService.getData() -
Lesson 9 - Reusing your Views
-
Module 2 Challenge - Movie List
Module 3 - The Restaurant App
https://github.com/dmkeks1/Restaurant
-
Lesson 2 - TabView
TabView { MenuView().tabItem { VStack { Text("Menu") Image(systemName: "menucard") } } AboutView().tabItem { VStack { Text("About") Image(systemName: "info.circle") } } GalleryView().tabItem { VStack{ Text("Gallery") Image(systemName: "photo") } } }
-
Lesson 3 - ScrollView
VStacks mit viel Inhalt verhalten sich komisch was Text und Images angeht da nicht genug Platz vorhanden ist. Sobald man ScrollView definiert verhält es sich wie gewünscht.
ScrollView {}ScrollView { VStack (alignment: .leading) { Text("About") .font(.largeTitle) .bold() Image("restaurant") .resizable() .scaledToFit() .padding(.bottom) Text("Sukiyabashi Jiro (すきやばし次郎, Sukiyabashi Jirō) is a sushi restaurant in Ginza, Chūō, Tokyo, owned by Jiro Ono.[2] Ono previously operated as the head chef, but stepped aside in favor of his son Yoshikazu Ono in 2023 due to ill health. Sukiyabashi Jiro was the first sushi restaurant[4] to receive three stars from the Michelin Guide.[5] It was removed from the Michelin Guide in November 2019 as it does not receive reservations from the general public,[6][7] instead requiring reservations to be made through the concierge of a luxury hotel.[8]") Image("map") .resizable() .scaledToFit() Text(""" Tsukamoto Sogyo Building Basement Floor 1 2-15, Ginza 4-chome Chūō, Tokyo Japan """) } } -
Lesson 4 - Dynamically Generating UI Elements using For Each
ForEach Syntax
ForEach(wordList) { word in Text(word) } ForEach(range) { _ in // range could be for example 2..5 Text("Hello") } -
Lesson 5 - LazyVGrids
LazyVGrid(columns: [GridItem(), GridItem(), GridItem()]) { }
Beispiel:
import SwiftUI struct ContentView: View { var photos = ["gallery1", "gallery2", "gallery3", "gallery4", "gallery5", "gallery6", "gallery7", "gallery8", "gallery9", "gallery10", "gallery11"] var body: some View { ScrollView { LazyVGrid(columns: [GridItem(), GridItem(), GridItem()]) { ForEach(photos, id: \.self) { p in Image(p) .resizable() .scaledToFit() } } } } } #Preview { ContentView() }
Beispiel wenn kein Abstand gewünscht: lazyvgrid
ScrollView { LazyVGrid(columns: [GridItem(spacing:0), GridItem(spacing:0), GridItem(spacing:0)], spacing: 0) { ForEach(photos, id: \.self) { p in Image(p) .resizable() .scaledToFit() } } }
-
Lesson 6 - Displaying Images in a Grid
GeometryReader { proxy in ScrollView { LazyVGrid { ... } } }
https://github.com/dmkeks1/Restaurant/blob/main/Restaurant/GalleryView.swift
-
Lesson 7 - Modal Views Using Sheets
-
Lesson 8 - Passing Data with Bindings
@State var dataArrayThere are two common ways to use bindings:
- Textfield listens to changes, but also can write data in the property. (here we are in the same view)

- able to pass data/variables into another views and back.

https://github.com/dmkeks1/Restaurant/blob/main/Restaurant/PhotoView.swift
-
Lesson 9 - Swift Closures, Initializers, Access Modifiers and More
Initializer
Closures


Access Modifiers
Arten von access modifiers:
public= defaultprivate= can only be used inside a struct/function. Can’t be accessed outside of a structure/function.fileprivate= you can access outside a struct, but only inside the current swift file.internal= only inside the same target. this is more advanced and probably wont be used. -
Module 3 Challenge
Module 4 - The Guidebook App
https://github.com/dmkeks1/Guidebook
-
Lesson 03 - NavigationStack and NavigationLink

NavigationStack{ ScrollView { VStack { ForEach(cities) { city in NavigationLink { AttractionView() } label: { Text(city.name) } } } } .padding() } .onAppear() { cities = dataService.getData() }NavigationLink { DetailView(attraction: attraction) } label: { Text(attraction.name) } -
Lesson 04 - Building the Guidebook UI
-
Lesson 05 - Debugging in Xcode

-
Lesson 06 - Swift Optionals

To prevent crashin you can user either
- if statement
if selectedFood != nil { Text(selectedFood!) } OR if selectedFood == nil { Text("Ice Cream") } else { Text(selectedFood!) }- optional binding
if let food = selectedFood { Text(food) } // if value is nil, this check just bypasses the lines -> no error- nil coalescent operator
Text(selectedFood ?? "Sushi") // if the value is valid, it will display selectedFood. If its nil // it will display Sushi. //can also be used for optional chaining: Text(selectedMenuItem?.name ?? "Pizza")
-
Lesson 07 - Swift Dictionaries


import UIKit var myArray: [String] = ["Orange", "Apple","Banana"] // Array var myEmptyArray = [String]() var myDictionary: [String:String] = ["OR":"Orange", "AP":"Apple", "BA":"Banana"] //Dictionary var myEmptyDictionary = [String:String]() myArray.append("Pear") myDictionary["PR"] = "Pear" // create key value pair myDictionary["PR"] = "Prune" //updates value for key "PR" myDictionary["PR"] = nil // deletes value from the dictionary myArray[1] // read from array - ORDER MATTERS // // if a Dictionary entry is not there, its nil, so you need to check: // if myDictionary["OR"] != nil { myDictionary["OR"] // read from array - WILL OUTPUT ORANGE } print(myDictionary["JDF"] ?? "Peach") -
Lesson 08 - Swift Loops

For In
var myArray: [String] = ["Orange", "Apple","Banana"] // Array var myDictionary: [String:String] = ["OR":"Orange", "AP":"Apple", "BA":"Banana"] //Dictionary for item in myArray { // going through an array print(item) } for k in myDictionary.keys { // going through the dictionary and prints out the keys print(k) } for v in myDictionary.values { // going through the dictionary and prints out the values print(v) } for (k, v) in myDictionary {// going through the dictionary and prints out the values and keys. // (k,v) -> is called a tuple, a group of variables print(k) print(v) }While
import UIKit var myArray: [String] = ["Orange", "Apple","Banana"] // Array var myDictionary: [String:String] = ["OR":"Orange", "AP":"Apple", "BA":"Banana"] //Dictionary var flag = false while flag == false { // checks initially and may not run even once print("Hello") flag = true } repeat { // run guaranteed once, and checks condition afterwards print("Repeat") } while flag == false -
Lesson 09 - JSON Data Format


https://github.com/dmkeks1/Guidebook/blob/main/Guidebook/DemoData.json
-
Lesson 10 - How to Parse JSON in Swift - November 12, 2024
Steps to get JSON Data into the APP:
// get filepath to DemoData.json // Read the file and turn into Data // parse Data into Swift InstancesCode of working JSON import for the Guidebook App (DataService file, rest is in the GitHub)
func getFileData() -> [City] { // get filepath to DemoData.json if let url = Bundle.main.url(forResource: "DemoData", withExtension: "json") { do { // Read the file and turn into Data let data = try Data(contentsOf: url) // try if it throws an error // parse Data into Swift Instances let decoder = JSONDecoder() do { let cities = try decoder.decode([City].self, from: data) //.self means that we try to create the type of City data and not an array or sth. return cities } catch { print("Couldn't parse the JSON: \(error.localizedDescription)") } } catch { print("Couldn't read file: \(error.localizedDescription)") } } return [City]() } -
Lesson 11 - Opening other Apps November 13, 2024
Url Schemes

Complete List of iOS URL Schemes for Apple Apps and Services (Always-Updated)
Button { // CReate URL Instance vbased on URL Scheme if let url = URL(string: "maps://?q=\(attraction.name.replacingOccurrences(of: " ", with: "+"))&s11=\(attraction.latLong)&z=10&t=s") { // Test if url can be opened, is an app present? if UIApplication.shared.canOpenURL(url) { // open url UIApplication.shared.open(url) } } } label: { ZStack { RoundedRectangle(cornerRadius: 15) .foregroundColor(.blue) .frame(height: 40) Text("Get Directions") .foregroundColor(.white) } }https://github.com/dmkeks1/Guidebook/blob/main/Guidebook/DetailView.swift
-
Challenge - Pokemon Guide November 13, 2024
-
Assignment for Certificate November 13, 2024
iOS Networking November 13, 2024
https://www.dropbox.com/scl/fo/3snpkc49at92dl1yg5lmi/h?rlkey=2o0510ofjl9cqke91wixhq364&e=1&dl=0
Module 1 - What is Networking? November 13, 2024
-
Lesson 02 - Finding and Using APIs


-
Lesson 03 - How to use API endpoints in Swift

-
Lesson 04 - What is a REST API

-
Lesson 05 - iOS Concurrency, Await and Async
Concurrency - several Threads to work on things


func longTask() async { print("Long Task" }Task { await longTask() } -
Lesson 06 - How to make a Network request in Swift

// the following line of code already takes care of the optinal check. // if the url is nil, it skips it. if let actualUrl = URL(string: "https://api.pexels.com/v1/search?query=nature") { // create url request and pass in actualUrl }error handling:

Request
... .onAppear { Task { await apiCall() } } ... func apiCall() async{ // 1. URL if let url = URL(string: "https://api.pexels.com/v1/search?query=nature&per_page=1") { // 2. URL request var request = URLRequest(url: url) request.addValue("\(api_key)", forHTTPHeaderField: "Authorization") // adds key to request // 3. URLSession do { // we dont ne a task block here because the function in the code is called // in a task block already let (data, response) = try await URLSession.shared.data(for: request) // returns in a tuple, so we need to put the answer in a tuple aswell print(data) // actual requested data print(response) // status code, other info } catch { print(error) } } } -
Lesson 07 - Debugging Network Requests
- install certs
- enabled domain
- remove app and reinstall
-
Lesson 08 - Parsing Network Repsonses
Complete call with response and parsing:
func apiCall() async{ // 1. URL if let url = URL(string: "https://api.pexels.com/v1/search?query=nature&per_page=1") { // 2. URL request var request = URLRequest(url: url) request.addValue("\(api_key)", forHTTPHeaderField: "Authorization") // adds key to request // 3. URLSession do { // we dont ne a task block here because the function in the code is called // in a task block already let (data, response) = try await URLSession.shared.data(for: request) // returns in a tuple, so we need to put the answer in a tuple aswell // 4. Parse the JSON let decoder = JSONDecoder() do { let searchResponse = try decoder.decode(SearchResponse.self, from: data) for photo in searchResponse.photos { print(photo) } } catch { print(error) } } catch { print(error) } } } -
Challenge - Jokes App
https://github.com/dmkeks1/ChallengeJokesApp
-
Instructions
In this challenge, I'd like you to try doing the same thing, except with a different API.As usual, to get the most out of this challenge, try to complete it by reviewing the training in this module before looking at the solution or asking for help.Getting stuck, looking things up, reviewing previous lessons.. these are all steps in the skill building process!Setup:API: [https://jokeapi.dev/](https://jokeapi.dev/)Authentication: NoneEndpoint: https://v2.jokeapi.dev/joke/Any?type=single
Challenge:Build a UI that has a Text label in the center of the screen. At the bottom, put a button.When the button is tapped, it sends the API requestWhen the response returns, parse the data and display the joke in the Text labelYou should be able to keep tapping the button to show a different joke in the Text labelMake sure you use "async" and "await" as you learned in Lesson 5.
Getting Help:Check the project that you worked on in this module which is very similar.Dedicated discussion thread for this challenge [here](https://codecrew.codewithchris.com/t/ios-networking-module-1-jokes-app-challenge/25336). (If you need access to the CWC+ students section of the community, fill out [this form](https://codewithchris.typeform.com/to/NlKfo8FS))Reach out to one of our coaches with the chat widget in the lower right corner.Check out the solution below.
Solution:Solution can be found [here](https://www.dropbox.com/scl/fi/xopy0eu436bplb2w4cp0u/Networking-Module-1-Challenge-1-Project.zip?rlkey=9ggl7pudef796v3sik5qu7id4&dl=1).
-
Module 2 - The Citysights App November 16, 2024
-
Module 01 - Source Control



-
Module 05 - Adding the API key to Xcode Securely

-
create config file from template in xcode

target needs to be unchecked

choose created config file in xcode project for it to be used

add api_key to info.plist


To test if the app can access the key you can print
.onAppear { print(Bundle.main.infoDictionary?["API_KEY"] as? String) }create .gitignore file to ignore the config file
navigate to the project folder an press SHIFT + COMMAND + . to reveal invis folders like .git
open terminal and navigate to the project folder by dragging the folder into the terminal.
in the terminal enter:
touch .gitignoretouch creates, . means hiddenfor creating gitignore we can use https://www.toptal.com/developers/gitignore
enter xcode and swift and copy the content in the .gitignore file we created.


make sure to unstage config.xcconfig in xcode so it doenst commit the api_key if we created that file after settings everyhting up

now we can commit.
if we used another branch we can merge into main after and delete the used branch (chris used that in his tutorial)
-
-
Module 06 - making API request for yelp api
import Foundation struct DataService { let api_key = Bundle.main.infoDictionary?["API_KEY"] as? String func businessSearch() async { //check if api key exists guard api_key != nil else { return } // 1. Create URL if let url = URL(string: "https://api.yelp.com/v3/businesses/search?latitude=35.665517&longitude=139.770398&categories=restaurants&limit=10") { // 2. Create request var request = URLRequest(url: url) request.addValue("Bearer \(api_key!)", forHTTPHeaderField: "Authorization") request.addValue("application/json", forHTTPHeaderField: "accept") // 3. Send request do { let (data, response) = try await URLSession.shared.data(for: request) print(data) print(response) } catch { print(error) } }https://github.com/dmkeks1/CitySights-App/blob/main/CitySights%20App/DataService.swift
-
Module 07 - Parsing Yelp API + CodingKeys
https://github.com/dmkeks1/CitySights-App/blob/main/CitySights%20App/Model/Business.swift
struct Business: Decodable, Identifiable { var id: String? var alias: String? var categories: [Category]? var coordinates: Coordinate? var displayPhone: String? var distance: Double? var imageUrl: String? var isClosed: Bool? var location: Location? var name: String? var phone: String? var price: String? var rating: Double? var reviewCount: Int? var url: String? enum CodingKeys: String, CodingKey { //properties die geändert werden müssen weil die bezeichnung nicht swift conform ist case displayPhone = "display_phone" case isClosed = "is_closed" case imageUrl = "image_url" case reviewCount = "review_count" //wenn properties geändert werden müssen, dann müssen trotzdem alle anderen nochmal im codingkeys enum aufgezählt werden case id case alias case categories case coordinates case distance case location case name case phone case price case rating case url } } -
Module 09 - Styling the list
https://github.com/dmkeks1/CitySights-App/blob/main/CitySights%20App/ContentView.swift
struct TextHelper { static func distanceAwayText(meters: Double) -> String { if meters > 1000 { return "\(Int(round(meters/meters/1000))) km away" } else { return "\(Int(round(meters))) m away" } } } -
Module 10 - Business Detail Using SwiftUI Sheets
https://github.com/dmkeks1/CitySights-App/blob/main/CitySights%20App/BusinessDetailView.swift
sheets, lists, sf symbols,
-
Challenge - Football Stats
Module 3 - Data Flow and Map November 17, 2024
-
Lesson 01 - The Observation Data Flow Pattern - MVVM




-
Lesson 02 - Swift Classes November 18, 2024 and Structures Part 1



-
Lesson 03 - Swift Classes and Structures Part 2
Verhalten von Structs:
creates copy and modifies copy

verhalten von class:
referenziert nur auf instance und erstellt keine copy. ändert werte der instance

Mutability:
// 2. Default initializers struct StructPerson { var name: String } var struct1 = StructPerson(name: "Dominik") class ClassPerson { var name: String init(name: String) { self.name = name } } var class1 = ClassPerson(name: "Dominik") // 3. Assignment of Structs and Classes var struct2 = struct1 struct1.name = "Mike" // Does this statement change struct2's name property? print(struct2.name) var class2 = class1 class1.name = "Mike" // Does this statement change class2's name property? print(class2.name) // 4. Mutability differences let struct3 = StructPerson(name: "Sara") let class3 = ClassPerson(name: "Sara") //struct3 = StructPerson(name: "Jen") //class3 = ClassPerson(name: "Jen") struct3.name = "Jen" class3.name = "Jen"
-
Lesson 04 - Swift Class Inheritance November 19, 2024


Syntax
class Animal { var name: String func talk() { print("woop" } init(name: String) { self.name = name } } class Cat: Animal { //declaring Cat as subclass from animal } let c = Cat(name:"Bob") print(c.name) // has accesss to property from class Animal c.talk() // has accesss to method/function from class AnimalOverriding
class Cat: Animal { //declaring Cat as subclass from animal override func talk() { // overriding method from main class print("meow" } }
Super

Polymorphism

-
Lesson 05 - How to implement the Observaion pattern
Syntax Observable
@Observable // ohter views, where this class is instanced will //notice when the value change class ViewModel { //@Observable only works with classes var wordDb = ["Potato", "Cat", "Sunshin", "Raindrop"] var currentWord = "Cactus" func randomizeWord() { // randomizes word and puts into currentWord currentWord = wordDb[Int.random(in: wordDb.indices)] } }Syntax Environment
@main struct ObservationDemoApp: App { @State var viewModel = ViewModel() var body: some Scene { WindowGroup { ContentView() .environment(viewModel) // declaring it as an environmental // will make it available for all subvies of contentview } } }In the ContentView you need to get the reference by adding:
@Environment(ViewModel.self) var viewModel
-
Lesson 06 - Observation Pattern For City Sights
https://github.com/dmkeks1/CitySights-App/blob/main/CitySights%20App/BusinessModel.swift
-
Lesson 07 - SwiftUIMaps & Picker
Map
https://github.com/dmkeks1/CitySights-App/blob/main/CitySights%20App/MapView.swift
... import MapKit //neede for map funcitonality ... Map() //creates map ...Picker
https://github.com/dmkeks1/CitySights-App/blob/main/CitySights%20App/HomeView.swift
Picker("", selection: $selectedTab) { Text("List") .tag(0) //legt reihenfolge fest Text("Map") .tag(1) //legt reihenfolge fest } .pickerStyle(SegmentedPickerStyle()) // ändert den style // siehe screenshot
-
Challenge Crypto Coin November 30, 2024
Module 4 - Building more App Features
-
Lesson 01 - Map Markers
https://github.com/dmkeks1/CitySights-App
Map Markers
To use Map markers we use Markers(). In this example we can go through our businesses with a foreach and iterate through every entry and display all the markers on the map:
Map() { ForEach(model.businesses, id: \.id) { b in Marker(b.name ?? "Restaurant", coordinate: CLLocationCoordinate2D(latitude: b.coordinates?.latitude ?? 0, longitude: b.coordinates?.longitude ?? 0)) }Marker Selection
To select a marker we have to set a tag with a unique ID for the selected item.
Also we need to create a @State var to recognize changes
@State var selectedBusinessId: String? Map() ... .tag(b.id ?? "None") //sets to None if is nil ... .onChange(of: selectedBusinessId) { ... }Displaying Business Details
.onChange(of: selectedBusinessId) { oldValue, newValue in // Find matching business // get the first business where this is true and assign in to the constance let business = model.businesses.first { business in business.id == selectedBusinessId } // if business is foujnd set it as selected one if business != nil { model.selectedBusiness = business! } -
Lesson 02 - Onboarding View
https://github.com/dmkeks1/CitySights-App
To create an onboarding view we can use a tabview with a special modifier and set the entry point to this view:
TabView { // CODE } .tabViewStyle(.page) //in app entry point file: .fullScreenCover(isPresented: Binding.constant(true)) { //TODO on dismiss } content: { OnboardingView() } -
Lesson 03 - Saving Data with AppStorage
https://github.com/dmkeks1/CitySights-App
Dismiss Onboarding
There is an environment functionality for dismissing screens:
@Environment(\.dismiss) var dismiss //where we want to dismiss we need to call the dismiss function ... dismiss()Also in the app entry we need to have a “switch” to change the ispresented
... @State var needsOnboarding = true ... .fullScreenCover(isPresented: $needsOnboarding) { needsOnboarding = false } content: { OnboardingView() }App Storage
@AppStorage("onboarding") var needsOnboarding = trueonboarding is the key which is used to store the data on the device
if in property
Circle() .frame(width: 10) .foregroundStyle(selectedViewIndex == 1 ? .white : .gray) // if condition in a property -
Lesson 04 - Location the User with CoreLocation
CLLocationManager delegate protocol

To ask for permissions for location services:

func getUserLocation() { // Check if we have permission if locationManager.authorizationStatus == .authorizedWhenInUse { locationManager.requestLocation() } else { // requests permission locationManager.requestWhenInUseAuthorization() } }we need to set something (class) as a location manger, see
-
Lesson 06 - Downloading Images
see:
https://github.com/dmkeks1/CitySights-App/blob/main/CitySights%20App/ListView.swift
if let imageUrl = b.imageUrl { // Display the business image AsyncImage(url: URL(string: imageUrl)!) { image in image .resizable() .frame(width:50, height:50) .scaledToFill() .clipShape(RoundedRectangle(cornerRadius: 6)) .padding(.trailing, 16) } placeholder: { ProgressView() .frame(width: 50, height: 50) } } else { Image("list-placeholder-image") .padding(.trailing, 16) }to cache images:
-
Lesson 07 - Enhancing the Yelp Query
https://github.com/dmkeks1/CitySights-App/tree/main
.focused($queryBoxFocus) // only shows when textbox is focused -
Lesson 08 - Launching other Apps URLSchemes
https://github.com/dmkeks1/CitySights-App
if let url = URL(string:"tel:\(business?.phone ?? "")") { Link(destination: url) { Text(business?.phone ?? "") } } else { Text(business?.phone ?? "") }Settings APp:
if model.locationAuthStatus == .denied { Text("Please allow location services for this app to see sights near you") .padding(.horizontal) Button { if let url = URL(string: UIApplication.openSettingsURLString) { UIApplication.shared.open(url) } } label: { Text("Open Privacy Settings") } .buttonStyle(.bordered) }
iOS Databases and Basic Figma December 2, 2024
https://www.dropbox.com/scl/fo/0y5bxp06mvnoysq8cyfjd/h?rlkey=zlhlx0iqp3ihg519kg39evl9m&dl=0
-
Lesson 01 - Databases Overview
Local Database

Remote Databases


-
Lesson 02 - What is SwiftData

@Model
**@Model** // needed for SwiftData class DataItem: Identifiable { var id: String var creationDate: Date init() { id = UUID().uuidString //every instance will get UUID creationDate = Date() // and date } }https://github.com/dmkeks1/swiftdata-demo/blob/main/swiftdata-demo/DataItem.swift
modelContainer in entry point
@main struct swiftdata_demoApp: App { var body: some Scene { WindowGroup { ContentView() **.modelContainer(**for: DataItem.self) // if you have more datatypes you can put an array here } } }https://github.com/dmkeks1/swiftdata-demo/blob/main/swiftdata-demo/swiftdata_demoApp.swift
@Environment Instance where we need it
**@Environment(\.modelContext) private var context**https://github.com/dmkeks1/swiftdata-demo/blob/main/swiftdata-demo/ContentView.swift
-
Lesson 03 - SwiftData Operations - CRUD
see add, update, create in source code
https://github.com/dmkeks1/swiftdata-demo/blob/main/swiftdata-demo/ContentView.swift
-
Lesson 04 - SwiftData Queries December 3, 2024

https://developer.apple.com/documentation/foundation/predicate
Filter with @Query predicate

@Query(filter: #Predicate<Person> { person in person.age > 50 || person.age < 20 }, sort: \Person.age, order: .reverse) //order is adjustableExample for changing filters while using a picker:
we are passing the selection to the initializer:
import SwiftUI import SwiftData struct PeopleListView: View { @Environment(\.modelContext) private var context @Query(filter: #Predicate<Person> { person in person.age < 20 }, sort: \Person.name, order: .reverse) private var people: [Person] var body: some View { List(people) { p in HStack { Text(p.name) Spacer() Text("Age: \(String(p.age))") } .swipeActions { Button("Delete") { context.delete(p) } } } } init(filter: Filter) { // Based on the filter, set the predicate if filter == Filter.kids { _people = Query(filter: #Predicate<Person> { person in person.age < 20 }, sort: \Person.age) } else if filter == Filter.adults { _people = Query(filter: #Predicate<Person> { person in person.age >= 20 }, sort: \Person.age) } } }