0

I'm new to SwiftUI, and to coding in general, and I'm currently trying to build an app using SwiftUI.

I have a problem that I was not able to solve, even after a careful review of my code, and with the help of GPT-4.

So, the goal of my app is to remind the user of interacting with the persons that they're close to. Therefore, my app mainly uses two structs, called Relation (representing a person), and Interaction (representing one interaction with a person).

I've built a sheet called "NewInteractionSheet", whose goal is to add a new Interaction to one of the relations' array of interactions.

This sheet works perfectly well when it comes to adding an interaction. However, for some reason, it only works once. Why does it do that? That's what I'm trying to figure out.

EDIT: This is where the sheet is called

Here is the parent view from which the sheet is called:

import SwiftUI

struct RelationsView: View {
    @Binding var relations: [Relation]
    
    @State var isPresentingNewInteractionSheet: Bool = false
    @State var isPresentingNewRelationSheet: Bool = false

    var body: some View {
        NavigationStack {
            ZStack {
                //... other UI elements
                RotatingButtons(isPresentingNewInteractionSheet: $isPresentingNewInteractionSheet, isPresentingNewRelationSheet: $isPresentingNewRelationSheet)
            }
        }
        .sheet(isPresented: $isPresentingNewInteractionSheet) {
            NewInteractionSheet(isPresentingNewInteractionView: $isPresentingNewInteractionSheet, relations: $relations)
        }
        .sheet(isPresented: $isPresentingNewRelationSheet) {
            NewRelationSheet(isPresentingNewRelationSheet: $isPresentingNewRelationSheet, relations: $relations)
        }
    }
}

Here's a part of the code of the sheet where I'm trying to append a struct to an array:

import PhotosUI
import CoreLocation
import MapKit

struct NewInteractionSheet: View {
    @Binding var isPresentingNewInteractionView: Bool
    @Binding var relations: [Relation]
    
    @State private var newInteraction = Interaction.emptyInteraction
    @State private var relation: Relation = Relation.emptyRelation
    @State private var isPresentingLocationPicker: Bool = false
        
    var body: some View {
        NavigationView {
            Form {
                //2 sections with UI elements
            }
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button("Dismiss") {
                        isPresentingNewInteractionView = false
                    }
                }
                ToolbarItem(placement: .confirmationAction) {
                    Button("Add") {
                        if let index = relations.firstIndex(where: { $0.id == relation.id }) {
                            print("\nBefore appending to relations")
                            print(relations[index])
                            print(newInteraction)
                            relations[index].interactions.append(newInteraction)
                            print("\nAfter having appended to relations")
                            print(relations[index])
                            print(newInteraction)
                        }
                        isPresentingNewInteractionView = false
                    }
                }
            }
            .navigationTitle("New interaction")
        }
    }
}

As you can see in the code, I've included three "print" instructions to help me debug this. And when I'm trying to add two interactions, here's what's printing in the console:

Before appending to relations
Relation(id: EA18AAD4-E576-49A9-90BF-CC58C5000ECE, firstName: "Johanna", lastName: "Duby", photo: nil, interactions: [], contactFrequency: 1814400.0, birthday: Optional(2023-06-15 14:34:40 +0000), notes: "", theme: Relations.Theme.blue, reminders: nil)

Interaction(id: 106CD832-1949-4800-AC75-E21B8890E580, date: 2023-06-15 14:34:43 +0000, type: Relations.InteractionType.audioCall, durationHours: 0, durationMinutes: 0, summary: "", location: Relations.Location(name: "", coordinates: nil), pictures: [])


After having appended to relations
Relation(id: EA18AAD4-E576-49A9-90BF-CC58C5000ECE, firstName: "Johanna", lastName: "Duby", photo: nil, interactions: [Relations.Interaction(id: 106CD832-1949-4800-AC75-E21B8890E580, date: 2023-06-15 14:34:43 +0000, type: Relations.InteractionType.audioCall, durationHours: 0, durationMinutes: 0, summary: "", location: Relations.Location(name: "", coordinates: nil), pictures: [])], contactFrequency: 1814400.0, birthday: Optional(2023-06-15 14:34:40 +0000), notes: "", theme: Relations.Theme.blue, reminders: nil)

Interaction(id: 106CD832-1949-4800-AC75-E21B8890E580, date: 2023-06-15 14:34:43 +0000, type: Relations.InteractionType.audioCall, durationHours: 0, durationMinutes: 0, summary: "", location: Relations.Location(name: "", coordinates: nil), pictures: [])




Before appending to relations
Relation(id: 8D3D2012-D8A2-4092-B1A9-D476F7E05B9A, firstName: "Nastassja", lastName: "Ferrari", photo: nil, interactions: [], contactFrequency: 1209600.0, birthday: nil, notes: "", theme: Relations.Theme.green, reminders: nil)

Interaction(id: 5C4EE2E1-7D2D-4E32-BC00-FCA781EC8C20, date: 2023-06-15 14:34:49 +0000, type: Relations.InteractionType.audioCall, durationHours: 0, durationMinutes: 0, summary: "", location: Relations.Location(name: "", coordinates: nil), pictures: [])


After having appended to relations
Relation(id: 8D3D2012-D8A2-4092-B1A9-D476F7E05B9A, firstName: "Nastassja", lastName: "Ferrari", photo: nil, interactions: [], contactFrequency: 1209600.0, birthday: nil, notes: "", theme: Relations.Theme.green, reminders: nil)

Interaction(id: 5C4EE2E1-7D2D-4E32-BC00-FCA781EC8C20, date: 2023-06-15 14:34:49 +0000, type: Relations.InteractionType.audioCall, durationHours: 0, durationMinutes: 0, summary: "", location: Relations.Location(name: "", coordinates: nil), pictures: [])

You don't need to read this in detail, but just see that:

  • the first time, the interaction is correctly appended to the relations array of the interaction
  • the second time though, for some reason, it's not appended.

I'd be really grateful for any guidance that could shed some light on this perplexing issue! I'm willing to share more code if necessary, such as the parent view from which this sheet is called for example. Any insight would be extremely valuable. Thank you so much for your time and help!

PS: The iPhone I'm using to run this is an iPhone 13 mini, running iOS 16.5

Louis
  • 1
  • 1
  • You should include a [mre], as this is not debuggable at all at this point. Given that it's a `sheet`, although you don't show the call site, but suspicion is that you're using `isPresented` instead of `item`, which is a classic issue in SwiftUI. See https://stackoverflow.com/questions/66162219/swiftui-switch-sheet-on-enum-does-not-work – jnpdx Jun 15 '23 at 16:00
  • Thanks for your answer! I added the "parent" view from which the problematic sheet is called in my post. I indeed used `isPresented`, but I don't really understand why it would be a problem? – Louis Jun 15 '23 at 16:18
  • If you include a [mre], it could be debugged by others here – jnpdx Jun 15 '23 at 16:19
  • I'm trying to reproduce the problem in a shorter program but I have to say that I'm struggling. I'll get back to you when I'll succeed. – Louis Jun 15 '23 at 17:19
  • In your parent view, you declare your `relations` var as an `@Binding`, but I believe it should be `@State`. A binding is used in a child-view to create the two-way connection with the object that stores the data (your parent view). See the [Apple documentation](https://developer.apple.com/documentation/swiftui/binding) on Bindings. I'm not sure if that will fix your bug, but its probably related. – Jacob Dyer Jun 16 '23 at 00:08

0 Answers0