Weird issue with SwiftData saving models correctly, but causing a crash when trying to access data prior to the saving

That may not be the best way to explain it. Essentially, I'm requesting data from Reddit and storing it in an object called Request. This object has a timestamp and an array of objects called Post. Everything was working fine until I started to add some code to filter the post that were being fetched from reddit.

extension [Request] {
    
    func insert(request: Request, in context: ModelContext) {
        
        if self.count == 0 {
            context.logMessage("There are no existing request")
            context.insert(request)
            context.logMessage("Request saved")
        }else {
             print(request) // No crash
             print(request.timestamp) // No crash
             print(request.posts) // Causes a crash
        }
    }
}

When it does crash, it points to this code inside the SwiftData model. This code seems to be something within SwiftData. I didn't write any of this.

{
    @storageRestrictions(accesses: _$backingData, initializes: _posts)
        init(initialValue) {
                    _$backingData.setValue(forKey: \.posts, to: initialValue)
                    _posts = _SwiftDataNoType()
        }

    get {
                    _$observationRegistrar.access(self, keyPath: \.posts)
                    return self.getValue(forKey: \.posts)
        }

    set {
                    _$observationRegistrar.withMutation(of: self, keyPath: \.posts) {
                            self.setValue(forKey: \.posts, to: newValue)
                    }
        }
}

It has the error at the return self.getValue() line: Thread 5: EXC_BREAKPOINT (code=1, subcode=0x2406965c4)

This is the sequence that occurs:

  1. View is loaded
  2. Checks if it should load a new request
  3. If it should, it calls this function
    private func requestNewData() {
        redditService.fetchRedditAllData(completion: { result in
            DispatchQueue.main.async {
                switch result {
                case .success(let newRequest):
                    modelContext.logMessage("Successfully retreived and decoded data from Reddit") // Log the success
                    //modelContext.insert(newRequest)
                    requests.insert(request: newRequest, in: modelContext)
                case .failure:
                    modelContext.logMessage("Failed to retrieve and decode data from Reddit")
                }
            }
        })
    }

The code for the fetch function is here:

func fetchRedditAllData(completion: @escaping (Result<Request, Error>) -> Void) {
        // Try to construct the URL and return if it fails
        guard let url = URL(string: RedditRequests.all) else {
            context.logMessage("Failed to contruct the url for r/all")
            return
        }
        
        // Try to retrieve data from the URL
        session.dataTask(with: url, completionHandler: { data, _, error in
            // If it fails, log the failure
            if let error = error {
                self.context.logMessage("Failed to retrieve data from the r/all URL.\n\(error.localizedDescription)")
            } else {
                // If it doesn't fail, try to decode the data
                do {
                    let data     = data ?? Data()  // Get data
                    let response = try self.decoder.decode(Request.self, from: data) // Decode JSON into Request model
                    completion(.success(response)) // Return response (request) if successful
                    self.context.logMessage("Decoded data")
                }
                catch {
                    completion(.failure(error))
                    self.context.logMessage("Failed to decode data into a Request.\n\(error.localizedDescription)")

                }
            }
        }).resume()
    }

If I don't try to access request.posts before saving it to the context, it works fine. It will fetch the data and store it to the phone and then display it on the phone. When I try to access request.posts to do some filtering, it crashes.

Does anyone have any ideas?

Post not yet marked as solved Up vote post of Kessler_jx Down vote post of Kessler_jx
1.1k views

Replies

Facing exact same issue. Calling insert immediately after changing a property will work but it will crash If I am not inserting

This works

entry.note = Note(text: note)
modelContext.insert(entry)

But this will crash

entry.note = Note(text: note)
  • It's such a weird issue. I would think if you can't access the object prior to inserting it, then it would also crash when you insert it.

    I ended up inserting the Request into the context, and then filtering after, but it won't update the view properly. I have to close and reopen the app. Even if I attach an ID to the view and change it, so it forces the view to redraw, it still doesn't update the view properly.

Add a Comment