UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Dynamically Resizing an Array for Room Descriptions in a SwiftUI Form

Forums > SwiftUI

Hi! I'm new to this community, and this is my first post :) I am new to Swift and SwiftUI/SwiftData, but I have 25 years experience in programming coming from a PHP/TS/Go/Rust background.

I'm working on a SwiftUI form for adding new hotels, where each hotel belongs to a specific category (e.g., big hotel, medium hotel, small hotel). Each category defines a default number of rooms, and for each room, I need to capture a description. The hotel category also has a boolean which allows or not the user to override the category number of rooms of an individual hotel.

In my implementation, selecting a hotel category updates the form to include a text input field for the description of each room based on the category's default room count. This works well when the room count is directly tied to the hotel category.

However, the form also allows users to manually adjust the number of rooms using a stepper, overriding the default count specified by the hotel category. It's at this point I encounter a challenge: when the number of rooms is increased via the stepper, I get an 'Index out of range' error accessing the array that holds the room descriptions.

How can I dynamically resize this descriptions array to accommodate the manual adjustments to the number of rooms without encountering out-of-range errors? I am aware of the onChange and onReceive, but I was thinking that maybe the new @Observable and @Bindable can be an easier approach ?

Also, am I doing this the right "SwiftUI" way, or is there a better way to do it ?

Appreciate any guidance or solutions you might have!

Attached is the code:

import Foundation
import SwiftUI
import SwiftData

struct AddHotelView: View {
    @Environment(\.modelContext) private var modelContext
    @Environment(\.presentationMode) var presentationMode

    @Query private var hotelCategories: [HotelCategoryEntity]

    @State private var selectedHotelCategory: HotelCategoryEntity?
    @State private var numberOfRooms: Int16 = 1 // Default value
    // Input by the user, for each room
    @State private var roomDescriptions: [String] = []

var body: some View {
        Form {
            Section(header: Text("Hotel Details")) {
                // Your existing fields like reference, postal code, and GPS position...

                NavigationLink(destination: SelectHotelCategory(onSelect: { selectedCategory in
                    self.selectedHotelCategory = selectedCategory
                    updateFieldsForSelectedCategory()
                })) {
                    Text(selectedHotelCategory?.categoryName ?? "Select Hotel Category")
                }
            }

            // Other sections like Location Details and Photo...

            if let hotelCategory = selectedHotelCategory {
                Section(header: Text("Hotel Customization")) {
                    if hotelCategory.allowCustomizingNumberOfRooms {
                        Stepper(value: $numberOfRooms, in: 1...10) {
                            Text("Number of Rooms: \(numberOfRooms)")
                        }
                    } else {
                        Text("Number of Rooms: \(hotelCategory.defaultNumberOfRooms)")
                            .background(Color.gray.opacity(0.2))
                    }
                }
                Section(header: Text("Room Descriptions")) {
                    ForEach(0..<Int(numberOfRooms), id: \.self) { roomIndex in
                        HStack {
                            Text("Room \(roomIndex + 1):")
                                .bold()
                            TextField("Enter description...", text: $roomDescriptions[roomIndex])
                                .textFieldStyle(RoundedBorderTextFieldStyle())
                        }
                        .padding(.vertical, 2)
                    }
                }
            }
        }
        .navigationTitle("Add Hotel")
        // Save action and other logic...
    }

    private func updateFieldsForSelectedCategory() {
        guard let hotelCategory = selectedHotelCategory else { return }
        numberOfRooms = hotelCategory.defaultNumberOfRooms
        updateRoomDescriptions()
    }

  private func updateRoomDescriptions() {
    self.roomDescriptions = Array(repeating: "", count: Int(self.numberOfRooms))
}

}

1      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.