BLACK FRIDAY: Save 50% on all my Swift books and bundles! >>

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      

Save 50% in my WWDC sale.

SAVE 50% All our books and bundles are half price for Black Friday, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

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.