30 Days of SwiftUI - Day 23: Networking, Forms, and Feel: Mastering Advanced SwiftUI Techniques


Hello Swift explorers! Today, we're diving into advanced SwiftUI concepts like network requests, form validation, haptic feedback, and more. Let's get started!

Data Exchange: Sending and Receiving Codable Data with URLSession and SwiftUI

We'll learn how to fetch and send Codable data using URLSession.

Example: Fetching Codable Data

import SwiftUI

struct User: Codable, Identifiable {
    let id: Int
    let name: String
    let username: String
    let email: String
}

struct NetworkRequest: View {
    @State private var users = [User]()

    var body: some View {
        List(users) { user in
            VStack(alignment: .leading) {
                Text(user.name).font(.headline)
                Text(user.email)
            }
        }
        .onAppear(perform: loadData)
    }

    func loadData() {
        guard let url = URL(string: "https://jsonplaceholder.typicode.com/users") else {
            print("Invalid URL")
            return
        }

        URLSession.shared.dataTask(with: url) { data, response, error in
            if let data = data {
                if let decodedUsers = try? JSONDecoder().decode([User].self, from: data) {
                    DispatchQueue.main.async {
                        self.users = decodedUsers
                    }
                    return
                }
            }
            print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
        }.resume()
    }
}

struct NetworkRequest_Previews: PreviewProvider {
    static var previews: some View {
        NetworkRequest()
    }
}

Visual Representation:

  • A list of users fetched from the JSONPlaceholder API.

Remote Images: Loading an Image from a Remote Server

We'll learn how to load images from URLs using AsyncImage.

Example: Loading Remote Image

import SwiftUI

struct RemoteImage: View {
    let imageURL = URL(string: "https://source.unsplash.com/random/400x300")!

    var body: some View {
        AsyncImage(url: imageURL) { image in
            image.resizable().scaledToFit()
        } placeholder: {
            ProgressView()
        }
        .frame(width: 300, height: 200)
    }
}

struct RemoteImage_Previews: PreviewProvider {
    static var previews: some View {
        RemoteImage()
    }
}

Visual Representation:

  • A random image loaded from Unsplash.

Form Fortress: Validating and Disabling Forms

We'll learn how to validate form inputs and disable the submit button until the form is valid.

Example: Form Validation

import SwiftUI

struct FormValidation: View {
    @State private var username = ""
    @State private var email = ""

    var isFormValid: Bool {
        !username.isEmpty && email.contains("@")
    }

    var body: some View {
        Form {
            TextField("Username", text: $username)
            TextField("Email", text: $email)
            Button("Submit") {
                print("Submitted")
            }
            .disabled(!isFormValid)
        }
    }
}

struct FormValidation_Previews: PreviewProvider {
    static var previews: some View {
        FormValidation()
    }
}

Visual Representation:

  • A form with a disabled submit button until both username and email are valid.

Observable Codable: Adding Codable Conformance to an @Observable Class

We'll learn how to make an @Observable class conform to Codable.

Example: Observable Codable Class

import SwiftUI

@Observable
class UserData: Codable {
    var name = "John Doe"
    var age = 30

    enum CodingKeys: CodingKey {
        case name, age
    }

    init() {}

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        name = try container.decode(String.self, forKey: .name)
        age = try container.decode(Int.self, forKey: .age)
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(name, forKey: .name)
        try container.encode(age, forKey: .age)
    }
}

struct ObservableCodable: View {
    @State private var userData = UserData()

    var body: some View {
        VStack {
            Text("Name: \(userData.name)")
            Text("Age: \(userData.age)")
        }
    }
}

Tactile Feedback: Adding Haptic Effects

We'll learn how to add haptic feedback to user interactions.

Example: Haptic Feedback

import SwiftUI
import CoreHaptics

struct HapticFeedback: View {
    var body: some View {
        Button("Tap for Haptic") {
            performHaptic()
        }
    }

    func performHaptic() {
        let generator = UINotificationFeedbackGenerator()
        generator.notificationOccurred(.success)
    }
}

struct HapticFeedback_Previews: PreviewProvider {
    static var previews: some View {
        HapticFeedback()
    }
}
  • requires physical iOS Device.

Location Validation: Checking for a Valid Address

We'll learn how to validate addresses using geocoding.

Conceptual Example:

import CoreLocation

func validateAddress(address: String, completion: @escaping (Bool) -> Void) {
    let geocoder = CLGeocoder()
    geocoder.geocodeAddressString(address) { placemarks, error in
        completion(placemarks?.first != nil)
    }
}

// Example usage
validateAddress(address: "1 Infinite Loop, Cupertino") { isValid in
    print("Address valid: \(isValid)")
}

🔥 Conclusion

Day 23 has been a deep dive into advanced SwiftUI techniques. We've covered network requests, form validation, haptic feedback, and more. Keep exploring, and you'll be building more robust and engaging apps!


Follow me on Linkedin: igatitech 🚀🚀🚀

Comments

Popular posts from this blog

30 Days of SwiftUI — Day 1: Getting Started with SwiftUI

30 Days of SwiftUI Learning Journey: From Zero to Hero!

30 Days of SwiftUI - Day 11: Building Interactive SwiftUI Apps